Pages: [1] 2 3   Go Down
Author Topic: Arduino Realtime Audio Processing  (Read 17546 times)
0 Members and 1 Guest are viewing this topic.
Cologne, DE
Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

For the Linux Audio Conference 2008 we prepared some examples to do realtime audio processing with arduino. The documentaion is now online:

http://interface.khm.de/index.php/labor/experimente/arduino-realtime-audio-processing/

We also put the link on the arduino playground.
Fell free to use it.
« Last Edit: October 23, 2008, 10:53:55 am by fux » Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 597
Posts: 33314
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Wuppertal/Germany
Offline Offline
God Member
*****
Karma: 1
Posts: 895
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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  smiley

Eberhard
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

martin

ps.

i put this answer also to the Arduino Development Forum
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?board=dev

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

Sir,

    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
<moz-screenshot-1.jpg>

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?

Sincerely,

David
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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);

regards
martin



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

Martin,

 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).

David

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

Kenosha, WI
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Martin,

I wanted to write some code that would measure pulse widths and this is what I came up with:
Code:
void setup(void) {
  
  Serial.begin(9600);
  
// 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:
// Start pulse train
  analogWrite(pwmPin,6);
  start = hpticks();
  delayMicroseconds(100);
  endtime = hpticks() - start;
  delay(333);
  Serial.print("100 microseconds is ");
  Serial.print(endtime);
  Serial.println(" hpticks");
  start = hpticks();
// Clear the adch by reading it
  myAnalogRead(readPin);
  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:
 for(int i=1;i<255;i++) {
    analogWrite(pwmPin,i);
    Serial.print(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:
byte myAnalogRead(byte pin) {
  
  ADMUX = (1 << 6) | (pin & 0x0f);
  sbi(ADMUX,ADLAR);  // 8-Bit ADC in ADCH Register

      // start the conversion
  sbi(ADCSRA, ADSC);

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

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

Thanks

Logged

Grenoble/Lyon - France
Offline Offline
Sr. Member
****
Karma: 0
Posts: 363
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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


SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6637
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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...
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello,
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
 sbi(ADCSRA, ADPS2);
 cbi(ADCSRA, ADPS1);
 sbi(ADCSRA, ADPS0);

martin
Logged

Kenosha, WI
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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. smiley

/me
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
http://interface.khm.de/wp-content/uploads/2009/02/sa_shield_v2_sch.pdf

here is an article that describes a audio pulse measurement
http://www.byrote.org/arduino/


regards
martin

Hi Martin,

Thank you for putting this library online
(http://interface.khm.de/index.php/labor/experimente/arduino-frequency-counter-library).

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
(etc.)

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:
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Thanks,
MM
Logged

0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 267
dinosaur cork
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

PaulB
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 30
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
http://interface.khm.de/index.php/lab/experiments/arduino-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.

martin
Logged

Pages: [1] 2 3   Go Up
Jump to: