home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Digispeech DS201A Drivers
/
dsapi_v120.zip
/
SOURCE
/
PLAY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-12
|
20KB
|
634 lines
/* PLAY.C */
/****************************************************************************/
/* */
/* Abstract: General purpose sound file player for DIGI drivers. */
/* */
/* Language: Microsoft C, v6.00a Model: LARGE Machine type: IBM PC */
/* */
/****************************************************************************/
/*
REV DATE AUTHOR DESCRIPTION
1.0 04-15-92 Lee Mulcahy Initial version.
--- 08-12-93 Lee Mulcahy Latest change.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <conio.h>
#include <io.h>
#include <dos.h>
#include <sys\types.h>
#include <sys\timeb.h>
/****************************************************************************/
/* */
/* Literals, etc. */
/* */
/****************************************************************************/
#include "digi.h"
#define NOT_FORCED -2
#define ESC_KEY 0x1B
#define PLAY_UNSUPPORTED 0xFF
#define EXIT_BAD_USAGE 1
#define EXIT_FILE_ERR 2
#define EXIT_BAD_STATUS 3
#define EXIT_NOT_SUPPORTED 4
/* OKI ADPCM play rates. */
static int playRates [4] = { 8000, 9000, 10000, 11000 };
static char *formatMsgs [] =
{
"Linear 8 bit PCM", // DF_PCM8 0
"Mu-Law PCM", // DF_PCMMU 1
"A-Law PCM", // DF_PCMA 2
"Linear 16 bit PCM", // DF_PCM16 3
"SB ADPCM 2 bit", // DF_SB2 4
"SB ADPCM 2.6 bit", // DF_SB3 5
"SB ADPCM 4 bit", // DF_SB4 6
"OKI ADPCM 4 bit", // DF_OKI4 7
"DVI ADPCM 4 bit", // DF_DVI4 8
"Digispeech Realtime", // DF_DIGIREAL 9
"Digispeech STD", // DF_DIGISTD 10
"Digispeech FIX", // DF_DIGIFIX 11
"",
"",
"CVSD", // DF_CVSD 14
NULL
};
/* Driver information. */
static WORD support = 0;
/* Global audio file information. */
static WORD rate;
static WORD format;
static WORD headerLen;
static DWORD length;
/* Audio data buffers. */
static char buf0[16384];
static char buf1[16384];
static void Usage ( void );
static int KeyPressed ( void );
static void DSExit ( int status );
static int DSSetup ( void );
static void ParseFileHeader ( FILE *fd );
static int PlayManager ( FILE *fd );
static int ParseCommandLine ( int argc, char *argv[] );
int main ( int argc, char *argv [] );
/** Usage *******************************************************************/
/* */
/* Display the program syntax and parameter list. */
/* */
/****************************************************************************/
static void Usage ( void )
{
puts( " Usage: PLAY <switches> <filename> \n" );
puts( " Plays sound files of the following formats:" );
puts( " (Requires DIGI driver. Some versions/configurations" );
puts( " do not support all formats)\n" );
puts( " IBM Linkway CVSD (*.CVS)" );
puts( " Digispeech CVSD (*.CVS, *.CVx)" );
puts( " Digispeech packed (*.PAC)" );
puts( " OKI ADPCM (*.OKI)" );
puts( " DVI ADPCM (*.DVI)" );
puts( " PCM 8-bit linear (*.PCM)" );
puts( " PCM Mu-Law (*.LIN)" );
puts( " PCM A-Law\n" );
puts( " /rx - Force playback rate to x (default 8000)" );
puts( " CVSD rate range is 0 - 5" );
exit( EXIT_BAD_USAGE );
}
/** KeyPressed **************************************************************/
/* */
/* If a key was pressed, return the key, else return FALSE. */
/* */
/****************************************************************************/
int KeyPressed ( void )
{
int key;
/* Check for ESC key. */
key = 0;
if ( kbhit())
{
key = getch();
/* If NULL, get another key and */
/* discard it (IBM PC oddity). */
if ( key == 0)
getch();
}
return( key );
}
/** DSExit ******************************************************************/
/* */
/* Print error message, status code, and then exit with error code. */
/* */
/* Quite a few of the error messages listed here will never be encountered */
/* by this program, but are included 'cause I wanted all of 'em. */
/* */
/****************************************************************************/
static void DSExit ( int status )
{
char *ptr;
/* If status is 0, this is actually a 'good' exit. */
if ( status == 0 )
exit( 0 );
ptr = NULL;
switch ( status )
{
case E_UNDEFINED: ptr = "Undefined command."; break;
case E_BUF0: ptr = "Current buffer is 0."; break;
case E_BUF1: ptr = "Current buffer is 1."; break;
case E_MUSIC: ptr = "Driver is in 3-tone gen mode."; break;
case E_COM: ptr = "Communication error."; break;
case E_LPC: ptr = "LPC index out of range."; break;
case E_CVSDSPEED: ptr = "CVSD speed is invalid."; break;
case E_TIMEOUT: ptr = "Audio Unit not responding."; break;
case E_ERR: ptr = "Audio Unit reported an error."; break;
case E_PAUSE: ptr = "Audio is paused."; break;
case E_GAIN: ptr = "Invalid gain index."; break;
case E_INDEX: ptr = "Buffer index is invalid."; break;
case E_LENGTH: ptr = "Buffer length is invalid."; break;
case E_NOBUFFER: ptr = "No buffers were defined."; break;
case E_IGNORED: ptr = "Command ignored."; break;
case E_INVALID: ptr = "Bad tone index specified."; break;
case E_BUSY: ptr = "Driver or device is busy"; break;
case E_SYNTH: ptr = "Driver is in synthesizer mode"; break;
case E_RATE: ptr = "Invalid RATE argument."; break;
case E_FORMAT: ptr = "Invalid FORMAT argument."; break;
case E_MODE: ptr = "Invalid MODE argument (REC/PLAY)."; break;
case E_VXD: ptr = "Windows VxD Request error."; break;
case E_CHANNELS: ptr = "Invalid channel count."; break;
default:
printf(
"\n\nUnknown Driver Error: 0x%04X\n\n",
status
);
break;
}
/* Recognized the error code, so print the message. */
if ( ptr != NULL )
printf( "\n\n%s\n\n", ptr );
exit( EXIT_BAD_STATUS );
}
/** DSSetup *****************************************************************/
/* */
/* Do some driver housekeeping. */
/* */
/****************************************************************************/
static int DSSetup ( void )
{
long support;
int status;
/* Setup driver stuff. */
if (( status = DSReset()) != E_OK )
DSExit( status );
if (( status = DSSetBuffer( 0, sizeof(buf0), (char far *)buf0)) != E_OK )
DSExit( status );
if (( status = DSSetBuffer( 1, sizeof(buf1), (char far *)buf1)) != E_OK )
DSExit( status );
if (( status = DSSetGain( 21 )) != E_OK )
DSExit( status );
DSQuery( NULL, NULL, &support );
return( (int)support ); // We don't care about upper bits.
}
/** ParseFileHeader *********************************************************/
/* */
/* Determine file type and audio characteristics from file header. */
/* */
/* Exits program if illegal file type encountered. */
/* */
/****************************************************************************/
static void ParseFileHeader ( FILE *fd )
{
char fileHead[10];
length = filelength( fileno( fd )); // Length of sound data.
/* First byte of file should determine its type. */
format = fgetc( fd );
rewind( fd );
/* Parse headers by file type. */
headerLen = 0;
switch ( format & 0xFF )
{
case H_DIGISTD:
format = DF_DIGISTD;
rate = 1100;
/* Current PORT-ABLE Sound does not support DIGISTD. */
if ( support & CAPS_301 )
{
if (( support & CAPS_DIGI ) == 0 )
format = PLAY_UNSUPPORTED;
}
break;
case H_DIGIFIX:
format = DF_DIGIFIX;
rate = 1625;
/* Current PORT-ABLE Sound does not support DIGIFIX. */
if ( support & CAPS_301 )
{
if (( support & CAPS_DIGI ) == 0 )
format = PLAY_UNSUPPORTED;
}
break;
case H_PCMRAW:
format = DF_PCM8;
headerLen = 1;
length--;
if ( rate == NOT_FORCED)
rate = 8000;
if (( support & CAPS_EPCM ) == 0 )
format = PLAY_UNSUPPORTED;
break;
case H_PCMA:
format = DF_PCMA;
headerLen = 1;
length--;
if ( rate == NOT_FORCED)
rate = 8000;
if (( support & CAPS_EPCM ) == 0 )
format = PLAY_UNSUPPORTED;
break;
case H_PCMMU:
format = DF_PCMMU;
headerLen = 1;
length--;
if ( rate == NOT_FORCED)
rate = 8000;
if (( support & CAPS_EPCM ) == 0 )
format = PLAY_UNSUPPORTED;
break;
case H_DIGICVSD:
format = DF_CVSD;
/* Read audio parameters from file header. */
fread( fileHead, 4, 1, fd );
headerLen = 4;
length -= 4;
/* CVSD rate is a value from 0 - 5. */
if ( rate == NOT_FORCED)
rate = fileHead[1];
/* Current PORT-ABLE Sound does not support CVSD. */
if ( support & CAPS_301 )
{
if (( support & CAPS_DIGI ) == 0 )
format = PLAY_UNSUPPORTED;
}
break;
case H_ADPCM:
format = DF_OKI4;
/* Read audio parameters from file header. */
fread( fileHead, 2, 1, fd );
headerLen = 2;
length -= 2;
if ( rate == NOT_FORCED)
rate = playRates[ fileHead[1]];
/* Only DS201A and PORT-ABLE Sound support OKI. */
if (( support & CAPS_ADPCM ) == 0 )
format = PLAY_UNSUPPORTED;
break;
case H_PCMDVI:
format = DF_DVI4;
/* Read audio parameters from file header. */
fread( fileHead, 1, 3, fd );
headerLen = 2;
length -= 2;
if ( rate == NOT_FORCED)
rate = *(unsigned int *)&fileHead[1];
/* Only PORT-ABLE Sound supports DVI. */
if (( support & CAPS_301 ) == 0 )
format = PLAY_UNSUPPORTED;
break;
default:
/* Is it Linkway CVSD? */
if (( isspace( format )) || ( isdigit( format )))
{
format = DF_CVSD;
/* Read audio parameters from file header. */
fread( fileHead, 10, 1, fd ); /* Skip 10 byte header. */
length -= 10;
headerLen = 10;
/* CVSD rate is a value from 0 - 5. */
if ( rate == NOT_FORCED)
rate = (fileHead[5] - '0');
/* Current PORT-ABLE Sound does not support CVSD. */
if ( support & CAPS_301 )
{
if (( support & CAPS_DIGI ) == 0 )
format = PLAY_UNSUPPORTED;
}
}
else
{
printf( "\nDon't recognize file type." );
DSReset();
fclose( fd );
exit( EXIT_FILE_ERR );
}
break;
}
if ( format == PLAY_UNSUPPORTED )
{
printf( "\nAudio device or driver does not support requested function." );
exit( EXIT_NOT_SUPPORTED );
}
/* Display format and rate. */
printf(
"\nData Format:\t%s\nSample Rate:\t%u\n",
formatMsgs[ format],
rate
);
}
/** PlayManager *************************************************************/
/* */
/* Manage the background play operation. */
/* */
/****************************************************************************/
static int PlayManager ( FILE *fd )
{
int stopPlay, bufferIndex, status;
/* Discard header and fill first two buffers. */
rewind( fd );
fread( buf0, 1, headerLen, fd );
fread( buf0, 1, sizeof(buf0), fd );
fread( buf1, 1, sizeof(buf1), fd );
/* Start and manage appropriate background process. */
status = StartPlay( format, rate, 1, length );
if ( status != E_OK )
return( status );
/* Monitor background process. */
stopPlay = FALSE;
bufferIndex = 0;
for ( ;; )
{
/* Check for user intervention. */
switch ( KeyPressed() )
{
case 'p':
case 'P':
status = DSPause();
printf( "-- Pause ('R' resumes play) : " );
break;
case 'r':
case 'R':
status = DSResume();
printf( "-- Resume\n" );
break;
case ESC_KEY:
stopPlay = TRUE;
break;
default:
break;
}
status = DSGetStatus();
if ( stopPlay )
break;
/* Skip rest if buffers are still busy. */
if (status == E_PAUSE)
continue;
if ((status == E_BUF0) && bufferIndex == 0)
continue;
if ((status == E_BUF1) && bufferIndex == 1)
continue;
/* Exit if error or end of action. */
if (( status != E_BUF0) && ( status != E_BUF1))
break;
/* Fill empty buffer. */
if ( bufferIndex == 0)
{
status = fread( buf0, 1, sizeof(buf0), fd );
bufferIndex = 1;
}
else
{
status = fread( buf1, 1, sizeof(buf1), fd );
bufferIndex = 0;
}
}
return( status );
}
/** ParseCommandLine ********************************************************/
/* */
/* Parse the command line (duh!). */
/* */
/****************************************************************************/
static int ParseCommandLine ( int argc, char *argv[] )
{
int annette, fileArg;
/* Parse any parameters. */
rate = NOT_FORCED;
fileArg = -1;
for ( annette = 1; annette < argc; annette++ )
{
/* Parse switches. */
if (( *argv[ annette] == '/' ) || ( *argv[ annette] == '-' ))
{
argv[ annette]++;
switch ( *argv[ annette] )
{
case 'r':
case 'R':
argv[ annette]++; // Get past switch character.
if ( *argv[ annette] )
rate = atoi( argv[ annette] );
break;
default:
Usage();
break;
}
}
else
fileArg = annette;
}
/* Must specify a sound file. */
if ( fileArg == -1 )
Usage();
return( fileArg );
}
/** main ********************************************************************/
/* */
/* Play a sound file through DIGI driver. */
/* */
/****************************************************************************/
int main ( int argc, char *argv [] )
{
FILE *fd;
int fileArg, status;
puts( "\nSound File Player, v1.00" );
puts( "Copyright 1993, DSP Solutions, Inc.\n" );
fileArg = ParseCommandLine( argc, argv );
/* Start up appropriate drivers. */
if ( !DriverInstalled() )
{
printf( "Cannot find Audio Driver");
exit( EXIT_BAD_STATUS );
}
signal( SIGINT, SIG_IGN ); // Ignore Ctrl-Break
/* File housekeeping. */
fd = fopen( argv[ fileArg], "rb" );
if ( fd == NULL )
{
printf( "\nCould not open %s \n\n", argv[ fileArg] );
exit( EXIT_FILE_ERR );
}
/* Get audio driver capabilities, then get audio */
/* data information from file header. */
support = DSSetup();
ParseFileHeader( fd );
/* Start and manage appropriate background process. */
status = PlayManager( fd );
/* Clean up and go home. */
DSReset();
fclose( fd );
DSExit( status );
}