Twittering Billy Bass plays back samples and looks out for and reads twitters!

Dependencies:   NetServices mbed

Committer:
simon
Date:
Sat Apr 09 08:35:20 2011 +0000
Revision:
1:27b1efbf5a46
Parent:
0:ad2574c88043

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
simon 1:27b1efbf5a46 1 // Original core billy player code factored from Steve Ravet's Big Mouth Billy Bass
simon 1:27b1efbf5a46 2 // - See http://mbed.org/cookbook/Big-Mouth-Billy-Bass
simon 1:27b1efbf5a46 3
simon 0:ad2574c88043 4 #include "billy.h"
simon 0:ad2574c88043 5
simon 0:ad2574c88043 6 #include "mbed.h"
simon 0:ad2574c88043 7
simon 0:ad2574c88043 8 #define SAMPLE_FREQ 40000
simon 0:ad2574c88043 9 #define BUF_SIZE (SAMPLE_FREQ/10)
simon 0:ad2574c88043 10 #define SLICE_BUF_SIZE 1
simon 0:ad2574c88043 11 #define USE_PUSHBUTTON 1
simon 0:ad2574c88043 12
simon 0:ad2574c88043 13 typedef struct uFMT_STRUCT {
simon 0:ad2574c88043 14 short comp_code;
simon 0:ad2574c88043 15 short num_channels;
simon 0:ad2574c88043 16 unsigned sample_rate;
simon 0:ad2574c88043 17 unsigned avg_Bps;
simon 0:ad2574c88043 18 short block_align;
simon 0:ad2574c88043 19 short sig_bps;
simon 0:ad2574c88043 20 } FMT_STRUCT;
simon 0:ad2574c88043 21
simon 0:ad2574c88043 22 typedef struct uMOV_STRUCT {
simon 0:ad2574c88043 23 long sample;
simon 0:ad2574c88043 24 unsigned motor;
simon 0:ad2574c88043 25 unsigned duty_cycle;
simon 0:ad2574c88043 26 unsigned played;
simon 0:ad2574c88043 27 } MOV_STRUCT;
simon 0:ad2574c88043 28
simon 0:ad2574c88043 29 // Billy's i/o
simon 0:ad2574c88043 30 AnalogOut DACout(p18);
simon 0:ad2574c88043 31 PwmOut body(p21);
simon 0:ad2574c88043 32 PwmOut mouth(p22);
simon 0:ad2574c88043 33 PwmOut tail(p23);
simon 0:ad2574c88043 34 Ticker tick;
simon 0:ad2574c88043 35
simon 0:ad2574c88043 36 // global variables used both by the main program and the ISR
simon 0:ad2574c88043 37 short DAC_fifo[256]; // FIFO for the DAC
simon 0:ad2574c88043 38 short DAC_wptr; // FIFO pointer
simon 0:ad2574c88043 39 volatile short DAC_rptr; // FIFO pointer
simon 0:ad2574c88043 40 long slice;
simon 0:ad2574c88043 41 unsigned num_movements;
simon 0:ad2574c88043 42 unsigned current_movement;
simon 0:ad2574c88043 43 MOV_STRUCT movements[500];
simon 0:ad2574c88043 44
simon 0:ad2574c88043 45 void dac_out(void);
simon 0:ad2574c88043 46 unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate);
simon 0:ad2574c88043 47
simon 0:ad2574c88043 48 void billy_play(char *wavname, char *movname) {
simon 0:ad2574c88043 49 unsigned chunk_id,chunk_size,channel;
simon 0:ad2574c88043 50 unsigned data,samp_int,i;
simon 0:ad2574c88043 51 short dac_data;
simon 0:ad2574c88043 52 char *slice_buf;
simon 0:ad2574c88043 53 short *data_sptr;
simon 0:ad2574c88043 54 unsigned char *data_bptr;
simon 0:ad2574c88043 55 int *data_wptr;
simon 0:ad2574c88043 56 FMT_STRUCT wav_format;
simon 0:ad2574c88043 57 FILE *wavfile;
simon 0:ad2574c88043 58 long num_slices;
simon 0:ad2574c88043 59 long long slice_value;
simon 0:ad2574c88043 60 int verbosity=0;
simon 0:ad2574c88043 61 DAC_wptr=0;
simon 0:ad2574c88043 62 DAC_rptr=0;
simon 0:ad2574c88043 63 for (i=0;i<256;i+=2) {
simon 0:ad2574c88043 64 DAC_fifo[i]=0;
simon 0:ad2574c88043 65 DAC_fifo[i+1]=3000;
simon 0:ad2574c88043 66 }
simon 0:ad2574c88043 67 DAC_wptr=4;
simon 0:ad2574c88043 68
simon 0:ad2574c88043 69 body.period_us(100);
simon 0:ad2574c88043 70 mouth.period_us(100);
simon 0:ad2574c88043 71 tail.period_us(100);
simon 0:ad2574c88043 72
simon 0:ad2574c88043 73 printf("Playing wave file '%s', mov file '%s'\n",wavname, movname);
simon 0:ad2574c88043 74
simon 0:ad2574c88043 75 wavfile=fopen(wavname,"rb");
simon 0:ad2574c88043 76 if (!wavfile) {
simon 0:ad2574c88043 77 printf("Unable to open wav file '%s'\n",wavname);
simon 0:ad2574c88043 78 return;
simon 0:ad2574c88043 79 }
simon 0:ad2574c88043 80
simon 0:ad2574c88043 81 fread(&chunk_id,4,1,wavfile);
simon 0:ad2574c88043 82 fread(&chunk_size,4,1,wavfile);
simon 0:ad2574c88043 83 while (!feof(wavfile)) {
simon 0:ad2574c88043 84 printf("Read chunk ID 0x%x, size 0x%x\n",chunk_id,chunk_size);
simon 0:ad2574c88043 85 switch (chunk_id) {
simon 0:ad2574c88043 86 case 0x46464952:
simon 0:ad2574c88043 87 fread(&data,4,1,wavfile);
simon 0:ad2574c88043 88 printf("RIFF chunk\n");
simon 0:ad2574c88043 89 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size);
simon 0:ad2574c88043 90 printf(" RIFF type 0x%x\n",data);
simon 0:ad2574c88043 91 break;
simon 0:ad2574c88043 92 case 0x20746d66:
simon 0:ad2574c88043 93 fread(&wav_format,sizeof(wav_format),1,wavfile);
simon 0:ad2574c88043 94 printf("FORMAT chunk\n");
simon 0:ad2574c88043 95 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size);
simon 0:ad2574c88043 96 printf(" compression code %d\n",wav_format.comp_code);
simon 0:ad2574c88043 97 printf(" %d channels\n",wav_format.num_channels);
simon 0:ad2574c88043 98 printf(" %d samples/sec\n",wav_format.sample_rate);
simon 0:ad2574c88043 99 printf(" %d bytes/sec\n",wav_format.avg_Bps);
simon 0:ad2574c88043 100 printf(" block align %d\n",wav_format.block_align);
simon 0:ad2574c88043 101 printf(" %d bits per sample\n",wav_format.sig_bps);
simon 0:ad2574c88043 102 if (chunk_size > sizeof(wav_format))
simon 0:ad2574c88043 103 fseek(wavfile,chunk_size-sizeof(wav_format),SEEK_CUR);
simon 0:ad2574c88043 104 // create a slice buffer large enough to hold multiple slices
simon 0:ad2574c88043 105 slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE);
simon 0:ad2574c88043 106 if (!slice_buf) {
simon 0:ad2574c88043 107 printf("Unable to malloc slice buffer");
simon 0:ad2574c88043 108 exit(1);
simon 0:ad2574c88043 109 }
simon 0:ad2574c88043 110 // now that the sample rate is known, process the movement file
simon 0:ad2574c88043 111 num_movements=process_movement_file(movname,movements,wav_format.sample_rate);
simon 0:ad2574c88043 112 break;
simon 0:ad2574c88043 113
simon 0:ad2574c88043 114 case 0x61746164:
simon 0:ad2574c88043 115 slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE);
simon 0:ad2574c88043 116 if (!slice_buf) {
simon 0:ad2574c88043 117 printf("Unable to malloc slice buffer");
simon 0:ad2574c88043 118 exit(1);
simon 0:ad2574c88043 119 }
simon 0:ad2574c88043 120 num_slices=chunk_size/wav_format.block_align;
simon 0:ad2574c88043 121 printf("DATA chunk\n");
simon 0:ad2574c88043 122 printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size);
simon 0:ad2574c88043 123 printf(" %d slices\n",num_slices);
simon 0:ad2574c88043 124 printf(" Ideal sample interval=%d\n",(unsigned)(1000000.0/wav_format.sample_rate));
simon 0:ad2574c88043 125 samp_int=1000000/(wav_format.sample_rate);
simon 0:ad2574c88043 126
simon 0:ad2574c88043 127 printf(" programmed interrupt tick interval=%d\n",samp_int);
simon 0:ad2574c88043 128
simon 0:ad2574c88043 129 // starting up ticker to write samples out -- no printfs until tick.detach is called
simon 0:ad2574c88043 130 current_movement = 0;
simon 0:ad2574c88043 131 tick.attach_us(&dac_out, samp_int);
simon 0:ad2574c88043 132 //led2=1;
simon 0:ad2574c88043 133 for (slice=0;slice<num_slices;slice+=SLICE_BUF_SIZE) {
simon 0:ad2574c88043 134 fread(slice_buf,wav_format.block_align*SLICE_BUF_SIZE,1,wavfile);
simon 0:ad2574c88043 135 if (feof(wavfile)) {
simon 0:ad2574c88043 136 printf("Oops -- not enough slices in the wave file\n");
simon 0:ad2574c88043 137 exit(1);
simon 0:ad2574c88043 138 }
simon 0:ad2574c88043 139 data_sptr=(short *)slice_buf;
simon 0:ad2574c88043 140 data_bptr=(unsigned char *)slice_buf;
simon 0:ad2574c88043 141 data_wptr=(int *)slice_buf;
simon 0:ad2574c88043 142 slice_value=0;
simon 0:ad2574c88043 143 for (i=0;i<SLICE_BUF_SIZE;i++) {
simon 0:ad2574c88043 144 for (channel=0;channel<wav_format.num_channels;channel++) {
simon 0:ad2574c88043 145 switch (wav_format.sig_bps) {
simon 0:ad2574c88043 146 case 16:
simon 0:ad2574c88043 147 if (verbosity)
simon 0:ad2574c88043 148 printf("16 bit channel %d data=%d ",channel,data_sptr[channel]);
simon 0:ad2574c88043 149 slice_value+=data_sptr[channel];
simon 0:ad2574c88043 150 break;
simon 0:ad2574c88043 151 case 32:
simon 0:ad2574c88043 152 if (verbosity)
simon 0:ad2574c88043 153 printf("32 bit channel %d data=%d ",channel,data_wptr[channel]);
simon 0:ad2574c88043 154 slice_value+=data_wptr[channel];
simon 0:ad2574c88043 155 break;
simon 0:ad2574c88043 156 case 8:
simon 0:ad2574c88043 157 if (verbosity)
simon 0:ad2574c88043 158 printf("8 bit channel %d data=%d ",channel,(int)data_bptr[channel]);
simon 0:ad2574c88043 159 slice_value+=data_bptr[channel];
simon 0:ad2574c88043 160 break;
simon 0:ad2574c88043 161 }
simon 0:ad2574c88043 162 }
simon 0:ad2574c88043 163 slice_value/=wav_format.num_channels;
simon 0:ad2574c88043 164
simon 0:ad2574c88043 165 // slice_value is now averaged. Next it needs to be scaled to an unsigned 16 bit value
simon 0:ad2574c88043 166 // with DC offset so it can be written to the DAC.
simon 0:ad2574c88043 167 switch (wav_format.sig_bps) {
simon 0:ad2574c88043 168 case 8:
simon 0:ad2574c88043 169 slice_value<<=8;
simon 0:ad2574c88043 170 break;
simon 0:ad2574c88043 171 case 16:
simon 0:ad2574c88043 172 slice_value+=32768;
simon 0:ad2574c88043 173 break;
simon 0:ad2574c88043 174 case 32:
simon 0:ad2574c88043 175 slice_value>>=16;
simon 0:ad2574c88043 176 slice_value+=32768;
simon 0:ad2574c88043 177 break;
simon 0:ad2574c88043 178 }
simon 0:ad2574c88043 179 dac_data=(short unsigned )slice_value;
simon 0:ad2574c88043 180 if (verbosity)
simon 0:ad2574c88043 181 printf("sample %d wptr %d slice_value %d dac_data %u\n",slice,DAC_wptr,(int)slice_value,dac_data);
simon 0:ad2574c88043 182
simon 0:ad2574c88043 183 // finally stick it in the DAC FIFO. If the write pointer wraps around and meets the read pointer
simon 0:ad2574c88043 184 // the wait until the read pointer moves.
simon 0:ad2574c88043 185 DAC_fifo[DAC_wptr]=dac_data;
simon 0:ad2574c88043 186 DAC_wptr=(DAC_wptr+1) & 0xff;
simon 0:ad2574c88043 187 while (DAC_wptr==DAC_rptr) {
simon 0:ad2574c88043 188 }
simon 0:ad2574c88043 189 }
simon 0:ad2574c88043 190 }
simon 0:ad2574c88043 191
simon 0:ad2574c88043 192 // wait for ISR to drain FIFO
simon 0:ad2574c88043 193 wait_us(300);
simon 0:ad2574c88043 194 tick.detach();
simon 0:ad2574c88043 195 printf("Ticker detached\n");
simon 0:ad2574c88043 196 free(slice_buf);
simon 0:ad2574c88043 197 break;
simon 0:ad2574c88043 198 case 0x5453494c:
simon 0:ad2574c88043 199 printf("INFO chunk, size %d\n",chunk_size);
simon 0:ad2574c88043 200 fseek(wavfile,chunk_size,SEEK_CUR);
simon 0:ad2574c88043 201 break;
simon 0:ad2574c88043 202 default:
simon 0:ad2574c88043 203 printf("unknown chunk type 0x%x, size %d\n",chunk_id,chunk_size);
simon 0:ad2574c88043 204 data=fseek(wavfile,chunk_size,SEEK_CUR);
simon 0:ad2574c88043 205 break;
simon 0:ad2574c88043 206 }
simon 0:ad2574c88043 207 fread(&chunk_id,4,1,wavfile);
simon 0:ad2574c88043 208 fread(&chunk_size,4,1,wavfile);
simon 0:ad2574c88043 209 }
simon 0:ad2574c88043 210 printf("Done with wave file\n");
simon 0:ad2574c88043 211 fclose(wavfile);
simon 0:ad2574c88043 212 body.pulsewidth_us(0);
simon 0:ad2574c88043 213 mouth.pulsewidth_us(0);
simon 0:ad2574c88043 214 tail.pulsewidth_us(0);
simon 0:ad2574c88043 215 }
simon 0:ad2574c88043 216
simon 0:ad2574c88043 217 void dac_out() {
simon 0:ad2574c88043 218 if (!movements[current_movement].played) {
simon 0:ad2574c88043 219 if (movements[current_movement].sample<=slice) {
simon 0:ad2574c88043 220 if (movements[current_movement].motor==0) body.pulsewidth_us(movements[current_movement].duty_cycle);
simon 0:ad2574c88043 221 if (movements[current_movement].motor==1) mouth.pulsewidth_us(movements[current_movement].duty_cycle);
simon 0:ad2574c88043 222 if (movements[current_movement].motor==2) tail.pulsewidth_us(movements[current_movement].duty_cycle);
simon 0:ad2574c88043 223 movements[current_movement].played=1;
simon 0:ad2574c88043 224 current_movement++;
simon 0:ad2574c88043 225 }
simon 0:ad2574c88043 226 }
simon 0:ad2574c88043 227 DACout.write_u16(DAC_fifo[DAC_rptr]);
simon 0:ad2574c88043 228 DAC_rptr=(DAC_rptr+1) & 0xff;
simon 0:ad2574c88043 229 }
simon 0:ad2574c88043 230
simon 0:ad2574c88043 231 unsigned process_movement_file(char *mfname, MOV_STRUCT *mv,unsigned samp_rate) {
simon 0:ad2574c88043 232 FILE *movfile;
simon 0:ad2574c88043 233 char line[100],*tmp;
simon 0:ad2574c88043 234 unsigned num_movements,i,j,x;
simon 0:ad2574c88043 235 movfile=fopen(mfname,"rb");
simon 0:ad2574c88043 236 if (!movfile) {
simon 0:ad2574c88043 237 printf("Unable to open mov file '%s'\n",mfname);
simon 0:ad2574c88043 238 return 0;
simon 0:ad2574c88043 239 }
simon 0:ad2574c88043 240
simon 0:ad2574c88043 241 fgets(line,100,movfile);
simon 0:ad2574c88043 242 num_movements=0;
simon 0:ad2574c88043 243 #ifdef VERBOSE
simon 0:ad2574c88043 244 printf("Motor report...\n");
simon 0:ad2574c88043 245 #endif
simon 0:ad2574c88043 246 while (!feof(movfile)) {
simon 0:ad2574c88043 247 if (line[0]!='#') {
simon 0:ad2574c88043 248 tmp=line;
simon 0:ad2574c88043 249 // first thing on line is time in ms
simon 0:ad2574c88043 250 movements[num_movements].sample=(atol(tmp)*samp_rate)/1000;
simon 0:ad2574c88043 251 // skip digits (non whitespace)
simon 0:ad2574c88043 252 tmp=line;
simon 0:ad2574c88043 253 while (*tmp!=' ' && *tmp!='\t' && *tmp!=0)
simon 0:ad2574c88043 254 tmp++;
simon 0:ad2574c88043 255 // skip whitespace
simon 0:ad2574c88043 256 while ((*tmp==' ' | *tmp=='\t') && *tmp!=0)
simon 0:ad2574c88043 257 tmp++;
simon 0:ad2574c88043 258 if (strstr(tmp,"body"))
simon 0:ad2574c88043 259 movements[num_movements].motor=0;
simon 0:ad2574c88043 260 if (strstr(tmp,"mouth"))
simon 0:ad2574c88043 261 movements[num_movements].motor=1;
simon 0:ad2574c88043 262 if (strstr(tmp,"tail"))
simon 0:ad2574c88043 263 movements[num_movements].motor=2;
simon 0:ad2574c88043 264 // skip letters (non whitespace)
simon 0:ad2574c88043 265 while (*tmp!=' ' && *tmp!='\t')
simon 0:ad2574c88043 266 tmp++;
simon 0:ad2574c88043 267 // skip whitespace
simon 0:ad2574c88043 268 while (*tmp==' ' | *tmp=='\t')
simon 0:ad2574c88043 269 tmp++;
simon 0:ad2574c88043 270 if (tmp)
simon 0:ad2574c88043 271 movements[num_movements].duty_cycle=atoi(tmp);
simon 0:ad2574c88043 272 movements[num_movements].played=0;
simon 0:ad2574c88043 273 #ifdef VERBOSE
simon 0:ad2574c88043 274 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);
simon 0:ad2574c88043 275 #endif
simon 0:ad2574c88043 276 num_movements++;
simon 0:ad2574c88043 277 }
simon 0:ad2574c88043 278 fgets(line,100,movfile);
simon 0:ad2574c88043 279 }
simon 0:ad2574c88043 280 printf(" %d movements read\n",num_movements);
simon 0:ad2574c88043 281 printf(" sorting movements...");
simon 0:ad2574c88043 282 for (i=0;i<num_movements;i++) {
simon 0:ad2574c88043 283 for (j=i;j<num_movements;j++) {
simon 0:ad2574c88043 284 if (movements[j].sample < movements[i].sample) {
simon 0:ad2574c88043 285 x=movements[i].sample;
simon 0:ad2574c88043 286 movements[i].sample=movements[j].sample;
simon 0:ad2574c88043 287 movements[j].sample=x;
simon 0:ad2574c88043 288 x=movements[i].motor ;
simon 0:ad2574c88043 289 movements[i].motor =movements[j].motor ;
simon 0:ad2574c88043 290 movements[j].motor =x;
simon 0:ad2574c88043 291 x=movements[i].duty_cycle;
simon 0:ad2574c88043 292 movements[i].duty_cycle=movements[j].duty_cycle;
simon 0:ad2574c88043 293 movements[j].duty_cycle=x;
simon 0:ad2574c88043 294 }
simon 0:ad2574c88043 295 }
simon 0:ad2574c88043 296 }
simon 0:ad2574c88043 297 printf("done\n");
simon 0:ad2574c88043 298 fclose(movfile);
simon 0:ad2574c88043 299 return num_movements;
simon 0:ad2574c88043 300 }