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