home *** CD-ROM | disk | FTP | other *** search
/ Digispeech DS201A Drivers / dsapi_v120.zip / SOURCE / PLAY.C < prev    next >
C/C++ Source or Header  |  1993-08-12  |  20KB  |  634 lines

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