Go Down

### Topic: Calibrating a VU meter using a pot/ dynamic calibration (Read 3393 times)previous topic - next topic

#### emceepaul

##### Mar 26, 2012, 09:58 pm
Hi Folks,
The following is some code I adopted from a website for my LED VU meter. However, one of the issues is that the Sensitivity is sort of HARD-CODED. Is there a way to incorporate a more dynamic calibration going on from the audio signal depending on the song. Imagine a variable standing for 20 (the calibration factor) and changing depending on the signal strength of the cube.

You can view the "signal" strength coming through from A0 from the serial print screen and values usually are around 200 ish for me when driven by an Ipod.

int led[6] = { 3, 4, 5, 6, 7, 8}; // Assign the pins for the leds
int leftChannel = A0;  // left channel input
int left, i;

void setup()
{
for (i = 0; i < 6; i++)  // Tell the arduino that the leds are digital outputs
pinMode(led, OUTPUT);
Serial.begin(9600);
}

void loop()
{
left = analogRead(leftChannel);  // read the left channel
Serial.println(left);
Serial.print("\t");
left = left / 20;    // adjusts the sensitivity
Serial.println(left);
Serial.print("\t");

if (left == 0)  // if the volume is 0 then turn off all leds
{
for(i = 0; i < 6; i++)
{
digitalWrite(led, LOW);
}
}

else
{
for (i = 0; i < left; i++) // turn on the leds up to the volume level
{
digitalWrite(led, HIGH);
}

for(i = i; i < 6; i++)  // turn off the leds above the voltage level
{
digitalWrite(led, LOW);
}
}
}

#### Udo Klein

#1
##### Mar 26, 2012, 10:34 pm
This code uses a linear mapping of the analog value to the number of active LEDs. A logarithmic mapping is more common.

What exactly do you want? Usually a VU meter is intended as an indicator of the absolute levels. Thus adopting it to specific songs is somewhat pointless. Unless you want to have it as a kind of mini light show. But then this is pretty hard to do. You would need to know in advance the peak level of the song. Unless the time machine gets invented this is somewhat tricky.

Check out my experiments http://blog.blinkenlight.net

#### emceepaul

#2
##### Mar 27, 2012, 12:59 am

This code uses a linear mapping of the analog value to the number of active LEDs. A logarithmic mapping is more common.

Can you please direct me to a source or improvise on the code to do a logarithmic mapping? It will be great if you could kindly show me how that is done. Complete newb here; hence, no idea how that can be done.

What exactly do you want? Usually a VU meter is intended as an indicator of the absolute levels. Thus adopting it to specific songs is somewhat pointless. Unless you want to have it as a kind of mini light show. But then this is pretty hard to do. You would need to know in advance the peak level of the song. Unless the time machine gets invented this is somewhat tricky.

Thanks for asking that question. I guess I was not able to make it as clear as I wanted it to.

The problem I am envision is: let's say that the highest value of the signal I get is around 500ish, and I scale the program to react as much. I am using an Ipod to drive the VU meter at FULL volume. However, should I decrease the ipod volume, the signal strength goes down and so does the number of LEDs that light up. All I want is the user to have control over the sensitivity of the lighting. Does that make sense? Or put it the other way: is there a way to ensure that the VU meter behaves independently of the volume of the ipod?

#### emceepaul

#3
##### Mar 27, 2012, 01:08 am
Also, one other problem is: I could not drive my VU meter with my laptop!! Any reason?

#### Magician

#4
##### Mar 27, 2012, 05:17 amLast Edit: Mar 27, 2012, 05:24 am by Magician Reason: 1
Something wrong with your code:
Code: [Select]
` for (i = 0; i < left; i++) // turn on the leds up to the volume level    {     digitalWrite(led, HIGH);  <<<< Do you mean digitalWrite( i, HIGH)?    }    `
What you are looking, is "automatic gain control"  loop, or AGC. To make it works, you need a low pass filter in software, look on this web site, should be running average or similar   example somewhere in playground / library section. Arduino IDE has smoothing in analog examples code, should be o'k.
Next, change your bargraph to :
Code: [Select]
`   int ledLevelKr = map( left_input , 0, PeakHold_smoothedValue, 0, ledCountKr);  for (int thisLed = 0; thisLed < ledCountKr; thisLed++) {    if (thisLed < ledLevelKr)       digitalWrite(ledPinsKr[thisLed], HIGH);    else      digitalWrite(ledPinsKr[thisLed], LOW);   } `

