Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of wave_player by
wave_player.cpp
00001 //----------------------------------------------------------------------------- 00002 // a sample mbed library to play back wave files. 00003 // 00004 // explanation of wave file format. 00005 // https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 00006 00007 // if VERBOSE is uncommented then the wave player will enter a verbose 00008 // mode that displays all data values as it reads them from the file 00009 // and writes them to the DAC. Very slow and unusable output on the DAC, 00010 // but useful for debugging wave files that don't work. 00011 //#define VERBOSE 00012 00013 00014 #include <mbed.h> 00015 #include <stdio.h> 00016 #include <wave_player.h> 00017 #include <stdlib.h> 00018 00019 extern int vol; 00020 //----------------------------------------------------------------------------- 00021 // constructor -- accepts an mbed pin to use for AnalogOut. Only p18 will work 00022 wave_player::wave_player(AnalogOut *_dac) 00023 { 00024 wave_DAC=_dac; 00025 wave_DAC->write_u16(32768); //DAC is 0-3.3V, so idles at ~1.6V 00026 verbosity=0; 00027 } 00028 00029 //----------------------------------------------------------------------------- 00030 // if verbosity is set then wave player enters a mode where the wave file 00031 // is decoded and displayed to the screen, including sample values put into 00032 // the DAC FIFO, and values read out of the DAC FIFO by the ISR. The DAC output 00033 // itself is so slow as to be unusable, but this might be handy for debugging 00034 // wave files that don't play 00035 //----------------------------------------------------------------------------- 00036 void wave_player::set_verbosity(int v) 00037 { 00038 verbosity=v; 00039 } 00040 00041 //----------------------------------------------------------------------------- 00042 // player function. Takes a pointer to an opened wave file. The file needs 00043 // to be stored in a filesystem with enough bandwidth to feed the wave data. 00044 // LocalFileSystem isn't, but the SDcard is, at least for 22kHz files. The 00045 // SDcard filesystem can be hotrodded by increasing the SPI frequency it uses 00046 // internally. 00047 //----------------------------------------------------------------------------- 00048 void wave_player::play(FILE *wavefile) 00049 { 00050 unsigned chunk_id,chunk_size,channel; 00051 unsigned data,samp_int,i; 00052 short unsigned dac_data; 00053 long long slice_value; 00054 char *slice_buf; 00055 short *data_sptr; 00056 unsigned char *data_bptr; 00057 int *data_wptr; 00058 FMT_STRUCT wav_format; 00059 long slice,num_slices; 00060 extern bool playing; 00061 extern int vol; 00062 extern bool old_playing; 00063 00064 00065 DAC_wptr=0; 00066 DAC_rptr=0; 00067 for (i=0;i<256;i+=2) { 00068 DAC_fifo[i]=0; 00069 DAC_fifo[i+1]=3000; 00070 } 00071 DAC_wptr=4; 00072 DAC_on=0; 00073 00074 fread(&chunk_id,4,1,wavefile); 00075 fread(&chunk_size,4,1,wavefile); 00076 while (!feof(wavefile)) { 00077 00078 if (verbosity) 00079 printf("Read chunk ID 0x%x, size 0x%x\n",chunk_id,chunk_size); 00080 switch (chunk_id) { 00081 case 0x46464952: 00082 fread(&data,4,1,wavefile); 00083 if (verbosity) { 00084 printf("RIFF chunk\n"); 00085 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); 00086 printf(" RIFF type 0x%x\n",data); 00087 } 00088 break; 00089 case 0x20746d66: 00090 fread(&wav_format,sizeof(wav_format),1,wavefile); 00091 if (verbosity) { 00092 printf("FORMAT chunk\n"); 00093 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); 00094 printf(" compression code %d\n",wav_format.comp_code); 00095 printf(" %d channels\n",wav_format.num_channels); 00096 printf(" %d samples/sec\n",wav_format.sample_rate); 00097 printf(" %d bytes/sec\n",wav_format.avg_Bps); 00098 printf(" block align %d\n",wav_format.block_align); 00099 printf(" %d bits per sample\n",wav_format.sig_bps); 00100 } 00101 if (chunk_size > sizeof(wav_format)) 00102 fseek(wavefile,chunk_size-sizeof(wav_format),SEEK_CUR); 00103 break; 00104 case 0x61746164: 00105 // allocate a buffer big enough to hold a slice 00106 slice_buf=(char *)malloc(wav_format.block_align); 00107 if (!slice_buf) { 00108 printf("Unable to malloc slice buffer"); 00109 exit(1); 00110 } 00111 num_slices=chunk_size/wav_format.block_align; 00112 samp_int=1000000/(wav_format.sample_rate); 00113 if (verbosity) { 00114 printf("DATA chunk\n"); 00115 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); 00116 printf(" %d slices\n",num_slices); 00117 printf(" Ideal sample interval=%d\n",(unsigned)(1000000.0/wav_format.sample_rate)); 00118 printf(" programmed interrupt tick interval=%d\n",samp_int); 00119 } 00120 00121 // starting up ticker to write samples out -- no printfs until tick.detach is called 00122 if (verbosity) 00123 tick.attach_us(this,&wave_player::dac_out, 500000); 00124 else 00125 tick.attach_us(this,&wave_player::dac_out, samp_int); 00126 DAC_on=1; 00127 00128 // start reading slices, which contain one sample each for however many channels 00129 // are in the wave file. one channel=mono, two channels=stereo, etc. Since 00130 // mbed only has a single AnalogOut, all of the channels present are averaged 00131 // to produce a single sample value. This summing and averaging happens in 00132 // a variable of type signed long long, to make sure that the data doesn't 00133 // overflow regardless of sample size (8 bits, 16 bits, 32 bits). 00134 // 00135 // note that from what I can find that 8 bit wave files use unsigned data, 00136 // while 16 and 32 bit wave files use signed data 00137 // 00138 for (slice=0;slice<num_slices;slice+=1) { 00139 if (playing == false){ 00140 00141 break; 00142 } 00143 fread(slice_buf,wav_format.block_align,1,wavefile); 00144 if (feof(wavefile)) { 00145 printf("Oops -- not enough slices in the wave file\n"); 00146 exit(1); 00147 } 00148 00149 00150 data_sptr=(short *)slice_buf; // 16 bit samples 00151 data_bptr=(unsigned char *)slice_buf; // 8 bit samples 00152 data_wptr=(int *)slice_buf; // 32 bit samples 00153 slice_value=0; 00154 for (channel=0;channel<wav_format.num_channels;channel++) { 00155 switch (wav_format.sig_bps) { 00156 case 16: 00157 if (verbosity) 00158 printf("16 bit channel %d data=%d ",channel,data_sptr[channel]); 00159 slice_value+=data_sptr[channel]; 00160 break; 00161 case 32: 00162 if (verbosity) 00163 printf("32 bit channel %d data=%d ",channel,data_wptr[channel]); 00164 slice_value+=data_wptr[channel]; 00165 break; 00166 case 8: 00167 if (verbosity) 00168 printf("8 bit channel %d data=%d ",channel,(int)data_bptr[channel]); 00169 slice_value+=data_bptr[channel]; 00170 break; 00171 } 00172 } 00173 slice_value/=wav_format.num_channels; 00174 00175 // slice_value is now averaged. Next it needs to be scaled to an unsigned 16 bit value 00176 // with DC offset so it can be written to the DAC. 00177 switch (wav_format.sig_bps) { 00178 case 8: slice_value<<=8; 00179 break; 00180 case 16: slice_value+=32768; 00181 break; 00182 case 32: slice_value>>=16; 00183 slice_value+=32768; 00184 break; 00185 } 00186 dac_data=(short unsigned)slice_value; 00187 if (verbosity) 00188 printf("sample %d wptr %d slice_value %d dac_data %u\n",slice,DAC_wptr,(int)slice_value,dac_data); 00189 DAC_fifo[DAC_wptr]=((16-vol)* dac_data)>>4; 00190 00191 00192 DAC_wptr=(DAC_wptr+1) & 0xff; 00193 while (DAC_wptr==DAC_rptr) { 00194 } 00195 } 00196 DAC_on=0; 00197 tick.detach(); 00198 free(slice_buf); 00199 break; 00200 case 0x5453494c: 00201 if (verbosity) 00202 printf("INFO chunk, size %d\n",chunk_size); 00203 fseek(wavefile,chunk_size,SEEK_CUR); 00204 break; 00205 default: 00206 printf("unknown chunk type 0x%x, size %d\n",chunk_id,chunk_size); 00207 data=fseek(wavefile,chunk_size,SEEK_CUR); 00208 break; 00209 } 00210 fread(&chunk_id,4,1,wavefile); 00211 fread(&chunk_size,4,1,wavefile); 00212 } 00213 } 00214 00215 00216 void wave_player::dac_out() 00217 { 00218 if (DAC_on) { 00219 #ifdef VERBOSE 00220 printf("ISR rdptr %d got %u\n",DAC_rptr,DAC_fifo[DAC_rptr]); 00221 #endif 00222 wave_DAC->write_u16(DAC_fifo[DAC_rptr]); 00223 DAC_rptr=(DAC_rptr+1) & 0xff; 00224 } 00225 } 00226
Generated on Tue Jul 12 2022 18:58:07 by
1.7.2
