home *** CD-ROM | disk | FTP | other *** search
/ Digispeech DS201A Drivers / dsapi_v120.zip / SOURCE / MUSIC.C < prev    next >
C/C++ Source or Header  |  1993-08-13  |  21KB  |  670 lines

  1. /* MUSIC.C */
  2. /****************************************************************************/
  3. /*                                                                          */
  4. /*  Abstract: High Level MIDI command demonstration.                        */
  5. /*                                                                          */
  6. /*  Language: Microsoft C, v6.00a  Model: LARGE    Machine type: IBM PC     */
  7. /*                                                                          */
  8. /****************************************************************************/
  9. /*
  10.  
  11.  REV  DATE       AUTHOR          DESCRIPTION
  12.  1.0  08-01-93   Lee Mulcahy     Initial version.
  13.  ---  08-13-93   Lee Mulcahy     Latest change.
  14.  
  15. */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <signal.h>
  21. #include <conio.h>
  22. #include <io.h>
  23. #include <dos.h>
  24. #include <sys\types.h>
  25. #include <sys\timeb.h>
  26.  
  27.  
  28. /****************************************************************************/
  29. /*                                                                          */
  30. /*  Literals, etc.                                                          */
  31. /*                                                                          */
  32. /****************************************************************************/
  33.  
  34. #include "digi.h"
  35.  
  36. #define E_NOMIDI        ( E_CHANNELS + 1)   // Define our own error message.
  37.  
  38. #define NOT_FORCED          -2
  39.  
  40. #define ESC_KEY             0x1B
  41.  
  42. #define PLAY_UNSUPPORTED    0xFF
  43.  
  44. #define EXIT_BAD_USAGE      1
  45. #define EXIT_FILE_ERR       2
  46. #define EXIT_BAD_STATUS     3
  47. #define EXIT_NOT_SUPPORTED  4
  48.  
  49. static int note = 0;
  50. static int octave = 0;
  51.  
  52. static int paused = FALSE;
  53.  
  54. static char *notes [] =
  55.     {
  56.     "C ",
  57.     "C#",
  58.     "D ",
  59.     "D#",
  60.     "E ",
  61.     "F ",
  62.     "F#",
  63.     "G ",
  64.     "G#",
  65.     "A ",
  66.     "A#",
  67.     "B "
  68.     };
  69.  
  70.  
  71.     /* OKI ADPCM play rates.    */
  72.  
  73. static int playRates [4] = { 8000, 9000, 10000, 11000 };
  74.  
  75. static char *formatMsgs [] =
  76.     {
  77.     "Linear 8 bit PCM",         //  DF_PCM8         0
  78.     "Mu-Law PCM",               //  DF_PCMMU        1
  79.     "A-Law PCM",                //  DF_PCMA         2
  80.     "Linear 16 bit PCM",        //  DF_PCM16        3
  81.     "SB ADPCM 2 bit",           //  DF_SB2          4
  82.     "SB ADPCM 2.6 bit",         //  DF_SB3          5
  83.     "SB ADPCM 4 bit",           //  DF_SB4          6
  84.     "OKI ADPCM 4 bit",          //  DF_OKI4         7
  85.     "DVI ADPCM 4 bit",          //  DF_DVI4         8
  86.     "Digispeech Realtime",      //  DF_DIGIREAL     9
  87.     "Digispeech STD",           //  DF_DIGISTD      10
  88.     "Digispeech FIX",           //  DF_DIGIFIX      11
  89.     "",
  90.     "",
  91.     "CVSD",                     //  DF_CVSD         14
  92.     NULL
  93.     };
  94.  
  95.     /* Driver information.  */
  96.  
  97. static WORD support = 0;
  98.  
  99.     /* BIOS Timer Tick Counter location.    */
  100.  
  101. static long far *tTickCount = (long far *)0x0040006CL;
  102.  
  103.     /* Global audio file information.   */
  104.  
  105. static WORD rate;
  106. static WORD format;
  107. static WORD headerLen;
  108. static DWORD length;
  109.  
  110.     /* Audio data buffers.  */
  111.  
  112. static char buf0[16384];
  113. static char buf1[16384];
  114.  
  115. static void Usage ( void );
  116. static int KeyPressed ( void );
  117. static void DSExit ( int status );
  118. static int DSSetup ( void );
  119. static void Pause ( void );
  120. static void Resume ( void );
  121. static void ParseFileHeader ( FILE *fd );
  122. static void PlayScales ( void );
  123. static void PlayRandom ( void );
  124. static int PlayManager ( FILE *fd );
  125. static int ParseCommandLine ( int argc, char *argv[] );
  126. int main ( int argc, char *argv [] );
  127.  
  128.  
  129. /** Usage *******************************************************************/
  130. /*                                                                          */
  131. /*  Display the program syntax and parameter list.                          */
  132. /*                                                                          */
  133. /****************************************************************************/
  134.  
  135. static void Usage ( void )
  136.     {
  137.  
  138.     puts( "  Usage: MUSIC <switches> filename \n" );
  139.     puts( "  Demonstrates use of PDIGI /M synthesizer interface.\n" );
  140.     puts( "  Plays a PCM Mu-Law or Linear file simultaneously" );
  141.     puts( "  with synthesized sound.\n" );
  142.     puts( "  /rx   - Force playback rate to x (default 8000)" );
  143.  
  144.     exit( EXIT_BAD_USAGE );
  145.     }
  146.  
  147.  
  148. /** KeyPressed **************************************************************/
  149. /*                                                                          */
  150. /*  If a key was pressed, return the key, else return FALSE.                */
  151. /*                                                                          */
  152. /****************************************************************************/
  153.  
  154. int KeyPressed ( void )
  155.     {
  156.     int key;
  157.  
  158.         /* Check for ESC key.   */
  159.  
  160.     key = 0;
  161.     if ( kbhit())
  162.         {
  163.         key = getch();
  164.  
  165.             /* If NULL, get another key and */
  166.             /* discard it (IBM PC oddity).  */
  167.  
  168.         if ( key == 0)
  169.             getch();
  170.         }
  171.  
  172.     return( key );
  173.     }
  174.  
  175.  
  176. /** DSExit ******************************************************************/
  177. /*                                                                          */
  178. /*  Print error message, status code, and then exit with error code.        */
  179. /*                                                                          */
  180. /*  Quite a few of the error messages listed here will never be encountered */
  181. /*  by this program, but are included 'cause I wanted all of 'em.           */
  182. /*                                                                          */
  183. /****************************************************************************/
  184.  
  185. static void DSExit ( int status )
  186.     {
  187.     char *ptr;
  188.  
  189.         /* If status is 0, this is actually a 'good' exit.  */
  190.  
  191.     if ( status == 0 )
  192.         exit( 0 );
  193.  
  194.     ptr = NULL;
  195.  
  196.     switch ( status )
  197.         {
  198.         case E_UNDEFINED:   ptr = "Undefined command.";                     break;
  199.         case E_BUF0:        ptr = "Current buffer is 0.";                   break;
  200.         case E_BUF1:        ptr = "Current buffer is 1.";                   break;
  201.         case E_MUSIC:       ptr = "Driver is in 3-tone gen mode.";          break;
  202.         case E_COM:         ptr = "Communication error.";                   break;
  203.         case E_LPC:         ptr = "LPC index out of range.";                break;
  204.         case E_CVSDSPEED:   ptr = "CVSD speed is invalid.";                 break;
  205.         case E_TIMEOUT:     ptr = "Audio Unit not responding.";             break;
  206.         case E_ERR:         ptr = "Audio Unit reported an error.";          break;
  207.  
  208.         case E_PAUSE:       ptr = "Audio is paused.";                       break;
  209.         case E_GAIN:        ptr = "Invalid gain index.";                    break;
  210.         case E_INDEX:       ptr = "Buffer index is invalid.";               break;
  211.         case E_LENGTH:      ptr = "Buffer length is invalid.";              break;
  212.         case E_NOBUFFER:    ptr = "No buffers were defined.";               break;
  213.         case E_IGNORED:     ptr = "Command ignored.";                       break;
  214.         case E_INVALID:     ptr = "Bad tone index specified.";              break;
  215.         case E_BUSY:        ptr = "Driver or device is busy";               break;
  216.         case E_SYNTH:       ptr = "Driver is in synthesizer mode";          break;
  217.  
  218.         case E_RATE:        ptr = "Invalid RATE argument.";                 break;
  219.         case E_FORMAT:      ptr = "Invalid FORMAT argument.";               break;
  220.         case E_MODE:        ptr = "Invalid MODE argument (REC/PLAY).";      break;
  221.         case E_VXD:         ptr = "Windows VxD Request error.";             break;
  222.         case E_CHANNELS:    ptr = "Invalid channel count.";                 break;
  223.         case E_NOMIDI:      ptr = "No MIDI Interpreter, use PDIGI /M";      break;
  224.  
  225.         default:
  226.             printf(
  227.                 "\n\nUnknown Driver Error: 0x%04X\n\n",
  228.                 status
  229.                 );
  230.             break;
  231.         }
  232.  
  233.         /* Recognized the error code, so print the message. */
  234.  
  235.     if ( ptr != NULL )
  236.         printf( "\n\n%s\n\n", ptr );
  237.  
  238.     exit( EXIT_BAD_STATUS );
  239.     }
  240.  
  241.  
  242. /** DSSetup *****************************************************************/
  243. /*                                                                          */
  244. /*  Do some driver housekeeping.                                            */
  245. /*                                                                          */
  246. /****************************************************************************/
  247.  
  248. static int DSSetup ( void )
  249.     {
  250.     long support;
  251.     int status;
  252.  
  253.         /* Setup driver stuff.  */
  254.  
  255.     if (( status = DSReset()) != E_OK )
  256.         DSExit( status );
  257.     if (( status = DSSetBuffer( 0, sizeof(buf0), (char far *)buf0)) != E_OK )
  258.         DSExit( status );
  259.     if (( status = DSSetBuffer( 1, sizeof(buf1), (char far *)buf1)) != E_OK )
  260.         DSExit( status );
  261.     if (( status = DSSetGain( 21 )) != E_OK )
  262.         DSExit( status );
  263.  
  264.     DSQuery( NULL, NULL, &support );
  265.  
  266.         /* Check for appropriate driver.    */
  267.  
  268.     if (( support & CAPS_MIDI ) == 0 )
  269.         DSExit( E_NOMIDI );
  270.  
  271.         /* Start synthesizer and set defaults.  */
  272.  
  273.     if (( status = DSInitSynthesizer( 0 )) != E_OK )
  274.         DSExit( status );
  275.     DSMIDIPgmChange( 0, 3 );
  276.  
  277.     return( (int)support );     // We don't care about upper bits.
  278.     }
  279.  
  280.  
  281. /** Pause *******************************************************************/
  282. /*                                                                          */
  283. /*  Pause the driver.  This involves turning off the current synthesizer    */
  284. /*  note and then calling the driver pause function.                        */
  285. /*                                                                          */
  286. /****************************************************************************/
  287.  
  288. static void Pause ( void )
  289.     {
  290.  
  291.         /* Leave if already in paused state.    */
  292.  
  293.     if ( paused )
  294.         return;
  295.  
  296.         /* Turn off the current note.   */
  297.  
  298.     DSMIDINoteOff( 0, (BYTE)(note + (octave * 12)) );
  299.  
  300.         /* We must wait for a short period of time to   */
  301.         /* allow the synthesizers commands to be sent   */
  302.         /* to the PORT*ABLE Sound before going on.      */
  303.         /* This is because the DSPause() routine is     */
  304.         /* immediate and may prevent these commands     */
  305.         /* from reaching the unit.                      */
  306.  
  307.     _Wait( 100 );
  308.  
  309.     DSPause();
  310.     printf( "\n-- Pause ('R' resumes play) : " );
  311.     paused = TRUE;
  312.     }
  313.  
  314.  
  315. /** Resume ******************************************************************/
  316. /*                                                                          */
  317. /*  Allow the driver to continue.                                           */
  318. /*                                                                          */
  319. /****************************************************************************/
  320.  
  321. static void Resume ( void )
  322.     {
  323.         /* Leave if not in paused state.    */
  324.  
  325.     if ( !paused )
  326.         return;
  327.  
  328.     DSResume();
  329.     printf( "-- Resume\n" );
  330.     paused = FALSE;
  331.     }
  332.  
  333.  
  334. /** ParseFileHeader *********************************************************/
  335. /*                                                                          */
  336. /*  Determine file type and audio characteristics from file header.         */
  337. /*                                                                          */
  338. /*  Exits program if illegal file type encountered.                         */
  339. /*                                                                          */
  340. /****************************************************************************/
  341.  
  342. static void ParseFileHeader ( FILE *fd )
  343.     {
  344.     char    fileHead[10];
  345.  
  346.     length = filelength( fileno( fd ));     // Length of sound data.
  347.  
  348.         /* First byte of file should determine its type.    */
  349.  
  350.     format = fgetc( fd );
  351.     rewind( fd );
  352.  
  353.         /* Parse headers by file type.  */
  354.  
  355.     headerLen = 0;
  356.     switch ( format & 0xFF )
  357.         {
  358.         case H_PCMRAW:
  359.             format = DF_PCM8;
  360.             headerLen = 1;
  361.             length--;
  362.  
  363.             if ( rate == NOT_FORCED)
  364.                 rate = 8000;
  365.  
  366.             if (( support & CAPS_EPCM ) == 0 )
  367.                 format = PLAY_UNSUPPORTED;
  368.             break;
  369.  
  370.         case H_PCMMU:
  371.             format = DF_PCMMU;
  372.             headerLen = 1;
  373.             length--;
  374.  
  375.             if ( rate == NOT_FORCED)
  376.                 rate = 8000;
  377.  
  378.             if (( support & CAPS_EPCM ) == 0 )
  379.                 format = PLAY_UNSUPPORTED;
  380.             break;
  381.  
  382.         default:
  383.  
  384.             printf( "\nMust be PCM8 or PCMMU format digitized audio.\n" );
  385.             DSReset();
  386.             fclose( fd );
  387.             exit( EXIT_FILE_ERR );
  388.             break;
  389.         }
  390.  
  391.     if ( format == PLAY_UNSUPPORTED )
  392.         {
  393.         printf( "\nAudio device or driver does not support requested function." );
  394.         exit( EXIT_NOT_SUPPORTED );
  395.         }
  396.  
  397.         /* Display format and rate. */
  398.  
  399.     printf(
  400.         "\nData Format:\t%s\nSample Rate:\t%u\n",
  401.         formatMsgs[ format],
  402.         rate
  403.         );
  404.     }
  405.  
  406.  
  407. /** PlayScales **************************************************************/
  408. /*                                                                          */
  409. /*  Play a 12 note scale through 8 octaves.  Allows the user to break the   */
  410. /*  sequence by pressing any key.                                           */
  411. /*                                                                          */
  412. /****************************************************************************/
  413.  
  414. static void PlayScales ( void )
  415.     {
  416.  
  417.     for ( octave = 1; octave <= 8; octave++ )
  418.         {
  419.         for ( note = 0; note < 12; note++ )
  420.             {
  421.             printf( "Note: %s   Octave: %d\r", notes[ note], octave );
  422.             DSMIDINoteOn( 0, (BYTE)(note + (octave * 12)), 65 );
  423.             _Wait( 250 );
  424.             DSMIDINoteOff( 0, (BYTE)(note + (octave * 12)) );
  425.             if ( kbhit())
  426.                 break;
  427.             }
  428.         if ( kbhit())
  429.             break;
  430.         }
  431.  
  432.         /* Get rid of any keystrokes and reset note index.  */
  433.  
  434.     while ( kbhit())
  435.         getch();
  436.     printf( "\n\n" );
  437.     note = 0;
  438.     octave = 0;
  439.     }
  440.  
  441.  
  442. /** PlayRandom **************************************************************/
  443. /*                                                                          */
  444. /*  Play a random note from one of the 8 octaves.                           */
  445. /*                                                                          */
  446. /****************************************************************************/
  447.  
  448. static void PlayRandom ( void )
  449.     {
  450.     static int noteDelay = 0;
  451.  
  452.     if (( ++noteDelay % 500) == 0 )
  453.         {
  454.             /* Turn off current note, change to a   */
  455.             /* new note, display it and play it.    */
  456.  
  457.         DSMIDINoteOff( 0, (BYTE)(note + (octave * 12)) );
  458.         note = (WORD)((++note + (*tTickCount ^ 0x55)) % 12);
  459.         octave = (WORD)((++octave + (*tTickCount ^ 0x55)) % 8);
  460.         printf( "Note: %s   Octave: %d\n", notes[ note], octave + 1 );
  461.         DSMIDINoteOn( 0, (BYTE)(note + (octave * 12)), 34 );
  462.         }
  463.     }
  464.  
  465.  
  466. /** PlayManager *************************************************************/
  467. /*                                                                          */
  468. /*  Manage the background play operation.                                   */
  469. /*                                                                          */
  470. /****************************************************************************/
  471.  
  472. static int PlayManager ( FILE *fd )
  473.     {
  474.     int stopPlay, bufferIndex, status;
  475.  
  476.         /* Discard header and fill first two buffers.   */
  477.  
  478.     rewind( fd );
  479.     fread( buf0, 1, headerLen, fd );
  480.     fread( buf0, 1, sizeof(buf0), fd );
  481.     fread( buf1, 1, sizeof(buf1), fd );
  482.  
  483.         /* Start and manage appropriate background process. */
  484.  
  485.     status = StartPlay( format, rate, 1, length );
  486.     if ( status != E_OK )
  487.         return( status );
  488.  
  489.         /* Monitor background process.  */
  490.  
  491.     stopPlay = FALSE;
  492.     bufferIndex = 0;
  493.     for ( ;; )
  494.         {
  495.             /* Check for user intervention. */
  496.  
  497.         switch ( KeyPressed() )
  498.             {
  499.             case 'p':
  500.             case 'P':
  501.                 Pause();
  502.                 break;
  503.  
  504.             case 'r':
  505.             case 'R':
  506.                 Resume();
  507.                 break;
  508.  
  509.             case ESC_KEY:
  510.                 stopPlay = TRUE;
  511.                 break;
  512.  
  513.             default:
  514.                 break;
  515.             }
  516.  
  517.         status = DSGetStatus();
  518.         if ( stopPlay )
  519.             break;
  520.  
  521.             /* Skip rest if paused. */
  522.  
  523.         if (status == E_PAUSE)
  524.             continue;
  525.  
  526.         PlayRandom();
  527.  
  528.             /* Skip rest if buffers are still busy. */
  529.  
  530.         if ((status == E_BUF0) && bufferIndex == 0)
  531.             continue;
  532.         if ((status == E_BUF1) && bufferIndex == 1)
  533.             continue;
  534.  
  535.             /* Exit if error or end of action.  */
  536.  
  537.         if (( status != E_BUF0) && ( status != E_BUF1))
  538.             break;
  539.  
  540.             /* Fill empty buffer.   */
  541.  
  542.         if ( bufferIndex == 0)
  543.             {
  544.             status = fread( buf0, 1, sizeof(buf0), fd );
  545.             bufferIndex = 1;
  546.             }
  547.         else
  548.             {
  549.             status = fread( buf1, 1, sizeof(buf1), fd );
  550.             bufferIndex = 0;
  551.             }
  552.         }
  553.  
  554.         /* E_SYNTH just means that the synthesizer  */
  555.         /* is active, it is not an actual error.    */
  556.  
  557.     if ( status == E_SYNTH )
  558.         status = E_OK;
  559.  
  560.     return( status );
  561.     }
  562.  
  563.  
  564. /** ParseCommandLine ********************************************************/
  565. /*                                                                          */
  566. /*  Parse the command line (duh!).                                          */
  567. /*                                                                          */
  568. /****************************************************************************/
  569.  
  570. static int ParseCommandLine ( int argc, char *argv[] )
  571.     {
  572.     int annette, fileArg;
  573.  
  574.         /* Parse any parameters.    */
  575.  
  576.     rate = NOT_FORCED;
  577.     fileArg = -1;
  578.     for ( annette = 1; annette < argc; annette++ )
  579.         {
  580.             /* Parse switches.  */
  581.  
  582.         if (( *argv[ annette] == '/' ) || ( *argv[ annette] == '-' ))
  583.             {
  584.             argv[ annette]++;
  585.             switch ( *argv[ annette] )
  586.                 {
  587.                 case 'r':
  588.                 case 'R':
  589.                     argv[ annette]++;           // Get past switch character.
  590.                     if ( *argv[ annette] )
  591.                         rate = atoi( argv[ annette] );
  592.                     break;
  593.  
  594.                 default:
  595.                     Usage();
  596.                     break;
  597.                 }
  598.             }
  599.         else
  600.             fileArg = annette;
  601.         }
  602.  
  603.         /* Must specify a sound file.   */
  604.  
  605.     if ( fileArg == -1 )
  606.         Usage();
  607.  
  608.     return( fileArg );
  609.     }
  610.  
  611.  
  612. /** main ********************************************************************/
  613. /*                                                                          */
  614. /*  Play a sound file through DIGI driver.                                  */
  615. /*                                                                          */
  616. /****************************************************************************/
  617.  
  618. int main ( int argc, char *argv [] )
  619.     {
  620.     FILE    *fd;
  621.     int     fileArg, status;
  622.  
  623.     puts( "\nSynthesizer Interface Demonstration, v1.00" );
  624.     puts( "Copyright 1993, DSP Solutions, Inc.\n" );
  625.  
  626.     fileArg = ParseCommandLine( argc, argv );
  627.  
  628.         /* Start up appropriate drivers.    */
  629.  
  630.     if ( !DriverInstalled() )
  631.         {
  632.         printf( "Cannot find Audio Driver");
  633.         exit( EXIT_BAD_STATUS );
  634.         }
  635.  
  636.     signal( SIGINT, SIG_IGN );          // Ignore Ctrl-Break
  637.  
  638.         /* File housekeeping.   */
  639.  
  640.     fd = fopen( argv[ fileArg], "rb" );
  641.     if ( fd == NULL )
  642.         {
  643.         printf( "\nCould not open %s \n\n", argv[ fileArg] );
  644.         exit( EXIT_FILE_ERR );
  645.         }
  646.  
  647.         /* Get audio driver capabilities, then get audio    */
  648.         /* data information from file header.               */
  649.  
  650.     support = DSSetup();
  651.  
  652.     PlayScales();
  653.  
  654.         /* Find out what type of digitized audio file we have.  */
  655.  
  656.     ParseFileHeader( fd );
  657.  
  658.         /* Start and manage appropriate background process. */
  659.  
  660.     status = PlayManager( fd );
  661.  
  662.         /* Clean up and go home.    */
  663.  
  664.     DSReset();
  665.     fclose( fd );
  666.     DSExit( status );
  667.     }
  668.  
  669.  
  670.