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