#### Cinezaster

#5
##### Mar 27, 2012, 08:57 am
You should average you levels.
Because if you sample sound you have a wave and you never know where you sampled the wave.
If you want a good responsive bargraph use something like this:

Code: [Select]
`for (int num=0; num < 4; num++) {sound[num]= analogRead (inputPIN);if(num==3) {soundav=(sound[0]+sound[1]+sound[2]+sound[3])/4; // average sound levels`

For you pot controle, use a lineaire pot meter a logarithmic will work to but won't give you a fine control.
You have to determine a max and minimum value. I choose between 15 and 25 because of your 20.
Code: [Select]
`potControl = analogRead(potPIN);   // connect a linear potmeter on potPIN levelControl = map(potControl, 0, 255,15,25); // you map the values of your pot to a more desired level between 15 and 25 left = left / levelControl;     // youre code`

Use Magician his bargraph code, which is much better and more efficient.
ARDUINO-JAM  BELGIUM 2012

#### emceepaul

#6
##### Mar 28, 2012, 06:02 am

Code: [Select]
` for (i = 0; i < left; i++) // turn on the leds up to the volume level    {     digitalWrite(led, HIGH);  <<<< Do you mean digitalWrite( i, HIGH)?>>>>>> Yes, extremely sorry for this. Somehow, the original code has digitalWrite (led[i], HIGH).    }    `
What you are looking, is "automatic gain control"  loop, or AGC. To make it works, you need a low pass filter in software, look on this web site, should be running average or similar   example somewhere in playground / library section. Arduino IDE has smoothing in analog examples code, should be o'k.
Next, change your bargraph to :
Code: [Select]
`   int ledLevelKr = map( left_input , 0, PeakHold_smoothedValue, 0, ledCountKr);  for (int thisLed = 0; thisLed < ledCountKr; thisLed++) {    if (thisLed < ledLevelKr)       digitalWrite(ledPinsKr[thisLed], HIGH);    else      digitalWrite(ledPinsKr[thisLed], LOW);   } `

Thank you so much for putting this in. I was wondering whether you can elaborate / comment on the code. I get the overall picture, but am having a hard time reading what this does:

int ledLevelKr = map( left_input , 0, PeakHold_smoothedValue, 0, ledCountKr);

where did you get the variables? So I am looking for a AGC? Is the code that you put in part of it, or something attached to it. When you are talking about AGC, are you talking about smoothing as described here: http://arduino.cc/en/Tutorial/Smoothing

Thanks and looking forward to your reply.

#### emceepaul

#7
##### Mar 28, 2012, 06:05 am

You should average you levels.
Because if you sample sound you have a wave and you never know where you sampled the wave.
If you want a good responsive bargraph use something like this:

Code: [Select]
`for (int num=0; num < 4; num++) {sound[num]= analogRead (inputPIN);if(num==3) {soundav=(sound[0]+sound[1]+sound[2]+sound[3])/4; // average sound levels`

So this part averaging every 4 samples it takes. Am I right? Moreover, will it quick enough to response to the music? Extremely sorry for not being able to understand. Providing a little more context will help me.

For you pot controle, use a lineaire pot meter a logarithmic will work to but won't give you a fine control.
You have to determine a max and minimum value. I choose between 15 and 25 because of your 20.
Code: [Select]
`potControl = analogRead(potPIN);   // connect a linear potmeter on potPIN levelControl = map(potControl, 0, 255,15,25); // you map the values of your pot to a more desired level between 15 and 25 left = left / levelControl;     // youre code`

Use Magician his bargraph code, which is much better and more efficient.

If I do NOT go for a pot control, can you help me devise the code such that the calibration is logarithmic, instead of linear?

#### emceepaul

#8
##### Mar 28, 2012, 06:06 am
Also, when you guys are talking about the bargraph, which portion of the code are you referring to: the one where the LEDs are toggled?

#### Magician

