Go Down

Topic: Arduino Realtime Audio Processing (Read 23010 times) previous topic - next topic


Oct 23, 2008, 05:50 pm Last Edit: Oct 23, 2008, 05:53 pm by fux Reason: 1
For the Linux Audio Conference 2008 we prepared some examples to do realtime audio processing with arduino. The documentaion is now online:


We also put the link on the arduino playground.
Fell free to use it.


Excellent, that should answer a lot of beginners questions we get on this forum. Thanks :)



For the Linux Audio Conference 2008 we prepared some examples to do realtime audio processing with arduino.

And nobody was there to make a recording?
What about  some samples?  
I always liked that LoFi (3kHz) approach  :)



Hi David,
thanks for the response,
the sampling rate is determind by the timer2 interrupt and set to 31,25KHz. Since we measure two inputs, the  audiosignal and the pot position alternately, the effective sampling rate is 15,625 KHz.
With a prescaler of 64 and a 16000KHz Clock and 13 Cycles for one sample we get a samplerate of 16000 / 64 / 13 = 19,2 KHz
So the ADC is just ready before the sample is processsed .
Maybe i made error in reasoning but i think it should be correct so far.



i put this answer also to the Arduino Development Forum

Am 12.02.2009 um 04:43 schrieb David H. T. Harrison (home):


   I really enjoyed your web page on real time audio processing, it helped me greatly in thinking about analog input on the arduino.  I noticed in your setup() code the following:
 // set adc prescaler  to 64 for 19kHz sampling frequency
 cbi(ADCSRA, ADPS2);
 sbi(ADCSRA, ADPS1);
 sbi(ADCSRA, ADPS0);

I looked at the ATMega168 manual, and it shows table 21-4

I believe that your code is giving you 8 uSec of ADC time (adc prescaler of 16) instead of 32 uSec (adc prescaler of 64).  This may add noise to your signal?




Hi David,
you where right. After having a look to it i figured out this configuration :

 // set adc prescaler to 32 for 38 kHz sampling frequency
 sbi(ADCSRA, ADPS2);
 cbi(ADCSRA, ADPS1);
 sbi(ADCSRA, ADPS0);


Am 12.02.2009 um 16:13 schrieb David H. T. Harrison (home):


After I sent my E-mail I figured out where the 19.2 KHz came from.  However, the main point of my E-mail was that 011 (ADPS2,ADPS1,ADPS0) corresponds to an adc prescaler of 8 NOT 64 (110).


P.S. - How hard can you push the sampling rate in 8 bit mode?



