//------------------------------------------------------------------- // pcmplay.cpp // // This program plays back the Waveform Audio File (.wav) whose // filename is provided by the user as a command-line argument. // // compile using: $ make pcmplay // execute using: $ pcmplay // // Online reference: "Audio Programming," 4Front Technologies, // // // programmer: ALLAN CRUSE // written on: 11 SEP 2005 //------------------------------------------------------------------- #include // for fprintf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for strncmp() #include // for mmap() #include // for ioctl() #include char devname[] = "/dev/audio"; int main( int argc, char **argv ) { // check for required command-line argument if ( argc == 1 ) { fprintf( stderr, "usage: pcmplay \n" ); exit(1); } // setup the filename for waveform audio data char wavname[ 100 ]; strncpy( wavname, argv[ 1 ], 95 ); strtok( wavname, ". \n\t" ); strcat( wavname, ".wav" ); // memory-map the data file to user-space int wav = open( wavname, O_RDONLY ); if ( wav < 0 ) { perror( wavname ); exit(1); } int filesize = lseek( wav, 0, SEEK_END ); int prot = PROT_READ; int flag = MAP_PRIVATE; char *mm = (char*)mmap( NULL, filesize, prot, flag, wav, 0 ); if ( mm == MAP_FAILED ) { perror( "mmap" ); exit(1); } // verify the .wav file-format fprintf( stdout, "\nplaying \'%s\' (%d bytes)\n", wavname, filesize ); if (( strncmp( mm+0, "RIFF", 4 ) )||( strncmp( mm+8, "WAVE", 4 ) )) { fprintf( stderr, "Not a Waveform Audio file\n" ); exit(1); } // extract the audio playback parameters char *fmt = mm+12; int chunkSize = *(int*)(fmt+4); if ( strncmp( fmt, "fmt ", 4 ) ) { fprintf( stderr, "format-chunk not found\n" ); exit(1); } short formatTag = *(short*)(fmt+8); short nChannels = *(short*)(fmt+10); int samplesPerSec = *(int*)(fmt+12); int avBytesPerSec = *(int*)(fmt+16); short blockAlignmnt = *(int*)(fmt+20); short bitsPerSample = *(int*)(fmt+22); if (( formatTag != 1 )||( chunkSize != 16 )) { fprintf( stderr, "unsupported format\n" ); exit(1); } // locate the DATA chunk and its waveform data int morebytes = filesize - 12; char *dat = fmt + 8 + chunkSize; chunkSize = *(int*)(dat + 4 ); while ( morebytes > 0 ) { if ( strncmp( dat, "data", 4 ) == 0 ) break; dat += 8 + chunkSize; morebytes -= 8 + chunkSize; } dat += 8; // point past the chunk-header to the chunk-data if ( morebytes < 8 ) { perror( "data-chunk not found\n" ); exit(1); } // open the audio device-file and set its playback parameters int bits = ( bitsPerSample == 8 ) ? AFMT_U8 : AFMT_S16_BE; int chns = ( nChannels == 1 ) ? 1 : 2; int rate = samplesPerSec; int dev = open( devname, O_WRONLY ); if ( dev < 0 ) { perror( devname ); exit(1); } if (( ioctl( dev, SNDCTL_DSP_SETFMT, &bits ) < 0 ) ||( ioctl( dev, SNDCTL_DSP_CHANNELS, &chns ) < 0 ) ||( ioctl( dev, SNDCTL_DSP_SPEED, &rate ) < 0 )) { perror( "audio format not supported\n" ); exit(1); } // main loop to playback the waveform audio data int bytes_to_play = chunkSize; while ( bytes_to_play > 0 ) { int nbytes = write( dev, dat, bytes_to_play ); bytes_to_play -= nbytes; dat += nbytes; } close( dev ); // report the playback duration double duration = (double)chunkSize / avBytesPerSec; fprintf( stdout, "finished playing after %0.2f seconds\n\n", duration ); }