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

Dependencies:   NetServices mbed

Revision:
0:ad2574c88043
Child:
1:27b1efbf5a46
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/billy.cpp	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,298 @@
+#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() {
+    int value;
+    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;
+}