I wanted to write some code that would measure pulse widths and this is what I came up with:
Code: [Select]
void setup(void) {
// set the adc prescaler to 16 this gives an adc clock of 1 Mhz.
// (I believe this is the limit of the adc)
// To convert the analog to ADHC takes 13 cycles, so I should have a
// resolution of about 13 uS
 sbi(ADCSRA, ADPS2);
 cbi(ADCSRA, ADPS1);
 cbi(ADCSRA, ADPS0);

Make an array of values reading as quickly as I possibly can.  This lets me evaluate what the arduino is seeing.  I am using the pwm function to generate a standard pulse train, thus I have connected pin 11 (pwmPin) to analogPin 2 (readPin).
Code: [Select]
// Start pulse train
 start = hpticks();
 endtime = hpticks() - start;
 Serial.print("100 microseconds is ");
 Serial.println(" hpticks");
 start = hpticks();
// Clear the adch by reading it
 for(int i=0;i<SHOTS;i++) snapshot[i] = myAnalogRead(readPin);
 endtime = hpticks() - start;

Now I determine how long a pulse train is on and off by systematically changing the pwmPin and measuring how long the pulse is on or off.
Code: [Select]
 for(int i=1;i<255;i++) {
   Serial.print(" of 255 ");
   int single;
//  Watch the pulse train turn off
   do {
     single = myAnalogRead(readPin);
   } while (single < 128);
   do {
     single = myAnalogRead(readPin);
   } while (single > 128);
// Start the measurement
   start = hpticks();
   do {
     single = myAnalogRead(readPin);
   } while (single < 128);
   endtime = hpticks();
   Serial.print("Off for  ");
   Serial.print((endtime - start)*4);
   Serial.print(" microseconds ");
// Now watch the pulse train turn ON
   do {
     single = myAnalogRead(readPin);
   } while (single > 128);
   do {
      single = myAnalogRead(readPin);
   } while (single < 128);
   start = hpticks();
   do {
     single = myAnalogRead(readPin);
   } while (single > 128);
   endtime = hpticks();
   Serial.print("On for  ");
   Serial.print((endtime - start)*4);
   Serial.println(" microseconds");

Interestingly this code shows me that the pwm frequency is about 490Hz [1/(t(ON) + t(OFF))] .  I was expecting about twice that.
Now to read the analog in one byte mode
Code: [Select]
byte myAnalogRead(byte pin) {
 ADMUX = (1 << 6) | (pin & 0x0f);
 sbi(ADMUX,ADLAR);  // 8-Bit ADC in ADCH Register

     // start the conversion

     // ADSC is cleared when the conversion finishes
 while (bit_is_set(ADCSRA, ADSC));


I should note that I have used these code fragments to watch various home-built LED-flashers with some success :).
I've noticed that your library code is interrupt driven using timer2.  Is there a better way to approach this problem?



Nice project, indeed, and very well documented. Will be really useful for some audio projects. Thx


Heh.  My scope says it's about 1000Hz on pin5 and pin6, and about 500Hz on the other PWM outputs.

That's ... interesting.  I wonder if it's intentional, or whether it's a bug?
The pin5/6 PWM outputs share the timer with the core millis() timer, so they pretty much have to ~1000Hz.
The comments say that the prescaler factors are all being set to the 64, but they set different bits...


in some examples i used some pins to monitor the timing with a scope. Maybe thats the reason why you see a signal there. The Audio PWM output has an freq. of 64 KHz anyway.

here is the correct prescaler for the adc again
// set adc prescaler to 32 for 38 kHz sampling frequency



Hi guys,

I just finished rewriting an interrupt based pulse width analyzer http://www.byrote.org/arduino/.  It has 16 uSec resolution and will average 100 cycles.  If you think it might be appropriate for the "playground" near the frequency monitor feel free to set up a link (I have yet to figure out the playground).  Thanks for the back and forth. :)



Hi Martijn,
its good for audio frequencies , but a period length measurement is for audio is more suitable.
For the input you need a squarewave signal , so a preamp when using an electret mic is a must.
On our SensorAktor Board you will see an mic amp with an TLC272 opamp.

here is an article that describes a audio pulse measurement


Hi Martin,

Thank you for putting this library online

I hope I may steal some of your time and ask you one question, since I'm not
very familiar with audio amplification.

I started playing with the library today, to get to know it better. I hooked
up an electret mic to the schematic of the one-transistor amplifier (using
the BC547), but the output of the Arduino is:

Frequency Counter
0  Freq: 0
1  Freq: 65536
2  Freq: 0
3  Freq: 0
4  Freq: 0

Now I wonder about two things: (1) is this schematic fit for /audio/
frequencies, or only for radio/HF?, (2) is an electret mic suitable?

I'm using the example provide with the library:


This project looks great, thanks to everyone involved with making it.

I'm sorry to post here with extreme newbie questions, but a quick look through the forums left me clueless as to a better place to ask. My questions are:

1) Where can I find out more about the _SFR_BYTE and _BV functions (macros?) and about writing ISR functions? I know I don't need to understand them to use the code, but I really need to understand this stuff better if I want modify the code or hack my own solutions. I think I understand that the main reason to use this low level stuff is to change the interrupt frequency so that we can make the PWM frequency high enough to be useful for audio... is this kind of correct?

2) (Off topic RE arduino) RE the output stage: I think that the main reason we need a low pass filter is to filter out the "carrier" signal of the pwm.... is this correct? I know a little bit about amplitude and frequency modulation/demodulation so I am trying to frame the example here in terms that I'm familiar with.
BTW, Is there any reason to use an inductor in the output "low pass filter"? I know it does change the output frequency response, but you could get a simple low pass without it right?

3) Can anyone give me a little hint as to what the multi-plexer is doing in this example? My practical knowledge of multiplexing is non-existent. It looks like its part of switching between monitoring the potentiometer voltage and the audio input signal but I don't understand at a hardware level why there's a multiplexer involved when there are two separate input channels... are the signals really routed through the same physical path?

Once again, apologies for the newbie post. As you can probably tell, most of my experience is in high level languages, and I've never had to  deal much with hardware interrupts etc. I am currently reading all the links I can find about interrupts on the arduino, etc, but nonetheless I hope someone has the time to offer me a link or some brief guidance.

Many thanks,
- MM


Hi again,

I have to admit that I mixed up the idea of this thread, which is about Realtime Audio with Arduino generally, with the specific example provided by Lab3 in the first post. Sorry about that.

I'm now going through the ATmega168 manual (or at least the bits that seem relevant) to try to understand the low level code from that example a bit better. I'd still love some extra explanations  if anyone can spare the time.



This is pretty darn exciting - how about wrapping this work up into a decent FreqOut function /library, instead of my somewhat lame bit-banged one? (in the playground)

It could have sine, triangle and square to start - but I realize there might be issues with having two or more wavetables since the memory overhead is high (maybe wavetables in PROGMEM)? Or are there speed issues with recovering data from PROGMEM fast enough.

I'll be happy to help anyway I can.



Hi PaulB,
i think its too special for "libraying" it. The analoRead , delay , and pwm would not work properly in the arduino anymore. but if you like to  try it out you  find in may frequency counter library
some hints how to deal with interrupts in librays.

wavetables in PROGMEM are possible but i did not try it out yet. Maybe the access to the Flash is to slow but copying the wavetable from the PROGMEM into an wavearray solves that.


Go Up

Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

via Egeo 16
Torino, 10131