Guitar Envelope Follower Help

Hey Guys,

New to the forum and new to Arduino in general,
I just wanted to get some help or if someone can shoot me in the right direction if this project has already been made.

I'm using an Arduino nano.

What I'm after is essentially making an LED get brighter to the volume of a guitar.

So the analog side of it would be the guitar signal going through an op amp to boost it up to a signal that the Arduino can read a little better which i can map to 0 to 1023 in the analog input.

So when i strum the guitar it will be picked up by the Arduino Nano and output a PWM to an LED to the same velocity/voltage as the guitar, (So if i strum quieter it will be softer, and louder it will be brighter).

Is this something that already exists in code i can see and deconstruct/alter?

Its essentially a envelope follower, and seems like something that exists already i just can’t seem to find anything as I’m having trouble on getting this code started off.

Thanks for your help.

Hi, @se7en_costanza
These links may help.

Also google.

arduino nano sound level meter

There are tutorials and projects that will help too.
Your project is a good intro project.

Tom... :smiley: :+1: :coffee: :australia:

Hey @TomGeorge thanks for the guidance.

Here is the code ive got so far, but the problem is that because guitar is an AC signal it goes positive and negative due to the frequency of the signal, which turns the led on and off really fast, is there a way to make it just be on and fade off, not stutter off due to reading ac negative voltages.

Here is the code ive got so far:

const int envelopeInPin = A5;
const int envelopeOutPin = 6;
const int envelopeInPin2 = A4;
int envelopeVoltage;

void setup() {
pinMode(envelopeInPin, INPUT);
pinMode(envelopeOutPin, OUTPUT);
}

void loop() {
envelopeVoltage = map(analogRead(envelopeInPin), 0, 1023, 0, 255);
analogWrite(envelopeOutPin, envelopeVoltage);

}

Hi,
Can you post a copy of your circuit please?

Also,
To add code please click this link;

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Hello and good morning,
what do you expect than as posted at the start?

What I'm after is essentially making an LED get brighter to the volume of a guitar.

The brightness of the LED ist following the input voltage.

You actually need one of the breakout board with a microphone and amplifier on the board. Get one with an analog output based on volume and you are ready to go.
You seem to be using an electronic guitar signal output, which is not what you want, unless you rectify it and use a capacitor to sum the voltages to indicate volume.
Paul

Hey guys, Thanks for all the responses.

@TomGeorge Its just going through a non-inverting op amp, there isn't any rectifying, just a boost. Essentially this with capacitors on the inputs and outputs, using 9V supply (resistor divider to make 4.5v virtual GND).
https://lh3.googleusercontent.com/proxy/YbkgKGHwDhxcR6Jqk9lwCsJsHSF1EvyhknYIFK4EwCiWseXi9u4dntpqmg0JNDbBWbXvWmHXYIoCat3dWvLFNYn_K_Y0PIRqbu5e3bjTnjWxKMedctsWtIA-4ciYIn483wio0y4Aig

@paulpaulson Sorry i should correct, i did say voltage but i meant volume, a smooth ramping up and ramping down of the led when playing guitar based on volume.

@Paul_KD7HB I was hoping to do it without any breakout boards but using analog components on a breadboard. I'll try adding a rectifier circuit before hand, i was just hoping its possible in code.

Thanks so much guys, sorry for my newbieness..

You can "rectify" in your program - just track the highest vMax and lowest vMin values you read. The difference between them is the size (ie volume).
You will need to reset Vmax on the "negative " half cycle, and VMin on the positive half cycle
vAv is the average input - the reading you get with no input signal.

Having given it a bit of thought I'll not write the code for you - its not difficult, but a rather fun challenge.
Draw a sine wave and figure out how to measure its size.

Hi,
Google

arduino audio envelope detection

As you are only looking for volume, try resistor/capacitor on the output of the opamp, this will give a smoothed voltage following the peak amplitude.

In your circuit I assume you have gnd of your source connected the the gnd of the op-amp power supply and the arduino gnd.

Tom.... :smiley: :+1: :coffee: :australia:

