PDA

View Full Version : Envelope detector and VCA with Teensy's Audio library



RTPNaskers
09-03-2015, 11:26 AM
Hi there!

I've been trying to build this thing for a while: an envelope detector from the signal of a bass guitar (or whatever instrument for that matter) to drive the envelope of a synth.
My first attempt, which actually work, used an analog envelope detector circuit so what I was inputting to the MCU was the envelope, which at that stage could be seen as a control signal more than an audio one.
For the sake of simplicity and also flexibility at some point, I'd like to input the pre-amplified pickup signal and then digitally get its envelope. Once I have it, it will be used as the envelope for a synth, firstly to drive the amplitude in some sort of (digital) VCA and also for the filter cutoff frequency. Pretty commom as you can see.
So, any suggestions with that? I'm using Teensy's library, cause I think it's the best and also cause the instrument I'm building it's already using it. Which diagram you'll suggest?

Thanx a lot!

PaulStoffregen
09-03-2015, 12:25 PM
Well, the library already has a VCA object (http://www.pjrc.com/teensy/gui/?info=AudioEffectMultiply) and a "voltage controlled" filter (http://www.pjrc.com/teensy/gui/?info=AudioFilterStateVariable), so the only part missing here is the envelope follower to get the "voltage" control signal.

Extracting the envelope should be pretty simple, as creating audio lib objects goes. Do you suppose this feature would be useful to more people? I might take a look... but to even begin working on this, I'd need a few pretty good audio clips for testing it.

RTPNaskers
09-03-2015, 01:37 PM
Hi Paul, thanx for your quick reply!

I'll take your advice and I will use "multiply" to act as VCA, until now I was doing that by driving the amplitude variable of the waveform with the analog reading I was inputting from the envelope. Your suggestion makes more sense.

At least it will be useful for me, and I think that having an object to get envelopes can be used in a lot of situations that don't only imply audio synthesis.
I really like trying to help here: I can record some audio samples and/or help with the audio lib object development if I can get some advice on how to set and IDE to do so!

Thanx again, you rock!

PaulStoffregen
09-03-2015, 02:02 PM
I really like trying to help here: I can record some audio samples and/or help with the audio lib object development if I can get some advice on how to set and IDE to do so!


Use File > Examples > Audio > Recorder

RTPNaskers
09-03-2015, 03:07 PM
Hmmm, I got the audio shield from last year's black friday, so I can record those. I'll give it a go trying to input the bass signal after some pre-amp.
Cheers!

RTPNaskers
09-30-2015, 10:22 AM
Hey!
Been a while since I last posted here.
In this time, I've been messing around the audio library and the audio shield just to corroborate how great they are.
I've tried a couple things with the codec and the effects and the sd card playback too.
Also managed to wire the thing up so I can record samples onto the sd card and yesterday, finally recorded the bass thing.
I modified the recorder sketch for it to work with just one push button (I don't have may of those around lately) and actually recorded and played back a few seconds of the bass playing after an audio preamp.
I've been trying, not hardly, to read the .raw data in Matlab without luck so I can't tell if everything went fine.
I'm attaching it (via Drive) https://drive.google.com/file/d/0BwuJ8dDZ7C_uYlh4WFVMbGhFdU0/view?usp=sharing
Cheers!

nagual
10-14-2015, 10:03 AM
to get the envelope, isn't it basically a low pass filter, or in other words, reading one (amplitude) sample at an interval of (x) and averaging it with an arbitrary interval of samples (then convert to absolute value) and sending that to the 'envelope' variable that you require? Is it more complicated than that?

Theremingenieur
10-14-2015, 10:09 AM
Easiest way is to take the absolute value of each sample and the doing a moving average with a more or less sophisticated LPF

RTPNaskers
10-14-2015, 10:14 AM
yeap, I supose so, actually the analog circuitry that I was using was doing that; two diodes were rectifying the wave so every value was "absolute" and a single RC net was acting as an LPF with low frequency cutoff frequency. Guess that the operation should be kinda similar in the digital domain!

RTPNaskers
01-23-2016, 04:50 PM
Hi!
I need to get this topic back to life cause the project where i will be using the audio object is near of a deadline!

During this time I've been experimenting with the audio library and even trying to understand how to write new audio objects for it, anyways still don't get the whole thing so i need some advice/help.

What I've been able to do is computing a similar functionality of the one I need but in Matlab: a simple envelope follower that does what some of you folks suggested; getting the absolute value of the signal and then low pass filtering it. The function works well enough and at least I think it will help me to design the object aslong as i've learnt which cutoff frequency on the lowpass filtering gives a more edgy envelope and also the coeficients for a biquad filter.

Here's a link to the matlab function and the input and output files.
https://drive.google.com/folderview?id=0B9UQzZr4Pin_Q2F1cERaLWVCVHc&usp=sharing

I've used an slice of the same audio file I uploaded which was recorded with teensy's audio shield (there's some noises, that I guess that have something to do with the SD writing process cause I don't hear them when I just bypass the audio through the shield...)

Also some plots of the signal process:

Original signal:

6182

Extracted envelope:

6183

Processed signal, a 110Hz sine wave envelope by the original signal:

6184


So, if anyone can give some advice it'll be really nice, I'm thinking that the most straightforward thing to do will be modyfing the biquad filter object and make it filter with the coeficients I got and just before that process getting the absolute value of the signal, is that right? Will it work to just pick up the input block samples and abs(them) in the same loop they're beeing filtered or should I abs the whole block and then filter it?

Thanks a lot!

RTPNaskers
01-28-2016, 04:03 PM
Ouch, nobody?
I've been trying couple things:

- Using analyzePeak/RMS to feed it's reading to the gain of the oscillator: it controls its amplitued but he variations introduce a lot of harshness, not good.

- Using the output of a LowPass (both biquad and variable) with a cutoff at 15-30Hz to control the VCA of the oscilloscope, a ring modulator effect occured, interesting but not what I was looking for.

- The same above but trying to abs(values) inside the filtering objects, actually I'm not sure that I modified the correct line (NEED HELP HERE), thought it compiled if there was a difference I coulnd't appreciate it. Here's what I modified inside biquad.cpp (for instance)

do {
in2 = abs(*data); // Does this make sense at all?
sum = signed_multiply_accumulate_32x16b(sum, b0, in2);
sum = signed_multiply_accumulate_32x16t(sum, b1, bprev);
sum = signed_multiply_accumulate_32x16b(sum, b2, bprev);
sum = signed_multiply_accumulate_32x16t(sum, a1, aprev);
sum = signed_multiply_accumulate_32x16b(sum, a2, aprev);
out2 = signed_saturate_rshift(sum, 16, 14);
sum &= 0x3FFF;
sum = signed_multiply_accumulate_32x16t(sum, b0, in2);
sum = signed_multiply_accumulate_32x16b(sum, b1, in2);
sum = signed_multiply_accumulate_32x16t(sum, b2, bprev);
sum = signed_multiply_accumulate_32x16b(sum, a1, out2);
sum = signed_multiply_accumulate_32x16t(sum, a2, aprev);
bprev = in2;
aprev = pack_16b_16b(
signed_saturate_rshift(sum, 16, 14), out2);
sum &= 0x3FFF;
bprev = in2;
*data++ = aprev;
} while (data < end);

Maybe that change in the code doesn't make anything at all... this code feels kinda low-level-ish to me and I'm pretty lost when I read it, let alone hack it propperly!
Once again HELP!!!

Salut!

PaulStoffregen
01-28-2016, 07:06 PM
Try making an object which only does the absolute value. That should be really simple code. You can just feed its output to an already-working filter. That'll be a *lot* easier than messing with this complicated biquad filter code!

One really important detail is the pointer and your variables need to be int16_t type. Many of the objects in the library use uint32_t, because they process 2 samples at the same time. Doing 2 at once can speed things up by at most 2X, but it makes the code 10X harder to understand and edit.

Keep it simple. The code should probably look something like this:



int16_t *p, *end;
audio_block_t *block;

block = receiveReadOnly(0);
if (block == NULL) return;

p = block->data;
end = p + AUDIO_BLOCK_SAMPLES;
while (p < end) {
int16_t s = *p;
if (s < 0) {
if (s == -32768) {
s = 32767;
} else {
s *= -1;
}
*p = s;
}
p++;
}
transmit(block);
release(block);

RTPNaskers
01-28-2016, 08:01 PM
Hi Paul,

I'm taking you're advice and will create the abs object and see (if I manage to get it working) if it does the trick!

Thanks a lot!

RTPNaskers
01-28-2016, 11:12 PM
YO!

The abs object works! I copy/paste Paul's code in the update function of a new object (and added it into the Audio.h also), insert it in a simple patch and voilà! it does the effect of a rectifier, doubling pitch into waveforms and a harshy uppitching on the mic.
Nice!
Tomorrow I'll plug it into a LPF and will see.
By the way, which filter object do you think will do better the job of a lowpass filtering around 15-30 Hz?

Thanks again!

PaulStoffregen
01-29-2016, 02:16 PM
The state variable filter is best for low corner frequencies.

RTPNaskers
01-31-2016, 05:14 PM
Yay!
It works pretty well!
No noise artifacts caused by the envelope, responds as expected and it can be fed working also good to the filter control input of a second filter to perform an envelope controlled filter!
Paul, you are the man!
Thanks a lot!

RTPNaskers
02-11-2016, 07:57 PM
Hi there!

As a conclusion to this thread I wanted post a little video playing the instrument I build thanks to Paul's Advice: the unoString. Some nice guy shot this video at this past weekend Maker's Faire in Barcelona (yeah, that was my deadline). Also in the video in second term appear two of my other instruments, both Teensy powered, of course!

https://www.youtube.com/watch?v=nwuWPWI6WbQ

Thanks again for your help Paul, now the unoString, although still needs a lot of enhancements, works way better and has a nice wide dynamic range thanks to the envelope follower connected to the VCA and the VCF!

Long life to Teensy!

Salut!

skwelker
04-13-2017, 11:31 PM
Hello I am new to Teensy so please bare with me. I am working on a school project where we are taking a very low frequency amplified signal(about 50 Hz) that we are wanting to store onto an SD card. Before passing our signal into an ADC, we want to capture the envelope of the signal. Is it possible to use this same method with the absolute value code to do this?

Thanks,
Samuel W.

RTPNaskers
04-14-2017, 02:15 PM
Hi Samuel,

Sure you can do that, with the abs object and a low pass filter it should output the envelope as you need, I can send you the .h and .cpp of the abs object if you need even giving you any further help with the program also.

Salut!

skwelker
04-14-2017, 04:01 PM
I am very new to teensy so I have a couple of questions. Can you please send me the full code that you used to implement the abs object and the LPF for the envelope detector? I downloaded the Teensyduino software and I don't know if I need to use the .h or .cpp file to run it but whichever file format would work better for Teensyduino I would prefer. Additionally, do you happen to know the detectable input frequency range of the Teensy off the top of your head?

Thanks,
Samuel Welker

RTPNaskers
04-14-2017, 08:02 PM
Hi Sam,

First of all, for being able to use teensy's audiolibrary you need to use a Teensy 3.x board (from 3.1 to 3.6), which are you using?.
Then, for inputting audio you can use different sources, ranging from the analog converters on the teensy using "AudioInputAnalog adc1(analogInputPinNumber);" to the USB sending audio data from the computer where you have the teensy attached amongst others (more info at: https://www.pjrc.com/teensy/gui/?info=AudioInputAnalog)
Which are you planning to use? I need to know this to help you writing the code of the sketch. The frequency range of the input in fact will depend on which input you use, I think that if your signal is a 50Hz sine, any of them will work with no problem though.
I'm attaching the code of the abs object, both .h and .cpp (you need both to declare and implement a class in C++ following teensy's audiolibrary framework). Also you'll need to add a line to the Audio.h file that you already shoud have in the Audio library folder for it to call the .h file of the new class. Anyways don't bother about that cause I'm attaching the modified Audio.h file, so you'll only need to put these three files (Audio.h, effect_abs.h and effect_abs.cpp) in the Audio library folder (located at ..Arduino/libraries/Audio/) replacing the Audio.h that you already have. For the low pass filter I simply used AudioFilterStateVariable that's already on the teensy library and Paul recommended me to use in this same thread.
One question that comes to my mind is, what do you want to do with the envelope you detect? Write it onto a file? The signal that you want to detect has a certain envelope that you want to measure and log? tell me more too! :-)
So, hope this helps and whenever you explain which audio input do you want to use I can help you with the code in the sketch.
Salut!

skwelker
04-14-2017, 08:40 PM
I am currently using the Teensy 3.6 board. I am planning on using the analog inputs on the teensy for the input signal. Do you think that the teensy will be able to handle something as high as 1MHz freq? I wasn't able to find anything in the data sheet that talked about detectable freq range. We are attempting to use the Teensy to detect human breathing patterns, so we are planning on feeding the input signals envelope into the Teensy's built in ADCs and then storing that data onto an SD card using the Teensy 3.6 micro SD dock. Thank you so much for all of your help, let me know if you have any other questions that I could answer for you to help me better.

Thanks,
Samuel W.

RTPNaskers
04-14-2017, 11:50 PM
1MHz is much (much) higher than Teensy's (or most of microcontrollers) onboard ADCs can handle. Actually the audio library (being an audio library) is meant to work with audio signals which can go as high as 20kHz so the sampling frequency suffices to be as the typical 44100Hz or as much as 192kHz for higher resolution codecs. Anyways, I don't think that this can be any problem cause I don't really think that you need to sample signals near those 1MHz rates when you're trying to sample the outcome signal of a breathe detector. I'm pretty sure that anything in the audio range will be more than enough. Which sensor/transducer are you using to capture the breathe? The datasheet should say which is the bandwidth of the signal they give and I suspect that is nothing close to 1MHz...
In the other hand, something that is a little confusing to me is that you say you want feed the signal's envelope into the Teensy's ADC, then... do you mean you plan to, somehow (analog circuitry I guess), get the envelope of the signal in the analog domain and then convert it to digital? If so, you will get the envelope of the signal right into the ADC so there will be no need to detect the envelope once more digitally... OR, do you mean that you want to feed the signal into the ADC and then detect its envelope in the digital domain (using Teensy's libraries) and then storing it into the SD?

sam
04-15-2017, 07:57 PM
so you'll only need to put these three files (Audio.h, effect_abs.h and effect_abs.cpp) in the Audio library folder (located at ..Arduino/libraries/Audio/)

I am eager to try out your envelope follower. I downloaded the zip however the files included are not effect_abs.h and effect_abs.cpp, but rather effect_envelope.cpp and effect_envelope.h. Are these the right files? Also, could you post a simple example sketch on how to use the envelope follower? thanks!!

RTPNaskers
04-15-2017, 08:33 PM
Ooops, my bad! You're right those are not the files, sorry! I'm attaching the right ones this time!
Concerning the example, I'll send tomorrow allright?

Salut!

sam
04-15-2017, 08:38 PM
sounds good, thanks so much!!

sam
04-15-2017, 09:19 PM
So I think I understand how it works, the Absolute value acts like an effect, it take the input of an audio stream and outputs the absolute value aka the envelope? So I take the output of the ABS and send that into the control input of a state variable filter?

RTPNaskers
04-16-2017, 06:45 PM
Well, not exactly. After you obtain the absolute value of the signal, which is called a rectified signal, you need to low pass filter it out in order to make it a signal that evolves following the envelope of the original signal. Then you can use the signal as a control signal as you pointed out.
https://en.wikipedia.org/wiki/Envelope_detector <- this is the equivalent in the analog domain, diode rectifies and capacitor lowpassfilters.

10313
Here's the arduino sketch that you can use as a test. It uses de signal you will input in the analog input of the teensy, gets its envelope and uses it to modulate the amplitude of a sine wave. What you should listen is the volume of the sine wave to increase as the signal volume of the breathe detector increases.

Hope it helps, and get back to me for any doubts or help you need.

Salut!

sam
04-17-2017, 03:18 AM
wow, I got it working!! Now I have a sweeet envelope controlled filter, and it sounds good! I appreciate you taking the time to help me out. Now my mind is exploding with all the possibilities of envelope control...

WMXZ
04-17-2017, 02:15 PM
Well, not exactly. After you obtain the absolute value of the signal, which is called a rectified signal, you need to low pass filter it out in order to make it a signal that evolves following the envelope of the original signal. Then you can use the signal as a control signal as you pointed out.
https://en.wikipedia.org/wiki/Envelope_detector <- this is the equivalent in the analog domain, diode rectifies and capacitor lowpassfilters.



which gives you not the envelope, but an approximation to the rms value.
Wikipedia is not completely correct!
See figure where the link is to analytic signal.

RTPNaskers
04-18-2017, 08:05 AM
Glad to hear that it helped you! Which breathe sensor are you using? I've always wanted to create a trumpet-like instrument but never known of suitable sensors... You think yours can serve that purpose?
WMXZ, dunno buddy, I call that envelope an it works for me to generate the envelope of another signal... I just linked to wikipedia for a quick-dirty illustration of the concept!

gfvalvo
04-18-2017, 05:13 PM
I'm thinking you may want to add the '#include "effect_abs.h"' statement explicitly to your application code rather than putting it in Audio.h. If PRJC updates the library and creates a new Audio.h, then your modification will be lost.

sam
04-19-2017, 08:38 AM
Glad to hear that it helped you! Which breathe sensor are you using? I've always wanted to create a trumpet-like instrument but never known of suitable sensors... You think yours can serve that purpose?
WMXZ, dunno buddy, I call that envelope an it works for me to generate the envelope of another signal... I just linked to wikipedia for a quick-dirty illustration of the concept!

Hey! I'm using the envelope to control the bandpass frequency of the state variable filter. So it's like an auto wah. I use the effect on the synth sounds generated using the library.

RTPNaskers
04-19-2017, 09:41 AM
Hey! I'm using the envelope to control the bandpass frequency of the state variable filter. So it's like an auto wah. I use the effect on the synth sounds generated using the library.

Nice! And which is the sensor you are using to detect the breathe?

RTPNaskers
04-19-2017, 09:44 AM
I'm thinking you may want to add the '#include "effect_abs.h"' statement explicitly to your application code rather than putting it in Audio.h. If PRJC updates the library and creates a new Audio.h, then your modification will be lost.

Good point, it actually happened to me once, but losing the Audio.h wasn't the most annoying thing but losing the .h and .cpp of the new class code which can be erased when you update the teensyduino. Can those be placed in another folder or they need to be placed in the Audio folder in order to fetch properly the dependencies like AudioStream?

gfvalvo
04-20-2017, 12:08 PM
You can put your .cpp and .h files for your custom audio classes in a separate folder in your 'libraries' folder or in the same folder as your application .ino file. The former makes more sense as it allows you to use your custom classes in multiple applications.

Delete your custom Audio.h file. In your custom .cpp and/or .h files files, include the classes you need from the Audio library. For example:


#include "AudioStream.h"

sam
04-21-2017, 07:51 PM
Nice! And which is the sensor you are using to detect the breathe?

Hey! Not totally sure what you mean. I'm not using any sensors or any external signals. The synth sound are generated inernally by the Teensy, and I'm using that to create the envelope and then using the envelope to control the state variable filter applied to the same signal I extracted the envelope from. Hopen that makes sense!

RTPNaskers
04-24-2017, 08:17 AM
Nevermind, I just thought that as long as you wanted to monitor human breath patterns you were using some sort of sensor to do so.

sam
04-26-2017, 01:24 AM
Nevermind, I just thought that as long as you wanted to monitor human breath patterns you were using some sort of sensor to do so.

I understand! There are two Sams!! You are referring to username skwelker, whose real name is Sam, who wants to monitor human breath patterns.
I am username Sam, my real name is Sam, and I want to use the envelope filter to make funky synth sounds. Now it all makes sense!!

RTPNaskers
04-26-2017, 10:37 AM
True that, okay!

Kirazvora
06-26-2018, 01:35 AM
Well, not exactly. After you obtain the absolute value of the signal, which is called a rectified signal, you need to low pass filter it out in order to make it a signal that evolves following the envelope of the original signal. Then you can use the signal as a control signal as you pointed out.
https://en.wikipedia.org/wiki/Envelope_detector <- this is the equivalent in the analog domain, diode rectifies and capacitor lowpassfilters.

10313
Here's the arduino sketch that you can use as a test. It uses de signal you will input in the analog input of the teensy, gets its envelope and uses it to modulate the amplitude of a sine wave. What you should listen is the volume of the sine wave to increase as the signal volume of the breathe detector increases.

Hope it helps, and get back to me for any doubts or help you need.

Salut!

RTPNaskers can you help me use your Envelope with midi cc? I thinking do it in steps like that: adc1(A2) go to abs go to filter1 go to usbMIDI CC1. But I'm not sure how to get output from filter, and use it to generating CC, and what I need else to connect to the input 1 filter? can I connect real potentiometer to the input 1 for setting freq filter?

RTPNaskers
06-28-2018, 09:45 AM
Hi Kirazvora!

I think that what you want to do is definitely possible. Your guess is right: you need to get the envelope with the abs and then the filter and then output this from the audio system to the sketch so you can put these values into a variable that is sent with usbMDI CC1. To do so input and output data from the sketch to the audio system and back again to the sketch I'm pretty sure you need to use AudioPlayQueue and AudioRecordQueue respectively. I haven't done so yet and it looks you have to deal with buffers and other stuff that might be tricky but I think that's the way to go. If needed I can try to implement and sketch with these so I learn myself how to use them!

Salut!

Kirazvora
06-28-2018, 04:56 PM
Hi Kirazvora!

I think that what you want to do is definitely possible. Your guess is right: you need to get the envelope with the abs and then the filter and then output this from the audio system to the sketch so you can put these values into a variable that is sent with usbMDI CC1. To do so input and output data from the sketch to the audio system and back again to the sketch I'm pretty sure you need to use AudioPlayQueue and AudioRecordQueue respectively. I haven't done so yet and it looks you have to deal with buffers and other stuff that might be tricky but I think that's the way to go. If needed I can try to implement and sketch with these so I learn myself how to use them!

Salut!

Yeah it’s possible, I downloaded abs and I will try it. Abs in the working, is similarly to RMS object from Audio library? I guess that is. Will be great to see examples from you if you can. I trying get envelope follower with RMS object and I get some success, close to my needs. Still have some minor problems, when finishing up, I put my code on forum.

RTPNaskers
06-29-2018, 09:30 AM
Take in account that abs by itself won't do the envelope following, actually by itself does some sort of double-pitching to the signal as it rectifies it: kinda funny, but not what you're looking for. It has to work along with an LPF with a low cutoff frequency around 15Hz or less. I'm attaching the same example I uploaded for you to test the envelope following. When I get a little more of free time I'll try to do an example that can output the envelope from the audio system to the sketch.