Steve Ravet
/
billy
The Big Mouth Billy Bass program
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 00002 #include "mbed.h" 00003 #include "SDFileSystem.h" 00004 00005 #define SAMPLE_FREQ 40000 00006 #define BUF_SIZE (SAMPLE_FREQ/10) 00007 #define SLICE_BUF_SIZE 1 00008 00009 // include this #define to enable lots of serial output 00010 //#define VERBOSE 00011 00012 00013 00014 typedef struct uFMT_STRUCT { 00015 short comp_code; 00016 short num_channels; 00017 unsigned sample_rate; 00018 unsigned avg_Bps; 00019 short block_align; 00020 short sig_bps; 00021 } FMT_STRUCT; 00022 00023 00024 typedef struct uMOV_STRUCT { 00025 long sample; 00026 unsigned motor; 00027 unsigned duty_cycle; 00028 unsigned played; 00029 } MOV_STRUCT; 00030 00031 // global MBED things 00032 AnalogOut DACout(p18); 00033 DigitalOut led1(LED1); 00034 DigitalOut led2(LED2); 00035 DigitalOut led3(LED3); 00036 DigitalOut led4(LED4); 00037 DigitalOut digout(p8); 00038 DigitalIn pushbutton(p24); 00039 PwmOut body(p21); 00040 PwmOut mouth(p22); 00041 PwmOut tail(p23); 00042 Ticker tick; 00043 SDFileSystem sd(p5, p6, p7, p13, "sd"); 00044 00045 // global variables used both by the main program and the ISR 00046 short DAC_fifo[256]; // FIFO for the DAC 00047 short DAC_wptr; // FIFO pointer 00048 volatile short DAC_rptr; // FIFO pointer 00049 long slice; 00050 unsigned num_movements; 00051 unsigned current_movement; 00052 MOV_STRUCT movements[500]; 00053 00054 void dac_out(void); 00055 void play_wave(char *,char *,unsigned); 00056 void cleanup(char *); 00057 unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate); 00058 00059 00060 int main() { 00061 FILE *cmdfile; 00062 char cmdline[100]; 00063 char *movfile,*tmp; 00064 char cmdfile_name[]="/sd/fish.txt"; 00065 unsigned slow_mode=0; 00066 if (pushbutton) slow_mode=1; 00067 led1=0; wait(.5); led1=1; wait(.5); led1=0; 00068 printf("\nHello, world!\n"); 00069 if (slow_mode) printf("Slooooow mode enabled...\n"); 00070 printf("Waiting for button push\n"); 00071 while (!pushbutton); 00072 printf("Button pushed\n"); 00073 while (1) { 00074 cmdfile=fopen(cmdfile_name,"rb"); 00075 if (!cmdfile) { 00076 printf("Unable to open command file '%s'\n",cmdfile_name); 00077 exit(1); 00078 } 00079 00080 fgets(cmdline,100,cmdfile); 00081 while (!feof(cmdfile)) { 00082 printf("Parsing '%s' from command file '%s'\n",cmdline,cmdfile_name); 00083 tmp=strchr(cmdline,'#'); 00084 if (tmp) *tmp=0; 00085 movfile=strchr(cmdline,' '); 00086 if (movfile) { 00087 *movfile=0; 00088 movfile++; 00089 tmp=strchr(movfile,'\n'); 00090 cleanup(movfile); 00091 if (tmp) *tmp=0; 00092 00093 #ifdef USE_PUSHBUTTON 00094 printf("Waiting for button push\n"); 00095 while (!pushbutton); 00096 printf("Button pushed\n"); 00097 #else 00098 wait_ms(2000); 00099 #endif 00100 play_wave(cmdline,movfile,slow_mode); 00101 printf("Back from play_wave()\n"); 00102 } else { 00103 printf("Unable to parse '%s' from command file '%s'\n",cmdline,cmdfile_name); 00104 } 00105 fgets(cmdline,100,cmdfile); 00106 } 00107 fclose(cmdfile); 00108 printf("Goodbye, world!\n"); 00109 } 00110 } 00111 00112 void play_wave(char *wavname,char *movname,unsigned slow) 00113 { 00114 unsigned chunk_id,chunk_size,channel; 00115 unsigned data,samp_int,i; 00116 short dac_data; 00117 char *slice_buf; 00118 short *data_sptr; 00119 unsigned char *data_bptr; 00120 int *data_wptr; 00121 FMT_STRUCT wav_format; 00122 FILE *wavfile; 00123 long num_slices; 00124 long long slice_value; 00125 int verbosity=0; 00126 DAC_wptr=0; 00127 DAC_rptr=0; 00128 for (i=0;i<256;i+=2) { 00129 DAC_fifo[i]=0; 00130 DAC_fifo[i+1]=3000; 00131 } 00132 DAC_wptr=4; 00133 00134 body.period_us(100); 00135 mouth.period_us(100); 00136 tail.period_us(100); 00137 led1=led2=led3=led4=0; 00138 00139 printf("Playing wave file '%s', mov file '%s'\n",wavname,movname); 00140 00141 wavfile=fopen(wavname,"rb"); 00142 if (!wavfile) { 00143 printf("Unable to open wav file '%s'\n",wavname); 00144 return; 00145 } 00146 00147 00148 fread(&chunk_id,4,1,wavfile); 00149 fread(&chunk_size,4,1,wavfile); 00150 while (!feof(wavfile)) { 00151 printf("Read chunk ID 0x%x, size 0x%x\n",chunk_id,chunk_size); 00152 switch (chunk_id) { 00153 case 0x46464952: 00154 fread(&data,4,1,wavfile); 00155 printf("RIFF chunk\n"); 00156 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); 00157 printf(" RIFF type 0x%x\n",data); 00158 break; 00159 case 0x20746d66: 00160 fread(&wav_format,sizeof(wav_format),1,wavfile); 00161 printf("FORMAT chunk\n"); 00162 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); 00163 printf(" compression code %d\n",wav_format.comp_code); 00164 printf(" %d channels\n",wav_format.num_channels); 00165 printf(" %d samples/sec\n",wav_format.sample_rate); 00166 printf(" %d bytes/sec\n",wav_format.avg_Bps); 00167 printf(" block align %d\n",wav_format.block_align); 00168 printf(" %d bits per sample\n",wav_format.sig_bps); 00169 if (chunk_size > sizeof(wav_format)) 00170 fseek(wavfile,chunk_size-sizeof(wav_format),SEEK_CUR); 00171 // create a slice buffer large enough to hold multiple slices 00172 slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE); 00173 if (!slice_buf) { 00174 printf("Unable to malloc slice buffer"); 00175 exit(1); 00176 } 00177 // now that the sample rate is known, process the movement file 00178 num_movements=process_movement_file(movname,movements,wav_format.sample_rate); 00179 break; 00180 00181 case 0x61746164: 00182 slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE); 00183 if (!slice_buf) { 00184 printf("Unable to malloc slice buffer"); 00185 exit(1); 00186 } num_slices=chunk_size/wav_format.block_align; 00187 printf("DATA chunk\n"); 00188 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); 00189 printf(" %d slices\n",num_slices); 00190 printf(" Ideal sample interval=%d\n",(unsigned)(1000000.0/wav_format.sample_rate)); 00191 samp_int=1000000/(wav_format.sample_rate); 00192 if (slow) samp_int*=1.5; 00193 printf(" programmed interrupt tick interval=%d\n",samp_int); 00194 00195 // starting up ticker to write samples out -- no printfs until tick.detach is called 00196 current_movement=0; 00197 tick.attach_us(&dac_out, samp_int); 00198 led2=1; 00199 for (slice=0;slice<num_slices;slice+=SLICE_BUF_SIZE) { 00200 fread(slice_buf,wav_format.block_align*SLICE_BUF_SIZE,1,wavfile); 00201 if (feof(wavfile)) { 00202 printf("Oops -- not enough slices in the wave file\n"); 00203 exit(1); 00204 } 00205 data_sptr=(short *)slice_buf; 00206 data_bptr=(unsigned char *)slice_buf; 00207 data_wptr=(int *)slice_buf; 00208 slice_value=0; 00209 for (i=0;i<SLICE_BUF_SIZE;i++) { 00210 for (channel=0;channel<wav_format.num_channels;channel++) { 00211 switch (wav_format.sig_bps) { 00212 case 16: 00213 if (verbosity) 00214 printf("16 bit channel %d data=%d ",channel,data_sptr[channel]); 00215 slice_value+=data_sptr[channel]; 00216 break; 00217 case 32: 00218 if (verbosity) 00219 printf("32 bit channel %d data=%d ",channel,data_wptr[channel]); 00220 slice_value+=data_wptr[channel]; 00221 break; 00222 case 8: 00223 if (verbosity) 00224 printf("8 bit channel %d data=%d ",channel,(int)data_bptr[channel]); 00225 slice_value+=data_bptr[channel]; 00226 break; 00227 } 00228 } 00229 slice_value/=wav_format.num_channels; 00230 00231 // slice_value is now averaged. Next it needs to be scaled to an unsigned 16 bit value 00232 // with DC offset so it can be written to the DAC. 00233 switch (wav_format.sig_bps) { 00234 case 8: slice_value<<=8; 00235 break; 00236 case 16: slice_value+=32768; 00237 break; 00238 case 32: slice_value>>=16; 00239 slice_value+=32768; 00240 break; 00241 } 00242 dac_data=(short unsigned )slice_value; 00243 if (verbosity) 00244 printf("sample %d wptr %d slice_value %d dac_data %u\n",slice,DAC_wptr,(int)slice_value,dac_data); 00245 00246 // finally stick it in the DAC FIFO. If the write pointer wraps around and meets the read pointer 00247 // the wait until the read pointer moves. 00248 DAC_fifo[DAC_wptr]=dac_data; 00249 DAC_wptr=(DAC_wptr+1) & 0xff; 00250 while (DAC_wptr==DAC_rptr) { 00251 } 00252 } 00253 } 00254 led2=0; 00255 // wait for ISR to drain FIFO 00256 wait_us(300); 00257 tick.detach(); 00258 printf("Ticker detached\n"); 00259 led3=1; 00260 free(slice_buf); 00261 break; 00262 case 0x5453494c: 00263 printf("INFO chunk, size %d\n",chunk_size); 00264 fseek(wavfile,chunk_size,SEEK_CUR); 00265 break; 00266 default: 00267 printf("unknown chunk type 0x%x, size %d\n",chunk_id,chunk_size); 00268 data=fseek(wavfile,chunk_size,SEEK_CUR); 00269 break; 00270 } 00271 fread(&chunk_id,4,1,wavfile); 00272 fread(&chunk_size,4,1,wavfile); 00273 } 00274 printf("Done with wave file\n"); 00275 fclose(wavfile); 00276 led1=0; 00277 body.pulsewidth_us(0); 00278 mouth.pulsewidth_us(0); 00279 tail.pulsewidth_us(0); 00280 } 00281 00282 00283 void dac_out() { 00284 int value; 00285 digout=1; 00286 if (!movements[current_movement].played) { 00287 if (movements[current_movement].sample<=slice) { 00288 if (movements[current_movement].motor==0) body.pulsewidth_us(movements[current_movement].duty_cycle); 00289 if (movements[current_movement].motor==1) mouth.pulsewidth_us(movements[current_movement].duty_cycle); 00290 if (movements[current_movement].motor==2) tail.pulsewidth_us(movements[current_movement].duty_cycle); 00291 movements[current_movement].played=1; 00292 current_movement++; 00293 } 00294 } 00295 DACout.write_u16(DAC_fifo[DAC_rptr]); 00296 DAC_rptr=(DAC_rptr+1) & 0xff; 00297 digout=0; 00298 } 00299 00300 00301 void cleanup(char *s) 00302 { 00303 char *t; 00304 t=strchr(s,'\n'); 00305 if (t) *t=0; 00306 t=strchr(s,'\r'); 00307 if (t) *t=0; 00308 } 00309 00310 unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate) 00311 { 00312 FILE *movfile; 00313 char line[100],*tmp; 00314 unsigned num_movements,i,j,x; 00315 movfile=fopen(mfname,"rb"); 00316 if (!movfile) { 00317 printf("Unable to open mov file '%s'\n",mfname); 00318 return 0; 00319 } 00320 00321 fgets(line,100,movfile); 00322 num_movements=0; 00323 #ifdef VERBOSE 00324 printf("Motor report...\n"); 00325 #endif 00326 while (!feof(movfile)) { 00327 if (line[0]!='#') { 00328 tmp=line; 00329 // first thing on line is time in ms 00330 movements[num_movements].sample=(atol(tmp)*samp_rate)/1000; 00331 // skip digits (non whitespace) 00332 tmp=line; 00333 while (*tmp!=' ' && *tmp!='\t' && *tmp!=0) 00334 tmp++; 00335 // skip whitespace 00336 while ((*tmp==' ' | *tmp=='\t') && *tmp!=0) 00337 tmp++; 00338 if (strstr(tmp,"body")) 00339 movements[num_movements].motor=0; 00340 if (strstr(tmp,"mouth")) 00341 movements[num_movements].motor=1; 00342 if (strstr(tmp,"tail")) 00343 movements[num_movements].motor=2; 00344 // skip letters (non whitespace) 00345 while (*tmp!=' ' && *tmp!='\t') 00346 tmp++; 00347 // skip whitespace 00348 while (*tmp==' ' | *tmp=='\t') 00349 tmp++; 00350 if (tmp) 00351 movements[num_movements].duty_cycle=atoi(tmp); 00352 movements[num_movements].played=0; 00353 #ifdef VERBOSE 00354 printf(" moving motor %d at sample %ld with duty cycle %d\n",movements[num_movements].motor,movements[num_movements].sample,movements[num_movements].duty_cycle); 00355 #endif 00356 num_movements++; 00357 } 00358 fgets(line,100,movfile); 00359 } 00360 printf(" %d movements read\n",num_movements); 00361 printf(" sorting movements..."); 00362 for (i=0;i<num_movements;i++) { 00363 for (j=i;j<num_movements;j++) { 00364 if (movements[j].sample < movements[i].sample) { 00365 x=movements[i].sample; movements[i].sample=movements[j].sample; movements[j].sample=x; 00366 x=movements[i].motor ; movements[i].motor =movements[j].motor ; movements[j].motor =x; 00367 x=movements[i].duty_cycle;movements[i].duty_cycle=movements[j].duty_cycle;movements[j].duty_cycle=x; 00368 } 00369 } 00370 } 00371 printf("done\n"); 00372 return num_movements; 00373 }
Generated on Fri Jul 22 2022 09:40:13 by 1.7.2