/* * playwave.c * * Play sound files in wave format. Only MicroSoft PCM is supported. * * Michel R. Prevenier. */ #include #include #include #include #include #include #include #include #include #include _PROTOTYPE( void main, (int argc, char **argv)); _PROTOTYPE( void usage, (void)); /******* Wave format definitions *********/ #define RIFF_ID 0x46464952 #define WAVE_ID1 0x45564157 #define WAVE_ID2 0x20746D66 #define DATA_ID 0x61746164 #define MS_PCM_FORMAT 0x0001 #define WORD short #define DWORD unsigned long struct RIFF_fields { DWORD RIFF_id; DWORD RIFF_len; DWORD WAVE_id1; DWORD WAVE_id2; DWORD data_ptr; } r_fields; struct common_fields { WORD FormatTag; WORD Channels; DWORD SamplesPerSec; DWORD AvgBytesPerSec; WORD BlockAlign; } c_fields; struct specific_fields { WORD BitsPerSample; } s_fields; DWORD data_id; DWORD data_len; /******** End of wave definitions *********/ void usage() { fprintf(stderr, "Usage: playwav [-i] file\n"); exit(-1); } void main ( int argc, char *argv[] ) { int i, audio, file; char *buffer, *file_name; unsigned int sign; unsigned int fragment_size; unsigned int channels; unsigned int bits; long data_pos; int showinfo = 0; /* Check Parameters */ if (argc > 2) { if (strncmp(argv[1], "-i", 2) == 0) { showinfo = 1; file_name = argv[2]; } else usage(); } else file_name = argv[1]; /* Open DSP */ if ((audio = open("/dev/audio", O_RDWR)) < 0) { printf("Cannot open /dev/audio\n"); exit(-1); } /* Get maximum fragment size and try to allocate a buffer */ ioctl(audio, DSPIOMAX, &fragment_size); if ((buffer = malloc(fragment_size)) == (char *)0) { fprintf(stderr, "Cannot allocate buffer\n"); exit(-1); } ioctl(audio, DSPIOSIZE, &fragment_size); /* Open wav file */ if((file = open(file_name, O_RDONLY)) < 0) { printf("Cannot open %s\n", file_name); exit(-1); } /* Check for valid wave format */ read(file, &r_fields, 20); if(r_fields.RIFF_id != RIFF_ID) { printf("%s not in RIFF format\n", file_name); exit(1); } if(r_fields.WAVE_id1 != WAVE_ID1 || r_fields.WAVE_id2 != WAVE_ID2) { printf("%s not in WAVE format\n", file_name); exit(1); } /* Store data_chunk position */ data_pos = lseek(file, 0L, 1) + r_fields.data_ptr; /* Read the common and specific fields */ read(file, &c_fields, 14); read(file, &s_fields, 2); /* Check for valid wave format, we can only play MicroSoft PCM */ if(c_fields.FormatTag != MS_PCM_FORMAT) { printf("%s not in MicroSoft PCM format\n", file_name); exit(1); } /* Set DSP parameters */ channels = c_fields.Channels; channels--; bits = s_fields.BitsPerSample; ioctl(audio, DSPIOSTEREO, &channels); ioctl(audio, DSPIORATE, &c_fields.SamplesPerSec); ioctl(audio, DSPIOBITS, &bits); sign = (bits == 16 ? 1 : 0); ioctl(audio, DSPIOSIGN, &sign); /* Goto data chunk */ lseek(file, data_pos, SEEK_SET); /* Check for valid data chunk */ read(file, &data_id, sizeof(data_id)); if(data_id != DATA_ID) { printf("Invalid data chunk\n"); exit(1); } /* Get length of data */ read(file, &data_len, sizeof(data_len)); if (showinfo) { printf("\nBits per sample : %d \n", s_fields.BitsPerSample); printf("Stereo : %s \n", (c_fields.Channels == 1 ? "yes" : "no")); printf("Samples per second: %ld \n", c_fields.SamplesPerSec); printf("Average bytes/sec : %ld \n", c_fields.AvgBytesPerSec); printf("Block alignment : %d \n", c_fields.BlockAlign); printf("Datalength (bytes): %ld \n\n", data_len); } /* Play data */ while(data_len > 0) { if (data_len > fragment_size) { /* Read next fragment */ read(file, buffer, fragment_size); data_len-= fragment_size; } else { /* Read until end of file and fill rest of buffer with silence, * in PCM this means: fill buffer with last played value */ read(file, buffer, data_len); for (i = data_len; i< fragment_size; i++) buffer[i] = buffer[(int)data_len-1]; data_len = 0; } /* Copy data to DSP */ write(audio, buffer, fragment_size); } }