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