You need a diode and capacitor to give peak amplitude and also a resistor in parallel with the capacitor so the capacitor discharges when the amplitude reduces. The product of resistance (in ohms) times the capacitance (in Farads) needs to be roughly 0.05 (that's seconds).

As subjective volume has a logarithmic relationship to acoustic sound pressure, I suggest trying if it's better if (in your code) you take the logarithm of the voltage from your peak detector (relative to the DC voltage of your signal earth) before feeding that to the PWM modulation of LED intensity.

Hey @johnerrington if i bias the analog input of the arduino with a voltage divider 10k resistors from 5v and gnd.
And if i map the input from 0, 1023, 0, 255.
When i am not playing guitar it will be at roughly 128, and when im playing with the highest positive voltage being 255, and the lowest negative voltage being 0 in arduino.

Would these be the steps to then rectify it? Im unsure what you mean by Vmax, Vmin, vAv
Can you expand a little further?

Thanks heaps for your advice :slightly_smiling_face:

Hi,

Yes rectify so you can have 0 to 1023 range.

Now no signal will be 0 and you can then use all 1023 steps of the ADC to scale your brightness.

You may need to do some scaling at the low end of the range as the LED brightness is not linear with 0 - 255 PWM.

Tom.. :smiley: :+1: :australia:

Audio amplifier , instead speaker LED, I am using that for a long time.

So the size of the wave is 255 - 0 = 255.

As the average input value with no input is "roughly" 512 you can VERY EASILY find the size of the signal.
Forget about mapping, work with the raw values as they have better resolution.

envelopeVoltage = analogRead(envelopeInPin);

For each reading

  • subtract 512. (envelopeVoltage is declared as a int so neg values will be OK)
    envelopeVoltage = envelopeVoltage - 512;
  • get rid of neg values - or any less than a threshold to allow for noise
    if (envelopeVoltage<5) {
    its the end of a cycle - so .. take the sum of the input values for this cycle and divide by the count;
    record the result as the signal size; then
    reset the count and the sum to start again.
    }
1 Like

Hey @johnerrington

This definitely is seeming for like what i'm after, and making a little bit more sense.
I'm just having trouble with what you mean by:

"take the sum of the input values for this cycle and divide by the count;
record the result as the signal size; then
reset the count and the sum to start again."

I'm still super new to Arduino but is that similar to the "smoothing" program in the examples sketches?

No; however there is a way to do it using that basic idea.

const int envelopeInPin = A5;
const int envelopeOutPin = 6;
const int envelopeInPin2 = A4;
float vol = 128;
int vout;
int sample;
int rate = 50; // controls the time between samples; a sample is 1 measurement of your incoming signal.

float filter = 0.01;  //you may need to play with this to get the results you want
float nfilter;

void setup() {
pinMode(envelopeInPin, INPUT);
pinMode(envelopeOutPin, OUTPUT);
nfilter = 1 - filter;
}

void loop() {
sample = analogRead(envelopeInPin);
sample -= 512;
if (sample < 0) { sample = -sample };   //or sample = abs(sample);
//sample will now be in the range 0 - 512; smooth it
vol = (vol * nfilter) + (sample * filter);  // in one instruction!
vout = int ( vol / 2);  //change the range to be between 0 and 255
analogWrite(envelopeOutPin, vout);
delayMicroseconds(rate);  
}

I havent tried it out so you may need to correct the odd typo.

1 Like

Hey @johnerrington
Thank you, this is almost perfect, i had to do a few changes to match the preamp i had, but its only values. And setting a min and max threshold.

const int envelopeInPin = A5;
const int envelopeOutPin = 9;
const int envelopeInPin2 = A4;
float vol = 128;
int vout;
int sample;
int rate = 50;
float filter = 0.008; 

void setup() {
pinMode(envelopeInPin, INPUT);
pinMode(envelopeOutPin, OUTPUT);
nfilter = 1 - filter;

TCCR1B = TCCR1B & 0b11111000 | 0x01; //pins 9/10 pwm to 31.25khz
}

void loop() {
sample = analogRead(envelopeInPin);
sample -= 512;
if (sample < 0) { sample = -sample; }; 
vol = (vol * nfilter) + (sample * filter);
vout = vol; 

if(vout <= 3) {
  vout = 0;
}

if(vout >= 255) {
  vout = 255;
}

analogWrite(envelopeOutPin, vout);
//delayMicroseconds(rate);  
}

But after seeing how this is done I understand the process so much more. Thanks so much.