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

Dependencies:   NetServices mbed

Committer:
simon
Date:
Wed Apr 06 15:16:45 2011 +0000
Revision:
0:ad2574c88043
Child:
1:27b1efbf5a46

        

Who changed what in which revision?

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