The Big Mouth Billy Bass program

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 }