Program to record speech audio into RAM and then play it back, moving Billy Bass's mouth in sync with the speech.

Dependencies:   mbed

Remember Big Mouth Billy Bass?

I've made a simple demo program for him using the Freescale FRDM-KL25Z board. I've hooked up the digital I/O to his motor driver transistors and pushbutton switch.

This program records 1.8 seconds of speech audio from ADC input when the pushbutton is pressed, then plays the audio back with Billy Bass's mouth controlled so that it opens during vowel sounds.

The ADC input is driven from a microphone and preamplifier, via a capacitor and into a resistor divider connected to the +3.3V supply pin to provide mid-range biasing for the ADC signals.

The DAC output is connected to his audio amplifier input (to the trace that was connected to pin 10 of the controller IC). I had to provide a DC bias using the DAC to get the single transistor amplifier biased into proper operation.

For more on the method of vowel recognition, please see the paper: http://www.mirlab.org/conference_papers/International_Conference/ICASSP%201999/PDF/AUTHOR/IC991957.PDF

Y. Nishida, Y. Nakadai, Y. Suzuki, T. Sakurai, T. Kurokawa, and H. Sato. 1999.

Voice recognition focusing on vowel strings on a fixed-point 20-MIPS DSP board.

In Proceedings of the Acoustics, Speech, and Signal Processing, 1999. on 1999 IEEE International Conference - Volume 01 (ICASSP '99), Vol. 1. IEEE Computer Society, Washington, DC, USA, 137-140. DOI=10.1109/ICASSP.1999.758081 http://dx.doi.org/10.1109/ICASSP.1999.758081

Files at this revision

API Documentation at this revision

Comitter:
bikeNomad
Date:
Tue May 14 17:19:45 2013 +0000
Parent:
1:2fa375aacece
Child:
3:c04d8d0493f4
Commit message:
Got 7.9KHz analog sampling working

Changed in this revision

FastAnalogIn.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- a/FastAnalogIn.h	Tue May 14 14:08:22 2013 +0000
+++ b/FastAnalogIn.h	Tue May 14 17:19:45 2013 +0000
@@ -7,12 +7,18 @@
 {
 
 using namespace mbed;
+extern "C" void ADC0_IRQHandler(void);
 
 class FastAnalogIn: public mbed::AnalogIn
 {
 public:
     void start_read() {
-        ADC0->SC1[0] = ADC_SC1_ADCH(_adc.adc);  // start conversion
+        ADC0->SC1[0] = ADC_SC1_ADCH(_adc.adc)
+                       | ADC_SC1_AIEN_MASK;     // enable interrupt
+    }
+
+    void abort_read() {
+        ADC0->SC1[0] = ADC_SC1_ADCH(0x1F);
     }
 
     uint16_t read_u16() {
@@ -23,26 +29,47 @@
         return (uint16_t)ADC0->R[0];
     }
 
-    FastAnalogIn(PinName what)
-        : mbed::AnalogIn(what) {
-        ADC0->CFG2 = /* ADC_CFG2_MUXSEL_MASK   // ADxxb channels are selected */
-            0 | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
-            | ADC_CFG2_ADHSC_MASK    // High-Speed Configuration
-            | ADC_CFG2_ADLSTS(0);    // Long Sample Time Select = 24 clocks
+    uint16_t read_u16_nowait() {
+        // Return value
+        return (uint16_t)ADC0->R[0];
+    }
+
+    uint8_t read_u8_nowait() {
+        // Return value
+        return (uint8_t)ADC0->R[0];
+    }
+
+    FastAnalogIn(PinName pin)
+        : mbed::AnalogIn(pin) {
+
+        NVIC_SetVector(ADC0_IRQn, (uint32_t)&ADC0_IRQHandler);
+        NVIC_DisableIRQ(ADC0_IRQn);
 
-        // set up for averaging 16 samples at 125KHz sample rate => 7812.5 samples/sec
+        ADC0->CFG1 = ADC_CFG1_ADLPC_MASK    // Low-Power Configuration
+                     | ADC_CFG1_ADIV(4)       // Clock Divide Select: (Input Clock)/4
+                     | ADC_CFG1_ADLSMP_MASK   // Long Sample Time
+                     | ADC_CFG1_MODE(3)       // (16)bits Resolution
+                     | ADC_CFG1_ADICLK(1);    // Input Clock: (Bus Clock)/2
+
+        ADC0->CFG2 = 0   // ADxxA channels are selected
+                     | ADC_CFG2_ADACKEN_MASK    // Asynchronous Clock Output Enable
+                     | ADC_CFG2_ADHSC_MASK      // High-Speed Configuration
+                     | ADC_CFG2_ADLSTS(0);      // Long Sample Time Select
+
+        ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference
+
         ADC0->SC3 = ADC_SC3_AVGE_MASK       // Hardware Average Enable
-                    | ADC_SC3_AVGS(2)        // 16 Samples Averaged
-                    | ADC_SC3_ADCO_MASK;      // contin conversion
+                    | ADC_SC3_AVGS(3);        // 16 Samples Averaged
+
+        ADC0->SC1[0] = ADC_SC1_ADCH(_adc.adc)
+                       | ADC_SC1_AIEN_MASK;     // enable interrupt
     }
 
     void enable_interrupt() {
-        ADC0->SC1[0] |= ADC_SC1_AIEN_MASK;   // enable interrupt
-        ADC0->SC1[1] |= ADC_SC1_AIEN_MASK;   // enable interrupt
+        NVIC_EnableIRQ(ADC0_IRQn);
     }
     void disable_interrupt() {
-        ADC0->SC1[0] &= ~ADC_SC1_AIEN_MASK;   // disable interrupt
-        ADC0->SC1[1] &= ~ADC_SC1_AIEN_MASK;   // disable interrupt
+        NVIC_DisableIRQ(ADC0_IRQn);
     }
 
 };
--- a/main.cpp	Tue May 14 14:08:22 2013 +0000
+++ b/main.cpp	Tue May 14 17:19:45 2013 +0000
@@ -26,24 +26,28 @@
 // Serial uart1(PTC4, PTC3);
 Serial pc(USBTX, USBRX);
 
-const unsigned SAMPLE_RATE_HZ  = 7812;
+const unsigned SAMPLE_RATE_HZ  = 7889;
 const unsigned SAMPLE_PERIOD_US     = (1000000U / SAMPLE_RATE_HZ);
+const unsigned SAMPLE_BUFFER_SIZE = 9000;
 
 Ticker sampleTicker;
+Timer timer;
 
-uint8_t sampleBuffer[SAMPLE_RATE_HZ];      // 1 second buffer
+uint8_t sampleBuffer[SAMPLE_BUFFER_SIZE];      // 1 second buffer
 uint8_t * volatile nextSample;
 unsigned volatile samplesRemaining;
 
 extern "C"
 void ADC0_IRQHandler(void)
 {
-    pc.printf("irq\r\n");
     if (samplesRemaining) {
-        *nextSample++ = microphone.read_u16() >> 8;
+        *nextSample++ = microphone.read_u16_nowait() >> 8;
+        microphone.start_read();
         samplesRemaining--;
     } else {
         microphone.disable_interrupt();
+        microphone.abort_read();
+        timer.stop();
     }
 }
 
@@ -54,56 +58,61 @@
         samplesRemaining--;
     } else {
         sampleTicker.detach();
+        timer.stop();
     }
 }
 
 void resetSampleBuffer()
 {
     nextSample = sampleBuffer;
-    samplesRemaining = sizeof(sampleBuffer);
+    samplesRemaining = SAMPLE_BUFFER_SIZE;
 }
 
 void recordAudio()
 {
-    pc.printf("Recording %d samples... ", sizeof(sampleBuffer));
+    pc.printf("Recording %d samples... ", SAMPLE_BUFFER_SIZE);
     blueLED = 0.0;
 
     resetSampleBuffer();
+    timer.start();
     microphone.enable_interrupt();
+    microphone.start_read();
 
     while (samplesRemaining) {
-        wait(0.05);
-        blueLED.write(1.0 - (1.0 * samplesRemaining / sizeof(sampleBuffer)));
+        wait_us(50000);
+        blueLED.write(1.0 - (1.0 * samplesRemaining / SAMPLE_BUFFER_SIZE));
     }
 
-    pc.printf("Done\r\n");
+    float elapsed = timer.read();
+    pc.printf("Done. %u samples in %f usec = %f samples/sec\r\n", SAMPLE_BUFFER_SIZE, elapsed * 1.0e6, SAMPLE_BUFFER_SIZE / elapsed);
 }
 
-void playAudio()
+void playAudio(float duration)
 {
-    pc.printf("Playing %d samples... ", sizeof(sampleBuffer));
+    pc.printf("Playing %d samples... ", SAMPLE_BUFFER_SIZE);
     greenLED = 0.0;
     resetSampleBuffer();
-    sampleTicker.attach_us(&playAudioSample, SAMPLE_PERIOD_US);
+    timer.reset();
+    timer.start();
+    sampleTicker.attach(&playAudioSample, duration/SAMPLE_BUFFER_SIZE);
     while (samplesRemaining) {
-        wait(0.05);
-        greenLED.write(1.0 - (1.0 *  samplesRemaining / sizeof(sampleBuffer)));
+        wait_us(50000);
+        greenLED.write(1.0 - (1.0 *  samplesRemaining / SAMPLE_BUFFER_SIZE));
     }
-    pc.printf("Done\r\n");
+    float elapsed = timer.read();
+    pc.printf("Done. %u samples in %f usec = %f samples/sec", SAMPLE_BUFFER_SIZE, elapsed * 1.0e6, SAMPLE_BUFFER_SIZE / elapsed);
+    pc.printf(" (Rate %#+0.2f%%)\r\n", (duration-elapsed)*100/duration);
+}
 
-}
 int main()
 {
     pc.baud(115200);
-    pc.printf("Sample buffer = %u samples; rate = %u Hz; period = %u usec\r\n", sizeof(sampleBuffer), SAMPLE_RATE_HZ, SAMPLE_PERIOD_US);
+    pc.printf("\r\n\r\nSample buffer = %u samples; rate = %u Hz; period = %u usec\r\n", SAMPLE_BUFFER_SIZE, SAMPLE_RATE_HZ, SAMPLE_PERIOD_US);
     redLED = 1.0;
     greenLED = 1.0;
     blueLED = 1.0;
 
-    microphone.enable_interrupt();
-    microphone.start_read();
-
     recordAudio();
 
-    playAudio();
+    playAudio(timer.read());
 }
--- a/mbed.bld	Tue May 14 14:08:22 2013 +0000
+++ b/mbed.bld	Tue May 14 17:19:45 2013 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/7e6c9f46b3bd
\ No newline at end of file
+http://mbed.org/users/mbed_official/code/mbed/builds/b3110cd2dd17
\ No newline at end of file