5

Is it practical to record speech with the Leonardo?

I want to record speech via a MEMS microphone and stream it over a serial connection to a Raspberry Pi for speech-to-text processing.

This article states that the typical bitrate for recording voice podcasts is 64 kbps. The Arduino's analogRead() function has a maximum sample rate of typically 8,600 times/sec for a maximum bitrate of 8,600 samples/sec * 10 bits/sample = 86 kbps, so theoretically, it should be fast enough to record decent voice audio.

However, will the serial connection be fast enough to stream this much data? Theoretically, the Leonardo's serial connection can go up to 115,200 bps, but I've never reliably gotten it to go faster than 57,600 bps, which would mean the serial connection would a bottleneck that would prevent it from sending a continuous stream of 64 kbps, and therefore it would be impractical to record speech with the Arduino.

Am I wrong? Has anyone had success with voice recording while streaming it over serial?

Cerin
  • 1,688
  • 2
  • 28
  • 45

2 Answers2

3

On my page about the ADC converter I attempted to record a 4 kHz sine wave on the ATmega328P with the following code:

const byte adcPin = 0;  // A0

const int MAX_RESULTS = 256;

volatile int results [MAX_RESULTS];
volatile int resultNumber;

// ADC complete ISR
ISR (ADC_vect)
  {
  if (resultNumber >= MAX_RESULTS)
    ADCSRA = 0;  // turn off ADC
  else
    results [resultNumber++] = ADC;
  }  // end of ADC_vect

EMPTY_INTERRUPT (TIMER1_COMPB_vect);

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TCCR1B = bit (CS11) | bit (WGM12);  // CTC, prescaler of 8
  TIMSK1 = bit (OCIE1B);  // WTF?
  OCR1A = 39;    
  OCR1B = 39;   // 20 uS - sampling frequency 50 kHz

  ADCSRA =  bit (ADEN) | bit (ADIE) | bit (ADIF);   // turn ADC on, want interrupt on completion
  ADCSRA |= bit (ADPS2);  // Prescaler of 16
  ADMUX = bit (REFS0) | (adcPin & 7);
  ADCSRB = bit (ADTS0) | bit (ADTS2);  // Timer/Counter1 Compare Match B
  ADCSRA |= bit (ADATE);   // turn on automatic triggering

  // wait for buffer to fill
  while (resultNumber < MAX_RESULTS)
    { }

  for (int i = 0; i < MAX_RESULTS; i++)
    Serial.println (results [i]);

  }  // end of setup

void loop () { }

The code (rather inefficiently) sends the results in ASCII, like this:

378
710
899
992
966
827
609
367
159
38
35
147
350
593
817
965
1001
917
733
494
259
88
21
76
239
471
711
905
1001
977
839
620
376
164
39

This gave reasonable results:

Sine wave with ADC

Now the Leonardo is, of course, a different processor. However it is similar. The ADC on it should be capable of similar performance.


I should point out that this code records first, then sends the data. This is so the recording can keep up. A normal ADC conversion (if you don't change the ADC prescaler) takes 104 µs. To send 10 bits via serial at 115200 baud rate would take 173.6 µs because it would require two bytes per sample (unless you somehow compress each reading). If you could put up with 8-bit resolution (per sample) then you halve that, and can probably just stream the data out fast enough.

Greenonline
  • 3,152
  • 7
  • 36
  • 48
Nick Gammon
  • 38,901
  • 13
  • 69
  • 125
1

You don't actually have to initialize your connection to 115,200 bps or 57,600 bps. You can use a custom baud rate of 65,000 bps.

One thing to keep in mind that, you can use any custom baud rate you want, as long as it's supported by the hardware. The Arduino IDE however only supports standard baud rates.

One more thing, as you are streaming data (kind of), you might also want to look into Arduino serial buffer sizes.

Greenonline
  • 3,152
  • 7
  • 36
  • 48
ARK
  • 514
  • 2
  • 15