Main fish project files
Dependencies: SDHCFileSystem wave_player
Fork of billy by
main.cpp
- Committer:
- Dean
- Date:
- 2015-07-15
- Revision:
- 1:35e4090cf6aa
- Parent:
- 0:ef6fc1737022
File content as of revision 1:35e4090cf6aa:
#include "mbed.h" //The next two includes are from the SDHC File System #include "string" #include "SDHCFileSystem.h" #define SAMPLE_FREQ 40000 #define BUF_SIZE (SAMPLE_FREQ/10) #define SLICE_BUF_SIZE 1 // include this #define to enable lots of serial output //#define VERBOSE typedef struct uFMT_STRUCT { short comp_code; short num_channels; unsigned sample_rate; unsigned avg_Bps; short block_align; short sig_bps; } FMT_STRUCT; typedef struct uMOV_STRUCT { long sample; unsigned motor; unsigned duty_cycle; unsigned played; } MOV_STRUCT; // global MBED things AnalogOut DACout(p18); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); DigitalOut digout(p8); DigitalIn pushbutton(p22); PwmOut body(p25); PwmOut mouth(p24); PwmOut tail(p23); Ticker tick; SDFileSystem sd(p5, p6, p7, p13, "sd"); // global variables used both by the main program and the ISR short DAC_fifo[256]; // FIFO for the DAC short DAC_wptr; // FIFO pointer volatile short DAC_rptr; // FIFO pointer long slice; unsigned num_movements; unsigned current_movement; MOV_STRUCT movements[500]; void dac_out(void); void play_wave(char *,char *,unsigned); void cleanup(char *); unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate); int main() { FILE *cmdfile; char cmdline[100]; char *movfile,*tmp; char cmdfile_name[]="/sd/fish.txt"; unsigned slow_mode=0; if (pushbutton) slow_mode=1; led1=0; wait(.5); led1=1; wait(.5); led1=0; printf("\nHello, world!\n"); if (slow_mode) printf("Slooooow mode enabled...\n"); printf("Waiting for button push\n"); while (!pushbutton); printf("Button pushed\n"); while (1) { cmdfile=fopen(cmdfile_name,"rb"); if (!cmdfile) { printf("Unable to open command file '%s'\n",cmdfile_name); exit(1); } fgets(cmdline,100,cmdfile); while (!feof(cmdfile)) { printf("Parsing '%s' from command file '%s'\n",cmdline,cmdfile_name); tmp=strchr(cmdline,'#'); if (tmp) *tmp=0; movfile=strchr(cmdline,' '); if (movfile) { *movfile=0; movfile++; tmp=strchr(movfile,'\n'); cleanup(movfile); if (tmp) *tmp=0; #ifdef USE_PUSHBUTTON printf("Waiting for button push\n"); while (!pushbutton); printf("Button pushed\n"); #else wait_ms(2000); #endif play_wave(cmdline,movfile,slow_mode); printf("Back from play_wave()\n"); } else { printf("Unable to parse '%s' from command file '%s'\n",cmdline,cmdfile_name); } fgets(cmdline,100,cmdfile); } fclose(cmdfile); printf("Goodbye, world!\n"); } } void play_wave(char *wavname,char *movname,unsigned slow) { unsigned chunk_id,chunk_size,channel; unsigned data,samp_int,i; short dac_data; char *slice_buf; short *data_sptr; unsigned char *data_bptr; int *data_wptr; FMT_STRUCT wav_format; FILE *wavfile; long num_slices; long long slice_value; int verbosity=0; DAC_wptr=0; DAC_rptr=0; for (i=0;i<256;i+=2) { DAC_fifo[i]=0; DAC_fifo[i+1]=3000; } DAC_wptr=4; body.period_us(100); mouth.period_us(100); tail.period_us(100); led1=led2=led3=led4=0; printf("Playing wave file '%s', mov file '%s'\n",wavname,movname); wavfile=fopen(wavname,"rb"); if (!wavfile) { printf("Unable to open wav file '%s'\n",wavname); return; } fread(&chunk_id,4,1,wavfile); fread(&chunk_size,4,1,wavfile); while (!feof(wavfile)) { printf("Read chunk ID 0x%x, size 0x%x\n",chunk_id,chunk_size); switch (chunk_id) { case 0x46464952: fread(&data,4,1,wavfile); printf("RIFF chunk\n"); printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); printf(" RIFF type 0x%x\n",data); break; case 0x20746d66: fread(&wav_format,sizeof(wav_format),1,wavfile); printf("FORMAT chunk\n"); printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); printf(" compression code %d\n",wav_format.comp_code); printf(" %d channels\n",wav_format.num_channels); printf(" %d samples/sec\n",wav_format.sample_rate); printf(" %d bytes/sec\n",wav_format.avg_Bps); printf(" block align %d\n",wav_format.block_align); printf(" %d bits per sample\n",wav_format.sig_bps); if (chunk_size > sizeof(wav_format)) fseek(wavfile,chunk_size-sizeof(wav_format),SEEK_CUR); // create a slice buffer large enough to hold multiple slices slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE); if (!slice_buf) { printf("Unable to malloc slice buffer"); exit(1); } // now that the sample rate is known, process the movement file num_movements=process_movement_file(movname,movements,wav_format.sample_rate); break; case 0x61746164: slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE); if (!slice_buf) { printf("Unable to malloc slice buffer"); exit(1); } num_slices=chunk_size/wav_format.block_align; printf("DATA chunk\n"); printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); printf(" %d slices\n",num_slices); printf(" Ideal sample interval=%d\n",(unsigned)(1000000.0/wav_format.sample_rate)); samp_int=1000000/(wav_format.sample_rate); if (slow) samp_int*=1.5; printf(" programmed interrupt tick interval=%d\n",samp_int); // starting up ticker to write samples out -- no printfs until tick.detach is called current_movement=0; tick.attach_us(&dac_out, samp_int); led2=1; for (slice=0;slice<num_slices;slice+=SLICE_BUF_SIZE) { fread(slice_buf,wav_format.block_align*SLICE_BUF_SIZE,1,wavfile); if (feof(wavfile)) { printf("Oops -- not enough slices in the wave file\n"); exit(1); } data_sptr=(short *)slice_buf; data_bptr=(unsigned char *)slice_buf; data_wptr=(int *)slice_buf; slice_value=0; for (i=0;i<SLICE_BUF_SIZE;i++) { for (channel=0;channel<wav_format.num_channels;channel++) { switch (wav_format.sig_bps) { case 16: if (verbosity) printf("16 bit channel %d data=%d ",channel,data_sptr[channel]); slice_value+=data_sptr[channel]; break; case 32: if (verbosity) printf("32 bit channel %d data=%d ",channel,data_wptr[channel]); slice_value+=data_wptr[channel]; break; case 8: if (verbosity) printf("8 bit channel %d data=%d ",channel,(int)data_bptr[channel]); slice_value+=data_bptr[channel]; break; } } slice_value/=wav_format.num_channels; // slice_value is now averaged. Next it needs to be scaled to an unsigned 16 bit value // with DC offset so it can be written to the DAC. switch (wav_format.sig_bps) { case 8: slice_value<<=8; break; case 16: slice_value+=32768; break; case 32: slice_value>>=16; slice_value+=32768; break; } dac_data=(short unsigned )slice_value; if (verbosity) printf("sample %d wptr %d slice_value %d dac_data %u\n",slice,DAC_wptr,(int)slice_value,dac_data); // finally stick it in the DAC FIFO. If the write pointer wraps around and meets the read pointer // the wait until the read pointer moves. DAC_fifo[DAC_wptr]=dac_data; DAC_wptr=(DAC_wptr+1) & 0xff; while (DAC_wptr==DAC_rptr) { } } } led2=0; // wait for ISR to drain FIFO wait_us(300); tick.detach(); printf("Ticker detached\n"); led3=1; free(slice_buf); break; case 0x5453494c: printf("INFO chunk, size %d\n",chunk_size); fseek(wavfile,chunk_size,SEEK_CUR); break; default: printf("unknown chunk type 0x%x, size %d\n",chunk_id,chunk_size); data=fseek(wavfile,chunk_size,SEEK_CUR); break; } fread(&chunk_id,4,1,wavfile); fread(&chunk_size,4,1,wavfile); } printf("Done with wave file\n"); fclose(wavfile); led1=0; body.pulsewidth_us(0); mouth.pulsewidth_us(0); tail.pulsewidth_us(0); } void dac_out() { // This line declared but not used int value; digout=1; if (!movements[current_movement].played) { if (movements[current_movement].sample<=slice) { if (movements[current_movement].motor==0) body.pulsewidth_us(movements[current_movement].duty_cycle); if (movements[current_movement].motor==1) mouth.pulsewidth_us(movements[current_movement].duty_cycle); if (movements[current_movement].motor==2) tail.pulsewidth_us(movements[current_movement].duty_cycle); movements[current_movement].played=1; current_movement++; } } DACout.write_u16(DAC_fifo[DAC_rptr]); DAC_rptr=(DAC_rptr+1) & 0xff; digout=0; } void cleanup(char *s) { char *t; t=strchr(s,'\n'); if (t) *t=0; t=strchr(s,'\r'); if (t) *t=0; } unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate) { FILE *movfile; char line[100],*tmp; unsigned num_movements,i,j,x; movfile=fopen(mfname,"rb"); if (!movfile) { printf("Unable to open mov file '%s'\n",mfname); return 0; } fgets(line,100,movfile); num_movements=0; #ifdef VERBOSE printf("Motor report...\n"); #endif while (!feof(movfile)) { if (line[0]!='#') { tmp=line; // first thing on line is time in ms movements[num_movements].sample=(atol(tmp)*samp_rate)/1000; // skip digits (non whitespace) tmp=line; while (*tmp!=' ' && *tmp!='\t' && *tmp!=0) tmp++; // skip whitespace while ((*tmp==' ' | *tmp=='\t') && *tmp!=0) tmp++; if (strstr(tmp,"body")) movements[num_movements].motor=0; if (strstr(tmp,"mouth")) movements[num_movements].motor=1; if (strstr(tmp,"tail")) movements[num_movements].motor=2; // skip letters (non whitespace) while (*tmp!=' ' && *tmp!='\t') tmp++; // skip whitespace while (*tmp==' ' | *tmp=='\t') tmp++; if (tmp) movements[num_movements].duty_cycle=atoi(tmp); movements[num_movements].played=0; #ifdef VERBOSE 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); #endif num_movements++; } fgets(line,100,movfile); } printf(" %d movements read\n",num_movements); printf(" sorting movements..."); for (i=0;i<num_movements;i++) { for (j=i;j<num_movements;j++) { if (movements[j].sample < movements[i].sample) { x=movements[i].sample; movements[i].sample=movements[j].sample; movements[j].sample=x; x=movements[i].motor ; movements[i].motor =movements[j].motor ; movements[j].motor =x; x=movements[i].duty_cycle;movements[i].duty_cycle=movements[j].duty_cycle;movements[j].duty_cycle=x; } } } printf("done\n"); return num_movements; }