playwave.c

Go to the documentation of this file.
00001 /*   
00002  *  playwave.c
00003  *
00004  *  Play sound files in wave format. Only MicroSoft PCM is supported. 
00005  *
00006  *  Michel R. Prevenier.
00007  */
00008 
00009 #include <sys/types.h>
00010 #include <errno.h>
00011 #include <signal.h>
00012 #include <stdlib.h>
00013 #include <unistd.h>
00014 #include <fcntl.h>
00015 #include <stdio.h>
00016 #include <string.h>
00017 #include <sys/ioctl.h>
00018 #include <minix/sound.h>
00019 
00020 _PROTOTYPE( void main, (int argc, char **argv));
00021 _PROTOTYPE( void usage, (void));
00022 
00023 /******* Wave format definitions *********/
00024 
00025 #define RIFF_ID         0x46464952
00026 #define WAVE_ID1        0x45564157
00027 #define WAVE_ID2        0x20746D66
00028 #define DATA_ID         0x61746164
00029 #define MS_PCM_FORMAT   0x0001
00030         
00031 #define WORD    short  
00032 #define DWORD   unsigned long
00033 
00034 struct RIFF_fields
00035 {
00036   DWORD RIFF_id;
00037   DWORD RIFF_len;
00038   DWORD WAVE_id1;
00039   DWORD WAVE_id2;
00040   DWORD data_ptr;
00041 } r_fields; 
00042 
00043 struct common_fields
00044 {
00045   WORD  FormatTag;
00046   WORD  Channels;
00047   DWORD SamplesPerSec;
00048   DWORD AvgBytesPerSec;
00049   WORD  BlockAlign;
00050 } c_fields;
00051 
00052 struct specific_fields
00053 {
00054   WORD BitsPerSample;
00055 } s_fields;
00056 
00057 DWORD data_id;
00058 DWORD data_len;
00059 
00060 /******** End of wave definitions *********/
00061 
00062 
00063 void usage()
00064 {
00065   fprintf(stderr, "Usage: playwav [-i] file\n");
00066   exit(-1);
00067 }
00068 
00069 
00070 void main ( int argc, char *argv[] )
00071 {
00072   int i, audio, file;
00073   char *buffer, *file_name;
00074   unsigned int sign;
00075   unsigned int fragment_size;
00076   unsigned int channels;
00077   unsigned int bits;
00078   long data_pos;  
00079   int showinfo = 0;
00080 
00081   /* Check Parameters */
00082   if (argc > 2)
00083   {
00084     if (strncmp(argv[1], "-i", 2) == 0)
00085     {
00086       showinfo = 1;
00087       file_name = argv[2];
00088     }
00089     else
00090       usage();
00091   }
00092   else file_name = argv[1];
00093 
00094   /* Open DSP */
00095   if ((audio = open("/dev/audio", O_RDWR)) < 0) 
00096   {
00097     printf("Cannot open /dev/audio\n");
00098     exit(-1);
00099   }
00100 
00101   /* Get maximum fragment size and try to allocate a buffer */
00102   ioctl(audio, DSPIOMAX, &fragment_size);
00103   if ((buffer = malloc(fragment_size)) == (char *)0)
00104   {
00105     fprintf(stderr, "Cannot allocate buffer\n");
00106     exit(-1);
00107   } 
00108   ioctl(audio, DSPIOSIZE, &fragment_size);
00109 
00110   /* Open wav file */
00111   if((file = open(file_name, O_RDONLY)) < 0)
00112   {
00113     printf("Cannot open %s\n", file_name);
00114     exit(-1);
00115   }
00116 
00117   /* Check for valid wave format */
00118   read(file, &r_fields, 20);
00119   if(r_fields.RIFF_id != RIFF_ID)
00120   {
00121       printf("%s not in RIFF format\n", file_name);
00122       exit(1);
00123   }
00124   if(r_fields.WAVE_id1 != WAVE_ID1 || r_fields.WAVE_id2 != WAVE_ID2)
00125   {
00126       printf("%s not in WAVE format\n", file_name);
00127       exit(1);
00128   }
00129 
00130   /* Store data_chunk position */
00131   data_pos = lseek(file, 0L, 1) + r_fields.data_ptr;
00132 
00133   /* Read the common and specific fields */
00134   read(file, &c_fields, 14);
00135   read(file, &s_fields, 2);
00136 
00137   /* Check for valid wave format, we can only play MicroSoft PCM */
00138   if(c_fields.FormatTag != MS_PCM_FORMAT)
00139   {
00140     printf("%s not in MicroSoft PCM format\n", file_name);
00141     exit(1);
00142   }
00143 
00144   /* Set DSP parameters */
00145   channels = c_fields.Channels;
00146   channels--;
00147   bits = s_fields.BitsPerSample;
00148   ioctl(audio, DSPIOSTEREO, &channels); 
00149   ioctl(audio, DSPIORATE, &c_fields.SamplesPerSec);
00150   ioctl(audio, DSPIOBITS, &bits); 
00151   sign = (bits == 16 ? 1 : 0);
00152   ioctl(audio, DSPIOSIGN, &sign); 
00153 
00154   /* Goto data chunk */
00155   lseek(file, data_pos, SEEK_SET);
00156 
00157   /* Check for valid data chunk */
00158   read(file, &data_id, sizeof(data_id));
00159   if(data_id != DATA_ID)
00160   {
00161     printf("Invalid data chunk\n");
00162     exit(1);
00163   }
00164 
00165   /* Get length of data */
00166   read(file, &data_len, sizeof(data_len));
00167 
00168   if (showinfo)
00169   {
00170     printf("\nBits per sample   : %d \n", s_fields.BitsPerSample);
00171     printf("Stereo            : %s \n", (c_fields.Channels == 1 ? "yes" : "no"));
00172     printf("Samples per second: %ld \n", c_fields.SamplesPerSec); 
00173     printf("Average bytes/sec : %ld \n", c_fields.AvgBytesPerSec);
00174     printf("Block alignment   : %d \n", c_fields.BlockAlign);
00175     printf("Datalength (bytes): %ld \n\n", data_len);
00176   }
00177     
00178   /* Play data */
00179   while(data_len > 0)
00180   {
00181     if (data_len > fragment_size) 
00182     {
00183       /* Read next fragment */
00184       read(file, buffer, fragment_size); 
00185       data_len-= fragment_size;
00186     }
00187     else 
00188     { 
00189       /* Read until end of file and fill rest of buffer with silence,
00190        * in PCM this means: fill buffer with last played value
00191        */
00192       read(file, buffer, data_len); 
00193       for (i = data_len; i< fragment_size; i++) 
00194         buffer[i] = buffer[(int)data_len-1];
00195       data_len = 0;
00196     }
00197 
00198     /* Copy data to DSP */
00199     write(audio, buffer,  fragment_size);
00200   }
00201 }

Generated on Fri Apr 14 22:56:57 2006 for minix by  doxygen 1.4.6