Twittering Billy Bass plays back samples and looks out for and reads twitters!
Dependencies: NetServices mbed
billy.cpp
- Committer:
- simon
- Date:
- 2011-04-09
- Revision:
- 1:27b1efbf5a46
- Parent:
- 0:ad2574c88043
File content as of revision 1:27b1efbf5a46:
// Original core billy player code factored from Steve Ravet's Big Mouth Billy Bass // - See http://mbed.org/cookbook/Big-Mouth-Billy-Bass #include "billy.h" #include "mbed.h" #define SAMPLE_FREQ 40000 #define BUF_SIZE (SAMPLE_FREQ/10) #define SLICE_BUF_SIZE 1 #define USE_PUSHBUTTON 1 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; // Billy's i/o AnalogOut DACout(p18); PwmOut body(p21); PwmOut mouth(p22); PwmOut tail(p23); Ticker tick; // 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); unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate); void billy_play(char *wavname, char *movname) { 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); 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); 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) { } } } // wait for ISR to drain FIFO wait_us(300); tick.detach(); printf("Ticker detached\n"); 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); body.pulsewidth_us(0); mouth.pulsewidth_us(0); tail.pulsewidth_us(0); } void dac_out() { 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; } 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"); fclose(movfile); return num_movements; }