#9
##### Mar 28, 2012, 07:08 am
In your arduino IDE open: File/Examples/Display->bargraph.
I copy/paste code from there. Play, and try to understand how it works.
There is a line in example sketch:
Code: [Select]
`  // map the result to a range from 0 to the number of LEDs:  int ledLevel = map(sensorReading, 0, 1023, 0, ledCount);`  which does the main function of the bargraph, it's scale numbers of lighting leds according to sensorReading value. The only issue with this, that a range from 0 to 1023 is hardcoded, and as it can't adapt itself to different music levels, it's not what you want. This is where AGC steps in.
Upper limit (1023) you should replace with another variable (peakHolder or whatever). Than, arduino should keep a track of the peak values (they call it envelope detector, wikipedia it), and change peaKHolder accordingly. One more things, to make it moves with different speed up and down, like real peak detector does, you would need second variable to store previous value, plus coefficient to regulate a falling speed.

Code: [Select]
` int peakHolder, old_peakHolder; float falling_s = 0.95;   //<<<- closer to 1 slowerThan in main loop()old_peakHolder = peakHolder;  //Save old data  for smoothing; peakHolder = analogRead(...);  //What is pin number //Smoothing, so it fall down gradually.    if ( peakHolder  <  ( old_peakHolder * falling_s ) )    peakHolder = ( old_peakHolder * falling_s );  int ledLevel = map(sensorReading, 0, peakHolder, 0, ledCount);  // And here comes BarGraph `

#### emceepaul

#10
##### Mar 28, 2012, 07:38 am
you rock magician! thanks a ton. will do it tomorrow. too sleepy now!

#### emceepaul

#11
##### Mar 30, 2012, 06:24 am
I have a quick question:

When I am sampling the audio, does it need to come from a MONO audio jack, or can I get it from a stereo? If I am to get it from a stereo do I need 2 audio inputs, aka 2 analog inputs? I don't want to go for that. However, I have a female audio jack that is stereo. Will it matter if I put in a mono male jack in it?

I am really confused.

#### Magician

#12
##### Mar 30, 2012, 06:34 am
It's up to you. Two channels stereo are independent, but very close in most audio program. They differ in phase, that isn't important for your project.
So you can take just one left channel, or connect two in parallel. Have you considered to build two channel display?
Btw, you need a DC offset for analog input,.

#### emceepaul

#13
##### Mar 31, 2012, 09:39 pm
Awesome. Fixed that part. Now I am facing a power issue. I have a few op amps that amplify my signal; however, I am just running of a +12V DC supply! How can I get the -V that is need for my opamp to work? Any ideas apart from going through a virtual ground, which is too complicated for me to understand atm?

#### emceepaul

#14
##### Apr 05, 2012, 05:39 amLast Edit: Apr 06, 2012, 04:11 am by emceepaul Reason: 1
Hey Guys,

So When I am running the following program:

int bassPins[] = { 3, 4, 5}; // Assign the pins for the leds
int treblePins[] = {6, 7, 8};
int bassInput = A1;  // left channel input
int trebleInput = A2;
int bass, treble, i;

void setup() {
for (i = 0; i < 3; i++) { // Tell the arduino that the leds are digital outputs
pinMode(bassPins, OUTPUT);
pinMode(treblePins, OUTPUT);
}
Serial.begin(9600); // Uncomment to enable troubleshooting over serial.
}

void loop() {
String b = "bass: ";
String bout = "";
bout = b + bass;
String tout = "";
String t = "treble: ";
tout = t + treble;

Serial.print(bout);
Serial.print("\t");
Serial.println(tout);

bass = bass / 80;    // adjusts the sensitivity
treble = treble/200;

//bass
if (bass == 0) { // if the volume is 0 then turn off all leds
for(i = 0; i < 3; i++) {
digitalWrite(bassPins, LOW);
}
}
else {
for (i = 0; i < bass; i++) { // turn on the leds up to the volume level
digitalWrite(bassPins, HIGH);
}

for(i = i; i < 3; i++) {  // turn off the leds above the voltage level
digitalWrite(bassPins, LOW);
}
}

//treble
if (treble == 0) { // if the volume is 0 then turn off all leds
for(i = 0; i < 3; i++) {
digitalWrite(treblePins, LOW);
}
}
else {
for (i = 0; i < treble; i++) {// turn on the leds up to the volume level
digitalWrite(treblePins, HIGH);
}
for(i = i; i < 3; i++)  {// turn off the leds above the voltage level
digitalWrite(treblePins, LOW);
}
}
}

Even when there is nothing connected to A1 and A2, the serial monitor reads 1021 or 1023. Why? Is there a way to stop it?

Moreover, whenever the song ends or if I stop the song, all the LEDs are HIGH. I could not figure our why this will be the case.

Go Up

Please enter a valid email to subscribe