home *** CD-ROM | disk | FTP | other *** search
/ Sound Sensations! / sound_sensations.iso / soundb / sndhack / play.c < prev    next >
C/C++ Source or Header  |  1991-07-30  |  27KB  |  949 lines

  1. #include <windows.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "app.h"
  6.  
  7. /*
  8.  * Module: play.c
  9.  *
  10.  * Contains: All functions associated with interpreting
  11.  * and playing the Edit buffer should go here.
  12.  *
  13.  */
  14.  
  15.  
  16. /*********************************************************************/
  17. /* Local Function Prototypes                                         */
  18. /*********************************************************************/
  19.  
  20. BOOL PlayLine( void );
  21. BOOL PlayTokens( int );
  22. BOOL PlayFunction( int );
  23. int  PlayGetToken(char **, char *, char *);
  24. void PlayError(char *);
  25.  
  26. BOOL PlayCloseSound( void );
  27. BOOL PlayCountVoiceNotes( void );
  28. BOOL PlayGetThresholdEvent( void );
  29. BOOL PlayGetThresholdStatus( void );
  30. BOOL PlayOpenSound( void );
  31. BOOL PlaySetSoundNoise( void );
  32. BOOL PlaySetVoiceAccent( void );
  33. BOOL PlaySetVoiceEnvelope( void );
  34. BOOL PlaySetVoiceNote( void );
  35. BOOL PlaySetVoiceQueueSize( void );
  36. BOOL PlaySetVoiceSound( void );
  37. BOOL PlaySetVoiceThreshold( void );
  38. BOOL PlayStartSound( void );
  39. BOOL PlayStopSound( void );
  40. BOOL PlaySyncAllVoices( void );
  41. BOOL PlayWaitSoundState( void );
  42.  
  43. BOOL PlayIntConvert(char *, int *);
  44. BOOL PlayLongConvert(char *, long *);
  45.  
  46.  
  47. /*********************************************************************/
  48. /* Local data and structures                                         */
  49. /*********************************************************************/
  50. #define MAXLINE     80
  51. #define MAXPARM      6
  52. #define MAXPARMLEN  33
  53.  
  54. extern SndDef SndState;
  55.  
  56. static BOOL b;
  57. static int rc;
  58. static char rcmsg[80];
  59.  
  60. static char pfunction[MAXPARMLEN];
  61. static char parms[MAXPARM][MAXPARMLEN];
  62. static char *parm[MAXPARM];
  63.  
  64. static int  ebuffchar;
  65. static char ebuffline[MAXLINE];
  66.  
  67. static struct {
  68.   char *fname;
  69.   int parms;
  70.   BOOL (*func)(void);
  71. } wsound[] = {
  72.   "CloseSound",          0,   PlayCloseSound,
  73.   "CountVoiceNotes",     1,   PlayCountVoiceNotes,
  74.   "GetThresholdEvent",   0,   PlayGetThresholdEvent,
  75.   "GetThresholdStatus",  0,   PlayGetThresholdStatus,
  76.   "OpenSound",           0,   PlayOpenSound,
  77.   "SetSoundNoise",       2,   PlaySetSoundNoise,
  78.   "SetVoiceAccent",      5,   PlaySetVoiceAccent,
  79.   "SetVoiceEnvelope",    3,   PlaySetVoiceEnvelope,
  80.   "SetVoiceNote",        4,   PlaySetVoiceNote,
  81.   "SetVoiceQueueSize",   2,   PlaySetVoiceQueueSize,
  82.   "SetVoiceSound",       3,   PlaySetVoiceSound,
  83.   "SetVoiceThreshold",   2,   PlaySetVoiceThreshold,
  84.   "StartSound",          0,   PlayStartSound,
  85.   "StopSound",           0,   PlayStopSound,
  86.   "SyncAllVoices",       0,   PlaySyncAllVoices,
  87.   "WaitSoundState",      1,   PlayWaitSoundState,
  88. };
  89.  
  90. /*********************************************************************/
  91. /* Global functions                                                  */
  92. /*********************************************************************/
  93.  
  94. /*-------------------------------------------------------------------*/
  95. /* The Play 'button' was hit, try and play contents of edit buffer   */
  96. /*-------------------------------------------------------------------*/
  97. void Play(void)
  98. {
  99.   HANDLE hEditBuffer;               /* handle to editing buffer      */
  100.   PSTR pEditBuffer;                 /* address of the edit buffer    */
  101.   PSTR pscan;
  102.   int i = 0, numchar = 0;
  103.                                     /* Get Edit window text          */
  104.   hEditBuffer = SendMessage(hEditWindow, EM_GETHANDLE, 0, 0L);
  105.   pEditBuffer = LocalLock(hEditBuffer);
  106.   if (pEditBuffer == NULL) {
  107.     PlayError("Could not lock edit buffer");
  108.     return;
  109.   }
  110.  
  111.   ebuffline[0] = '\0';              /* Break the text buffer up into */
  112.   pscan = pEditBuffer;              /* lines and ship it off to      */
  113.   while (*pscan) {                  /* PlayLine for execution        */
  114.     switch( *pscan ) {
  115.       case '\n':
  116.         ebuffline[i] = '\0';
  117.         if (PlayLine() == FALSE) {
  118.           LocalUnlock(hEditBuffer);
  119.           return;
  120.         }
  121.         i = 0;
  122.         break;
  123.       case '\r':
  124.         break;
  125.       default:
  126.        if (i == MAXLINE-1) {
  127.           ebuffline[i] = '\0';
  128.           PlayError("Line is too long");
  129.           return;
  130.         }
  131.         ebuffline[i++] = *pscan;
  132.         break;
  133.     }
  134.     pscan++;
  135.     numchar++;
  136.   }
  137.  
  138.   if (i > 0) {                      /* Watch out for any text left   */
  139.     ebuffline[i] = '\0';            /* over if we hit a null before  */
  140.     PlayLine();                     /* finding a \n for the last line*/
  141.   }
  142.   LocalUnlock(hEditBuffer);         /* Release the edit buffer text  */
  143. }
  144.  
  145. /*-------------------------------------------------------------------*/
  146. /* Try and convert a text string to a note value.                    */
  147. /*-------------------------------------------------------------------*/
  148.  
  149. BOOL PlayNoteConvert(parm, pvalue)
  150. char *parm;
  151. int *pvalue;
  152. {
  153.   int value;
  154.  
  155.  
  156.   if (PlayIntConvert(parm,&value) == TRUE)
  157.     ;
  158.   else if (strlen(parm) == 2 || strlen(parm) == 3) {
  159.     switch( *parm ){
  160.       case 'A':
  161.         value = 10;
  162.         break;
  163.       case 'B':
  164.         value = 12;
  165.         break;
  166.       case 'C':
  167.         value = 1;
  168.         break;
  169.       case 'D':
  170.         value = 3;
  171.         break;
  172.       case 'E':
  173.         value = 5;
  174.         break;
  175.       case 'F':
  176.         value = 6;
  177.         break;
  178.       case 'G':
  179.         value = 8;
  180.         break;
  181.       default:
  182.         return(FALSE);
  183.     }
  184.     if (strlen(parm) == 3) {
  185.       if ( *(parm+1) == '#' || *(parm+1) == '+' ) {
  186.         switch( *parm ){
  187.           case 'A':
  188.           case 'C':
  189.           case 'D':
  190.           case 'F':
  191.           case 'G':
  192.             value++;
  193.             parm++;
  194.             break;
  195.           default:
  196.             return(FALSE);
  197.         }
  198.       }
  199.       else if ( *(parm+1) == '-' ) {
  200.         switch( *parm ){
  201.           case 'A':
  202.           case 'B':
  203.           case 'D':
  204.           case 'E':
  205.           case 'G':
  206.             value--;
  207.             parm++;
  208.             break;
  209.           default:
  210.             return(FALSE);
  211.         }
  212.       }
  213.       else
  214.         return(FALSE);
  215.     }
  216.     parm++;
  217.     if (*parm >= '1' && *parm <= '7')
  218.       value += (*parm - '1') * 12;
  219.     else
  220.       return(FALSE);
  221.   }
  222.   else
  223.     return(FALSE);
  224.  
  225.   *pvalue = value;
  226.   return(TRUE);
  227. }
  228.  
  229.  
  230. /*********************************************************************/
  231. /* Local functions                                                   */
  232. /*********************************************************************/
  233.  
  234. /*-------------------------------------------------------------------*/
  235. /* Parse a line into its components and try to execute it            */
  236. /*-------------------------------------------------------------------*/
  237.  
  238. BOOL PlayLine()
  239. {
  240.   int numparms, curparm;
  241.   char *pline = ebuffline;
  242.   int scnt = 0;
  243.  
  244.   memset(pfunction,'\0',MAXPARMLEN);/* Initialize parm pointer array */
  245.   for (curparm = 0; curparm < MAXPARM; curparm++) {
  246.     parm[curparm] = parms[curparm];
  247.     memset(parm[curparm],'\0',MAXPARMLEN);
  248.   }
  249.  
  250.   while (*pline) {                  /* Ignore anything after a       */
  251.     if (*pline == ';')              /* terminating semicolon, ';'    */
  252.       *pline = '\0';
  253.     else {
  254.       if (!isspace(*pline))         /* count non-blank characters    */
  255.         scnt++;
  256.       pline++;
  257.     }
  258.   }
  259.   if (scnt == 0)                    /* If zero non-blank characters  */
  260.     return(TRUE);                   /* then skip the empty line      */
  261.  
  262.   pline = ebuffline;
  263.   if ( PlayGetToken(&pline,pfunction,"(") != '(' ) {
  264.     PlayError("Syntax Error");
  265.     return(FALSE);
  266.   }
  267.   pline++;
  268.  
  269.   curparm = 0;
  270.   while(*pline && curparm < MAXPARM) {
  271.     switch( PlayGetToken(&pline,parm[curparm],",)") ) {
  272.       case ',':
  273.         pline++;
  274.         curparm++;
  275.         if (curparm == MAXPARM) {
  276.           PlayError("Too many parameters");
  277.           return(FALSE);
  278.         }
  279.         break;
  280.  
  281.       case ')':
  282.         if (strlen(parm[curparm]) > 0)
  283.           numparms = curparm+1;
  284.         else
  285.           numparms = curparm;
  286.         curparm = MAXPARM;
  287.         break;
  288.  
  289.       default:
  290.         PlayError("Syntax Error");
  291.         return(FALSE);
  292.     }
  293.   }
  294.   if (*pline == '\0') {
  295.     PlayError("Syntax Error");
  296.     return(FALSE);
  297.   }
  298.   return( PlayFunction(numparms) );
  299. }
  300.  
  301.  
  302. /*-------------------------------------------------------------------*/
  303. /* Try and execute a parsed line                                     */
  304. /*-------------------------------------------------------------------*/
  305.  
  306. BOOL PlayFunction(numparms)
  307. int numparms;
  308. {
  309.   char dmsg[80];
  310.   int i;
  311.  
  312.   for(i = 0; i < sizeof(wsound)/sizeof(wsound[0]); i++) {
  313.     if (strcmp(wsound[i].fname,pfunction) == 0) {
  314.       if (numparms != wsound[i].parms) {
  315.         strcpy(dmsg,"Wrong number of parameters for ");
  316.         strcat(dmsg,pfunction);
  317.         PlayError(dmsg);
  318.         return(FALSE);
  319.       }
  320.       return( (*wsound[i].func)() );
  321.     }
  322.   }
  323.   strcpy(dmsg,"Unrecognized function ");
  324.   strcat(dmsg,pfunction);
  325.   PlayError(dmsg);
  326.   return(FALSE);
  327. }
  328.  
  329.  
  330. /*-------------------------------------------------------------------*/
  331. /* Close the sound device                                            */
  332. /*-------------------------------------------------------------------*/
  333.  
  334. BOOL PlayCloseSound( void )
  335. {
  336.   CloseSound();
  337.   SndState.open = 0;
  338.   return(TRUE);
  339. }
  340.  
  341. /*-------------------------------------------------------------------*/
  342. /* Retrieves the count of notes in the specified queue.              */
  343. /*-------------------------------------------------------------------*/
  344.  
  345. BOOL PlayCountVoiceNotes( void )
  346. {
  347.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  348.     PlayError("CountVoiceNotes voice parameter must be numeric");
  349.     return(FALSE);
  350.   }
  351.   CountVoiceNotes(SndState.voice);
  352.   return(TRUE);
  353. }
  354.  
  355. /*-------------------------------------------------------------------*/
  356. /* Retrieves a flag that identifies a recent threshold event.        */
  357. /*-------------------------------------------------------------------*/
  358.  
  359. BOOL PlayGetThresholdEvent( void )
  360. {
  361.   GetThresholdEvent();
  362.   return(TRUE);
  363. }
  364.  
  365. /*-------------------------------------------------------------------*/
  366. /* Retrieves the threshold-event status for each voice.              */
  367. /*-------------------------------------------------------------------*/
  368.  
  369. BOOL PlayGetThresholdStatus( void )
  370. {
  371.   GetThresholdStatus();
  372.   return(TRUE);
  373. }
  374.  
  375. /*-------------------------------------------------------------------*/
  376. /* Opens the play device and prevents it from being opened by others.*/
  377. /*-------------------------------------------------------------------*/
  378.  
  379. BOOL PlayOpenSound( void )
  380. {
  381.   switch (rc = OpenSound()) {
  382.     case S_SERDVNA:
  383.       PlayError("The play device is in use");
  384.       return(FALSE);
  385.     case S_SEROFM:
  386.       PlayError("Out of memory");
  387.       return(FALSE);
  388.     default:
  389.       break;
  390.   }
  391.   SndState.numvoices = rc;
  392.   SndState.open = 1;
  393.   return(TRUE);
  394. }
  395.  
  396. /*-------------------------------------------------------------------*/
  397. /* Sets the source and duration of a noise.                          */
  398. /*-------------------------------------------------------------------*/
  399.  
  400. BOOL PlaySetSoundNoise( void )
  401. {
  402.   if (strcmp(parm[0],"S_PERIOD512") == 0)
  403.     SndState.source = S_PERIOD512;
  404.   else if (strcmp(parm[0],"S_PERIOD1024") == 0)
  405.     SndState.source = S_PERIOD1024;
  406.   else if (strcmp(parm[0],"S_PERIOD2048") == 0)
  407.     SndState.source = S_PERIOD2048;
  408.   else if (strcmp(parm[0],"S_PERIODVOICE") == 0)
  409.     SndState.source = S_PERIODVOICE;
  410.   else if (strcmp(parm[0],"S_WHITE512") == 0)
  411.     SndState.source = S_WHITE512;
  412.   else if (strcmp(parm[0],"S_WHITE1024") == 0)
  413.     SndState.source = S_WHITE1024;
  414.   else if (strcmp(parm[0],"S_WHITE2048") == 0)
  415.     SndState.source = S_WHITE2048;
  416.   else if (strcmp(parm[0],"S_WHITEVOICE") == 0)
  417.     SndState.source = S_WHITEVOICE;
  418.   else {
  419.     PlayError("SetSoundNoise source parameter is invalid");
  420.     return(FALSE);
  421.   }
  422.   if (PlayIntConvert(parm[1],&SndState.duration) == FALSE) {
  423.     PlayError("SetSoundNoise duration parameter must be numeric");
  424.     return(FALSE);
  425.   }
  426.  
  427.   rc = SetSoundNoise(
  428.     SndState.source,
  429.     SndState.duration);
  430.  
  431.   switch (rc) {
  432.     case S_SERDSR:
  433.       PlayError("SetSoundNoise Error: Invalid Source");
  434.       return(FALSE);
  435.     case 0:
  436.       break;
  437.     default:
  438.       wsprintf(rcmsg,"SetSoundNoise Error: Non zero return (%d)",rc);
  439.       PlayError(rcmsg);
  440.       return(FALSE);
  441.   }
  442.   return(TRUE);
  443. }
  444.  
  445. /*-------------------------------------------------------------------*/
  446. /* Puts an accent (tempo, volume, mode, and pitch) in a voice queue. */
  447. /*-------------------------------------------------------------------*/
  448.  
  449. BOOL PlaySetVoiceAccent( void )
  450. {
  451.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  452.     PlayError("SetVoiceAccent voice parameter must be numeric");
  453.     return(FALSE);
  454.   }
  455.   if (PlayIntConvert(parm[1],&SndState.tempo) == FALSE) {
  456.     PlayError("SetVoiceAccent tempo parameter must be numeric");
  457.     return(FALSE);
  458.   }
  459.   if (PlayIntConvert(parm[2],&SndState.volume) == FALSE) {
  460.     PlayError("SetVoiceAccent volume parameter must be numeric");
  461.     return(FALSE);
  462.   }
  463.   if (strcmp(parm[3],"S_LEGATO") == 0)
  464.     SndState.mode = S_LEGATO;
  465.   else if (strcmp(parm[3],"S_NORMAL") == 0)
  466.     SndState.mode = S_NORMAL;
  467.   else if (strcmp(parm[3],"S_STACCATO") == 0)
  468.     SndState.mode = S_STACCATO;
  469.   else {
  470.     PlayError("SetVoiceAccent mode parameter choices: S_LEGATO, S_NORMAL, S_STACCATO");
  471.     return(FALSE);
  472.   }
  473.   if (PlayIntConvert(parm[4],&SndState.pitch) == FALSE) {
  474.     PlayError("SetVoiceAccent pitch parameter must be numeric");
  475.     return(FALSE);
  476.   }
  477.  
  478.   rc = SetVoiceAccent(
  479.     SndState.voice,
  480.     SndState.tempo,
  481.     SndState.volume,
  482.     SndState.mode,
  483.     SndState.pitch);
  484.  
  485.   switch (rc) {
  486.     case S_SERDMD:
  487.       PlayError("SetVoiceAccent Error: Invalid Mode");
  488.       return(FALSE);
  489.     case S_SERDTP:
  490.       PlayError("SetVoiceAccent Error: Invalid Tempo");
  491.       return(FALSE);
  492.     case S_SERDVL:
  493.       PlayError("SetVoiceAccent Error: Invalid Volume");
  494.       return(FALSE);
  495.     case S_SERQFUL:
  496.       PlayError("SetVoiceAccent Error: Queue full");
  497.       return(FALSE);
  498.     case 0:
  499.       break;
  500.     default:
  501.       wsprintf(rcmsg,"SetVoiceAccent Error: Non zero return (%d)",rc);
  502.       PlayError(rcmsg);
  503.       return(FALSE);
  504.   }
  505.   return(TRUE);
  506. }
  507.  
  508. /*-------------------------------------------------------------------*/
  509. /* Queues an envelope (wave shape and repeat count) into the         */
  510. /* specified voice queue.                                            */
  511. /*-------------------------------------------------------------------*/
  512.  
  513. BOOL PlaySetVoiceEnvelope( void )
  514. {
  515.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  516.     PlayError("SetVoiceEnvelope voice parameter must be numeric");
  517.     return(FALSE);
  518.   }
  519.   if (PlayIntConvert(parm[1],&SndState.shape) == FALSE) {
  520.     PlayError("SetVoiceEnvelope shape parameter must be numeric");
  521.     return(FALSE);
  522.   }
  523.   if (PlayIntConvert(parm[2],&SndState.repeat) == FALSE) {
  524.     PlayError("SetVoiceEnvelope repeat parameter must be numeric");
  525.     return(FALSE);
  526.   }
  527.  
  528.   rc = SetVoiceEnvelope(SndState.voice, SndState.shape, SndState.repeat);
  529.   switch (rc) {
  530.     case S_SERDSH:
  531.       PlayError("SetVoiceEnvelope Error: Invalid shape");
  532.       return(FALSE);
  533.     case S_SERQFUL:
  534.       PlayError("SetVoiceEnvelope Error: Queue full");
  535.       return(FALSE);
  536.     case 0:
  537.       break;
  538.     default:
  539.       wsprintf(rcmsg,"SetVoiceEnvelope Error: Non zero return (%d)",rc);
  540.       PlayError(rcmsg);
  541.       return(FALSE);
  542.   }
  543.   return(TRUE);
  544. }
  545.  
  546.  
  547. /*-------------------------------------------------------------------*/
  548. /*  Queues a note that has value, length, and cdots qualities        */
  549. /*  into the specified voice queue.                                  */
  550. /*-------------------------------------------------------------------*/
  551.  
  552. BOOL PlaySetVoiceNote( void )
  553. {
  554.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  555.     PlayError("SetVoiceNote voice parameter must be numeric");
  556.     return(FALSE);
  557.   }
  558.   if (PlayNoteConvert(parm[1],&SndState.value) == FALSE ) {
  559.     PlayError("SetVoiceNote value parameter is invalid");
  560.     return(FALSE);
  561.   }
  562.   if (PlayIntConvert(parm[2],&SndState.length) == FALSE) {
  563.     PlayError("SetVoiceNote length parameter must be numeric");
  564.     return(FALSE);
  565.   }
  566.   if (PlayIntConvert(parm[3],&SndState.cdots) == FALSE) {
  567.     PlayError("SetVoiceNote cdots parameter must be numeric");
  568.     return(FALSE);
  569.   }
  570.  
  571.   rc = SetVoiceNote(
  572.     SndState.voice,
  573.     SndState.value,
  574.     SndState.length,
  575.     SndState.cdots);
  576.  
  577.   switch (rc) {
  578.     case S_SERDCC:
  579.       PlayError("SetVoiceNote Error: Invalid dot count");
  580.       return(FALSE);
  581.     case S_SERDLN:
  582.       PlayError("SetVoiceNote Error: Invalid note length");
  583.       return(FALSE);
  584.     case S_SERBDNT:
  585.       PlayError("SetVoiceNote Error: Invalid note");
  586.       return(FALSE);
  587.     case S_SERQFUL:
  588.       PlayError("SetVoiceNote Error: Queue full");
  589.       return(FALSE);
  590.     case 0:
  591.       break;
  592.     default:
  593.       wsprintf(rcmsg,"SetVoiceNote Error: Non zero return (%d)",rc);
  594.       PlayError(rcmsg);
  595.       return(FALSE);
  596.   }
  597.   return(TRUE);
  598. }
  599.  
  600.  
  601. /*-------------------------------------------------------------------*/
  602. /* Sets the size of a voice queue                                    */
  603. /*-------------------------------------------------------------------*/
  604.  
  605. BOOL PlaySetVoiceQueueSize( void )
  606. {
  607.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  608.     PlayError("SetVoiceQueueSize voice parameter must be numeric");
  609.     return(FALSE);
  610.   }
  611.   if (PlayIntConvert(parm[1],&SndState.qsize) == FALSE) {
  612.     PlayError("SetVoiceQueueSize bytes parameter must be numeric");
  613.     return(FALSE);
  614.   }
  615.  
  616.   rc = SetVoiceQueueSize(
  617.     SndState.voice,
  618.     SndState.qsize);
  619.  
  620.   switch (rc) {
  621.     case S_SERMACT:
  622.       PlayError("SetVoiceQueueSize Error: Music Active");
  623.       return(FALSE);
  624.     case S_SEROFM:
  625.       PlayError("SetVoiceQueueSize Error: Out of Memory");
  626.       return(FALSE);
  627.     case 0:
  628.       break;
  629.     default:
  630.       wsprintf(rcmsg,"SetVoiceQueueSize Error: Non zero return (%d)",rc);
  631.       PlayError(rcmsg);
  632.       return(FALSE);
  633.   }
  634.   return(TRUE);
  635. }
  636.  
  637.  
  638. /*-------------------------------------------------------------------*/
  639. /* Queues a sound frequency and duration into the                    */
  640. /* specified voice queue.                                            */
  641. /*-------------------------------------------------------------------*/
  642.  
  643. BOOL PlaySetVoiceSound( void )
  644. {
  645.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  646.     PlayError("SetVoiceSound voice parameter must be numeric");
  647.     return(FALSE);
  648.   }
  649.   if (PlayLongConvert(parm[1],&SndState.lfreq) == FALSE) {
  650.     PlayError("SetVoiceSound frequency parameter must be numeric");
  651.     return(FALSE);
  652.   }
  653.   else {
  654.     SndState.frequency = (int)(SndState.lfreq >> 16);
  655.     SndState.fraction = (int)(SndState.lfreq & 0xff);
  656.   }
  657.   if (PlayIntConvert(parm[2],&SndState.duration) == FALSE) {
  658.     PlayError("SetVoiceSound duration parameter must be numeric");
  659.     return(FALSE);
  660.   }
  661.  
  662.   rc = SetVoiceSound(SndState.voice, SndState.lfreq, SndState.duration);
  663.   switch (rc) {
  664.     case S_SERDDR:
  665.       PlayError("SetVoiceSound Error: Invalid duration");
  666.       return(FALSE);
  667.     case S_SERDFQ:
  668.       PlayError("SetVoiceSound Error: Invalid frequency");
  669.       return(FALSE);
  670.     case S_SERQFUL:
  671.       PlayError("SetVoiceSound Error: Queue full");
  672.       return(FALSE);
  673.     case 0:
  674.       break;
  675.     default:
  676.       wsprintf(rcmsg,"SetVoiceSound Error: Non zero return (%d)",rc);
  677.       PlayError(rcmsg);
  678.       return(FALSE);
  679.   }
  680.   return(TRUE);
  681. }
  682.  
  683.  
  684. /*-------------------------------------------------------------------*/
  685. /* Sets a voice queues threshold level.                              */
  686. /*-------------------------------------------------------------------*/
  687.  
  688. BOOL PlaySetVoiceThreshold( void )
  689. {
  690.   if (PlayIntConvert(parm[0],&SndState.voice) == FALSE) {
  691.     PlayError("SetVoiceThreshold voice parameter must be numeric");
  692.     return(FALSE);
  693.   }
  694.  
  695.   if (PlayIntConvert(parm[1],&SndState.tcount) == FALSE) {
  696.     PlayError("SetVoiceThreshold note count parameter must be numeric");
  697.     return(FALSE);
  698.   }
  699.  
  700.   if ( (rc = SetVoiceThreshold(SndState.voice, SndState.tcount)) != 0) {
  701.     wsprintf(rcmsg,"SetVoiceThreshold Error: Non zero return (%d)",rc);
  702.     PlayError(rcmsg);
  703.     return(FALSE);
  704.   }
  705.   return(TRUE);
  706. }
  707.  
  708.  
  709. /*-------------------------------------------------------------------*/
  710. /* Starts play in each voice queue, non-destructive.                 */
  711. /*-------------------------------------------------------------------*/
  712.  
  713. BOOL PlayStartSound( void )
  714. {
  715.   StartSound();
  716.   return(TRUE);
  717. }
  718.  
  719.  
  720. /*-------------------------------------------------------------------*/
  721. /* Stops playing all voice queues.                                   */
  722. /*-------------------------------------------------------------------*/
  723.  
  724. BOOL PlayStopSound( void )
  725. {
  726.   StopSound();
  727.   return(TRUE);
  728. }
  729.  
  730.  
  731. /*-------------------------------------------------------------------*/
  732. /*  Puts a sync mark into each voice queue.                          */
  733. /*-------------------------------------------------------------------*/
  734.  
  735. BOOL PlaySyncAllVoices( void )
  736. {
  737.   switch (rc = SyncAllVoices()) {
  738.     case S_SERQFUL:
  739.       PlayError("SyncAllVoices Error: Queue full");
  740.       return(FALSE);
  741.     case 0:
  742.       break;
  743.     default:
  744.       wsprintf(rcmsg,"SyncAllVoices Error: Non zero return (%d)",rc);
  745.       PlayError(rcmsg);
  746.       return(FALSE);
  747.   }
  748.   return(TRUE);
  749. }
  750.  
  751. /*-------------------------------------------------------------------*/
  752. /*  Waits for the sound device to enter a specified state.           */
  753. /*-------------------------------------------------------------------*/
  754.  
  755. BOOL PlayWaitSoundState( void )
  756. {
  757.   HANDLE oldCursor;
  758.  
  759.   if (strcmp(parm[0],"S_ALLTHRESHOLD") == 0)
  760.     SndState.waitstate = S_ALLTHRESHOLD;
  761.   else if (strcmp(parm[0],"S_QUEUEEMPTY") == 0)
  762.     SndState.waitstate = S_QUEUEEMPTY;
  763.   else if (strcmp(parm[0],"S_THRESHOLD") == 0)
  764.     SndState.waitstate = S_THRESHOLD;
  765.   else {
  766.     PlayError("WaitSoundState parameter choices: S_ALLTHRESHOLD, S_QUEUEEMPTY, S_THRESHOLD");
  767.     return(FALSE);
  768.   }
  769.  
  770.   oldCursor = SetCursor(hNote);
  771.   rc = WaitSoundState(SndState.waitstate);
  772.   SetCursor(oldCursor);
  773.   switch (rc) {
  774.     case S_SERDST:
  775.       PlayError("WaitSoundState Error: Invalid State");
  776.       return(FALSE);
  777.     case 0:
  778.       break;
  779.     default:
  780.       wsprintf(rcmsg,"WaitSoundState Error: Non zero return (%d)",rc);
  781.       PlayError(rcmsg);
  782.       return(FALSE);
  783.   }
  784.   return(TRUE);
  785. }
  786.  
  787. /*-------------------------------------------------------------------*/
  788. /* Parse a token from an input line given a set of terminators.      */
  789. /*-------------------------------------------------------------------*/
  790.  
  791. int PlayGetToken(alptr, tptr, endchars)
  792. char **alptr;
  793. char * tptr;
  794. char * endchars;
  795. {
  796.   int curchar = 0;
  797.   enum {PREWHITE, INTOKEN, POSTWHITE};
  798.   int state = PREWHITE;
  799.   char *lptr = *alptr;
  800.   char tmsg[80];
  801.  
  802.   while ( *lptr && strchr(endchars, *lptr) == NULL ) {
  803.     switch (state) {
  804.       case PREWHITE:
  805.         if ( !isspace(*lptr) )
  806.           state = INTOKEN;
  807.         else
  808.           lptr++;
  809.         break;
  810.  
  811.       case INTOKEN:
  812.         if (!isspace(*lptr)) {
  813.           if (curchar >= MAXPARMLEN-1)
  814.             return('\0');
  815.           *(tptr + curchar) = *lptr;
  816.           curchar++;
  817.         }
  818.         else
  819.           state = POSTWHITE;
  820.         lptr++;
  821.         break;
  822.  
  823.       case POSTWHITE:
  824.       default:
  825.         if (!isspace(*lptr))
  826.           return('\0');
  827.         lptr++;
  828.         break;
  829.     }
  830.   }
  831.   *alptr = lptr;
  832.   return(*lptr);
  833. }
  834.  
  835.  
  836. /*-------------------------------------------------------------------*/
  837. /* Try and convert a character string into a numeric integer.        */
  838. /*-------------------------------------------------------------------*/
  839.  
  840. BOOL PlayIntConvert(parm, iptr)
  841. char *parm;
  842. int *iptr;
  843. {
  844.   char *s;
  845.   int i = 0;
  846.   char c;
  847.  
  848.   if (strspn(parm,"0123456789") == strlen(parm) )
  849.     i = atoi(parm);
  850.   else if (strlen(parm) > 2 && strnicmp(parm,"0x",2) == 0) {
  851.     for(s = parm+2; *s; s++) {
  852.       switch (c = toupper(*s)) {
  853.         case 'A':
  854.         case 'B':
  855.         case 'C':
  856.         case 'D':
  857.         case 'E':
  858.         case 'F':
  859.           i = (i * 0x10) + (c - 'A' + 0xA);
  860.           break;
  861.         case '0':
  862.         case '1':
  863.         case '2':
  864.         case '3':
  865.         case '4':
  866.         case '5':
  867.         case '6':
  868.         case '7':
  869.         case '8':
  870.         case '9':
  871.           i = (i * 0x10) + (c - '0');
  872.           break;
  873.         default:
  874.           return(FALSE);
  875.       }
  876.     }
  877.   }
  878.   else
  879.     return(FALSE);
  880.  
  881.   *iptr = i;
  882.   return(TRUE);
  883. }
  884.  
  885.  
  886. /*-------------------------------------------------------------------*/
  887. /* Try and convert a character string into a numeric long value.     */
  888. /*-------------------------------------------------------------------*/
  889.  
  890. BOOL PlayLongConvert(parm, iptr)
  891. char *parm;
  892. long *iptr;
  893. {
  894.   char *s;
  895.   long i = 0;
  896.   char c;
  897.  
  898.   if (strspn(parm,"0123456789") == strlen(parm) )
  899.     i = atol(parm);
  900.   else if (strlen(parm) > 2 && strnicmp(parm,"0x",2) == 0) {
  901.     for(s = parm+2; *s; s++) {
  902.       switch (c = toupper(*s)) {
  903.         case 'A':
  904.         case 'B':
  905.         case 'C':
  906.         case 'D':
  907.         case 'E':
  908.         case 'F':
  909.           i = (i * 0x10) + (c - 'A' + 0xA);
  910.           break;
  911.         case '0':
  912.         case '1':
  913.         case '2':
  914.         case '3':
  915.         case '4':
  916.         case '5':
  917.         case '6':
  918.         case '7':
  919.         case '8':
  920.         case '9':
  921.           i = (i * 0x10) + (c - '0');
  922.           break;
  923.         default:
  924.           return(FALSE);
  925.       }
  926.     }
  927.   }
  928.   else
  929.     return(FALSE);
  930.  
  931.   *iptr = i;
  932.   return(TRUE);
  933. }
  934.  
  935.  
  936. /*-------------------------------------------------------------------*/
  937. /* Display an error message                                          */
  938. /*-------------------------------------------------------------------*/
  939.  
  940. void PlayError(char *Text)
  941. {
  942.   MessageBox(
  943.     GetFocus(),
  944.       (LPSTR)ebuffline,
  945.       (LPSTR)Text,
  946.       MB_OK);
  947. }
  948.  
  949.