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