Basic Envelope to Filter question

Status
Not open for further replies.

degu234

Active member
Hey everybody,

it´s my first post, so please be kind and patent.
I am working on a teensy eurorack module, based on the chord organ/radio station from music thing modular.
It will be a complete voice module with wavefolder, bitcrusher, delay and chord function.
There are just to things i want to eliminate before i publish the code to the community.

1.) I want to modulate the filter1frequency by the envelope1.
Envelope1 is feed by dc1. Amplitude is 1. the adsr signalthen goes to input1 of the filter

From what i´ve read, the input1 on the filter tracks automatically.
So a given cornerfreuqency + signalInput from 0-1 * Octaverange gets me the desired cutofffrequency.

Please correct me if i´m wrong.

But I also tried to calculate the output of the env1 to get the desired frequency, also with no success.

View attachment envelope-filterTest2.ino

Any help would be appreciated :)
Thanks in advance
Stefan
 
If you dont want to open the code:

//a trigger input (~10ms) at pin 9 should start an envelope1 which modulates the frequency
//input of the envelope is dc1, with an amplitude of 1
//my attempt to calculate directly -assuming the eg sends an envelope from 0-1- did not work!
//the attempt: filter1.frequency(65 * pow(2, (envelope1))); at line 67
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformDc dc1; //xy=78,879
AudioSynthWaveform waveform1; //xy=250,806
AudioEffectEnvelope envelope1; //xy=280,877
AudioFilterStateVariable filter1; //xy=532,777
AudioOutputAnalog dac1; //xy=837,756
AudioConnection patchCord1(dc1, envelope1);
AudioConnection patchCord2(waveform1, 0, filter1, 0);
AudioConnection patchCord3(envelope1, 0, filter1, 1);
AudioConnection patchCord4(filter1, 0, dac1, 0);
// GUItool: end automatically generated code


//Constants
const int triggerPin = 9; //Jack for TriggerIn at Pin 9
const int L5Pin = 11; // LED5 at Pin 11

int triggerState = 0; // Variable to save triggerstate

void setup() {
// put your setup code here, to run once:
AudioMemory(20);
waveform1.begin(WAVEFORM_SAWTOOTH);
waveform1.amplitude(1);
waveform1.frequency(220);
waveform1.pulseWidth(0.15);

filter1.frequency(65);
filter1.resonance(0);
filter1.octaveControl(5);

dc1.amplitude(1);

envelope1.delay(0);
envelope1.attack(20);
envelope1.hold(200);
envelope1.decay(5000);
envelope1.sustain(0.7);
envelope1.release(500);


pinMode(triggerPin, INPUT); //trigger is input
pinMode(L5Pin, OUTPUT); // Set LEDPin as output
}
void loop() {
triggerState = digitalRead(triggerPin); //read triggerPin and set as triggerState

if (triggerState == HIGH) //when tasterState is High
{
envelope1.noteOn(); //trigger envelope1 to start envelope
}
else {
envelope1.noteOff(); //end of gate, start release

}
digitalWrite(L5Pin, triggerState );
//filter1.frequency(65 * pow(2, (envelope1))); //i think it shoud work somekind of this
}
 
set your base frequency in code, eg: filter1.frequency(220); will set the corner frequency to 220hz, generally speaking I would set the filter frequency to be the same as the note frequency, that way the filter will track your oscillators. eg: waveform1.frequency(220); filter1.frequency(220); will match the filter frequency to the note frequency.

Then a signal at filter1, input1, will shift that frequency in relation to the base frequency by the amount defined in octaveControl.
With octaveControl set at 1, an envelope at input1 that goes from 0,00 - 1.00, will shift the frequency by one octave above the base frequency.
With octaveControl set at 2, an envelope at input1 that goes from 0,00 - 1.00, will shift the frequency by two octaves above the base frequency.

So waveform1.frequency(220); filter1.octaveControl(1); filter1.frequency(220); will result in the filter shifting from 220hz to 440hz during the attack stage of the envelope.
Setting the values to: waveform1.frequency(220); filter1.octaveControl(2); filter1.frequency(220); will result in the filter shifting from 220hz to 880hz during the attack stage of the envelope (two octaves).

Similarly, waveform1.frequency(110); filter1.octaveControl(2); filter1.frequency(110); will result in the filter shifting from 110hz to 440hz (110hz base frequency + frequency shift from input1)

I hope that helps to clarify :)
 
Last edited:
I doubt if this would work:

filter1.frequency(65 * pow(2, (envelope1))); //i think it shoud work somekind of this

As far as I know, you cannot just put envelope1 into filter frequency like this!
 
set your base frequency in code, eg: filter1.frequency(220); will set the corner frequency to 220hz, generally speaking I would set the filter frequency to be the same as the note frequency, that way the filter will track your oscillators. eg: waveform1.frequency(220); filter1.frequency(220); will match the filter frequency to the note frequency.

Then a signal at filter1, input1, will shift that frequency in relation to the base frequency by the amount defined in octaveControl.
With octaveControl set at 1, an envelope at input1 that goes from 0,00 - 1.00, will shift the frequency by one octave above the base frequency.
With octaveControl set at 2, an envelope at input1 that goes from 0,00 - 1.00, will shift the frequency by two octaves above the base frequency.

So waveform1.frequency(220); filter1.octaveControl(1); filter1.frequency(220); will result in the filter shifting from 220hz to 440hz during the attack stage of the envelope.
Setting the values to: waveform1.frequency(220); filter1.octaveControl(2); filter1.frequency(220); will result in the filter shifting from 220hz to 880hz during the attack stage of the envelope (two octaves).

Similarly, waveform1.frequency(110); filter1.octaveControl(2); filter1.frequency(110); will result in the filter shifting from 110hz to 440hz (110hz base frequency + frequency shift from input1)

I hope that helps to clarify :)

That´s all? Nothing more? Ok i will try that at home. Thank you so far :)
 
EDIT: Cause it´s not unimportent, as the Filter will be the only control over the "volume" the cornerFrequency should go as low as possible.
With an external Control Voltage it worked flawlessly :)

Hey,
I tried to do it as you mentioned. But i dont get it to work. I know there is one setting or so.
I set:

66 AudioConnection patchCord5(dc2, envelope1);
68 AudioConnection patchCord7(envelope1, 0, filter1, 1);

86 const int triggerPin = 9;
99 int triggerState = 0;

124 void setup ()

157 envelope1.delay(0);
158 envelope1.attack(20);
159 envelope1.hold(0);
160 envelope1.decay(5000);
161 envelope1.sustain(0.7);
162 envelope1.release(500);

164 dc2.amplitude(1);

167 filter1.frequency(110);
168 filter1.resonance(0);
169 filter1.octaveControl(5);

211 pinMode(triggerPin, INPUT);

224 void loop()

248 triggerState = digitalRead(triggerPin);

250 if (triggerState == HIGH) {
251 envelope1.noteOn();
}
253 else {
254 envelope1.noteOff();
}
256 digitalWrite(L5Pin, triggerState );

The L5Pin Led shows me the correct State, but not the output.
The filter lets the sound just pass thru, no modulation from the envelope :/
as you can see this is just an excerpt of the code
the full code can be found here:
https://pastebin.com/pSk1MmrA
or maybe i have something completly wrong :/
If you could take a moment to look at my sketch would be really helpful for me :)
TIA
 
before you do anything else, I suggest you make the following modifications to your code.

pinMode(triggerPin, INPUT); //trigger is input
pinMode(L5Pin, OUTPUT); // Set LEDPin as output
}
void loop() {
triggerState = digitalRead(triggerPin); //read triggerPin and set as triggerState

if (triggerState == HIGH) //when tasterState is High
{
if (triggerlock == 0)
{
triggerlock == 1; //prevents envelope from being constantly re-triggered while note is held down, you only want the envelope to be triggered once per trigger.
envelope1.noteOn(); //trigger envelope1 to start envelope
}
}
else
{
if (triggerlock == 1)
}
triggerlock == 0; // locks the envelope1.noteOff() command from being continuously sent when there is no note, only one note off command is sent.
envelope1.noteOff(); //end of gate, start release
}
}
digitalWrite(L5Pin, triggerState );
//filter1.frequency(notefrequency); // use whatever variable you use to set note frequency
}

because you have not locked the envelope on and off commands from re-triggering I suspect that what is happening is that your program is reading triggerpin, turning the envelope on, then looping around again. and because triggerpin is still high, the envelope is being sent a second start command, and repeating several times per second.
This is probably why the envelope is just turning on and then staying on, because each envelope on command is retriggering the envelope again, preventing it from reaching the decay / sustain stages.

The input1 pin on the envelope generator automatically performs expotential conversion of the control signals, so no need to do those conversions in code.

One idea I've been meaning to try out but not got round to yet is to use the DC control to apply external voltages to the filter etc (I don't have external cv's on my modules yet)

something like:

modsignal1 = analogRead(A1);
dc2.amplitude(modsignal1 / 1024);

then feed the dc2 output to input 1 of the filter via a mixer.
Having a mixer between the envelope / mod signals, enables you to mix those signals to get the right balance of envelope and other mod signals.

BTW is there a reason for having two filters in series like that? seems a bit overkill to me.
 
Hello, thank you for your time.

Thank you for the triggerlock, i will implement this. But my problem is, that the modulation of the envelope isn´t starting at all.
I had a small test programm, where the filtermodulation (from the envelope via "triggerIn") really worked.
(From another thread, where paul showed the envelope on a WaveformMod)
I noticed the retriggering of the envelope. (I mostly send trigger impulses ~10ms, so the retrigger-thing didn´t bothered me to much)
The set up for D A H D S R stayed the same. So my thought is that the envelope isn´t starting in my code,
though the trigger LED L5 showns differently or the envelope is not set up correctly in my code.

Analog read for DC is not an option, as i want to really just trigger the envelope. This would give me a potentially CV input
A line above in my complete code there is cv control over the filter commented ;)

Filter2 is to control a filter cutoff via a knob. There are some parts not necessiary like mixer 2 & 5, but hey its my first program, i layed out the "modules" as i would have done it in Eurorack :D
 
You definitely do not need the second filter then, there are several much more efficient ways of doing this.
Filter control is best achieved by using a structure like the one below:

Screenshot 2021-09-10 at 09.41.46.png

this is actually much closer to how a modular filter is used in a modular rig.

the mixer allows all your control signals to be added together to create your final modulation signal for input1 on the filter. in cv terms the control signals would all be linear 1v per octave, the filter will convert the linear voltages to expotential ones for you (no need to use pow() on this input).

to implement a frequency knob you can use:

modsignal1 = analogRead(A1);
dc1.amplitude(modsignal1 / 128); // dividing mod signal by 128 gives a float from 0-8 which when converted by input1 of the filter, should give eight octaves of frequency control.

Or, to do it completely in code:

float notefreq = 110;
float modsignal1 = analogRead(A1);
float filtfreq = pow((modsignal1 / 128),2); // dividing mod signal by 128 gives a float from 0-8 which when converted by pow(), should give eight octaves of frequency control.
filter1.frequency(notefreq * filtfreq); //this should give a full range of eight octaves of filter control, while still maintaining keyboard tracking.

I just noticed that you have the pow() parameters backwards in your code, it should be the value you are converting first, then the power ratio (in this case 2) after the comma. eg pow(value,2).

I would suggest trying this out as a seperate mini project to get a better idea of how it works, then try to incorporate it into your larger project.
 
Thanks again for your time.

As already mentioned, its my first code ever, so there will be alot of things to do better.
Also i tried to work with one filter, but i didn´t liked it for my purposes.
Funny about the pow() as i read several times, because i was unsure how to use the function, and i used the clarification from arduino.cc
Unlike many others, idont need filter tracking. The env just need to go up and down to increase and decrease the "volume" Like a lowpassgate.

But back to the envelope problem, where you able to find a mistake in my code snippets?
 
Thanks again for your time.

As already mentioned, its my first code ever, so there will be alot of things to do better.
Also i tried to work with one filter, but i didn´t liked it for my purposes.
Funny about the pow() as i read several times, because i was unsure how to use the function, and i used the clarification from arduino.cc
Unlike many others, idont need filter tracking. The env just need to go up and down to increase and decrease the "volume" Like a lowpassgate.

But back to the envelope problem, where you able to find a mistake in my code snippets?

Don't worry I was not criticising, just trying to help you spot mistakes in the code, I realise how confusing it can be for a beginner. The pow() function is definitely pow(value,2), I can promise you that :)

I think I understand what you are trying to achieve now, had I realised you were just after creating an LPG I would have given different advice, but no worries, I think I'm with you now.

If you are certain you need 2 filters then I would suggest a setup like this:

Screenshot 2021-09-10 at 12.03.43.png

You can alter the value of dc1 to change the amount the filter opens up by, so a value of 0.00 on dc1 would produce no sound at the output, a value of 1.00 would produce the full 5 octaves of filter shift

However, for a true LPG result I'd replace the second filter with an envelope to shape the sound, like this:

Screenshot 2021-09-10 at 12.08.14.png

in this version, you would have to send the same ADSR settings to both envelopes when you adjust the settings, and trigger them simultaneously, which I'm sure you can do easily enough.
again the dc1 would control filter opening.

LPG's, because of the way they work are both a filter and voltage controlled amp at the same time, the volume does not just drop due to filtering, but due to a combination of filtering and volume control. The basic circuit behind an LPG is actually a simple vca controlled by a vactrol. this was later modified by adding some capacitors and resistors to add filtration to the mix, ie the sound would be additionally filtered as it was volume controlled. so filtering alone will not produce a true LPG effect.

TBH there are a few issues with the audio library in terms of utility, for example the lack of a seperate VCA, which means that you cannot use the vca in alternate ways and the fact that you have to run two envelopes - one for the filter and one for the 'vca' which is wasteful in terms of code.
 
Hey, yeah a real lpg is a vca and lpf, but i really like the sound how it sounds right now.
My only problem is, that the envelope seems to not start with a gate in.
"and trigger them simultaneously, which I'm sure you can do easily enough." this is exactly my problem, i cant get the envelope to work in this situation. (Envelope1 problem, envelope2 no problem) :D
If i put it right into the audio path, like the envelope is supposed to be, the envelope and shaping of the audio is working, but just not in my case, where i want to send this adsr signal to my filter.
Somehow i´m to stupid for the envelope block :/
 
Hey, yeah a real lpg is a vca and lpf, but i really like the sound how it sounds right now.
My only problem is, that the envelope seems to not start with a gate in.
"and trigger them simultaneously, which I'm sure you can do easily enough." this is exactly my problem, i cant get the envelope to work in this situation. (Envelope1 problem, envelope2 no problem) :D
If i put it right into the audio path, like the envelope is supposed to be, the envelope and shaping of the audio is working, but just not in my case, where i want to send this adsr signal to my filter.
Somehow i´m to stupid for the envelope block :/

As far as I can see there is no reason for the envelope not triggering, except for possibly the timing. Coming back to the triggerlock I suggested earlier, I'd implement that first to see what happens.
But I'm wondering now if the 10ms trigger length you mentioned is too short.
If you think about it, your attack is set to 20ms, and you are going into the envelope1.noteOff() stage after 10ms. The envelope is switching off before it has even had a chance to complete the attack stage!

implementing the triggerlock, and making the trigger length longer might be the solution you need!
 
Yes i will try the triggerlock, as i will need it in many other projects.
With the times yes you are true, but so far i tried also gatesignals (+10ms) which also brought no luck.
I will call back with a video, if that will help :)
Thank you so far Graham :)
 
So with your help the envelope modulates the filter, BUT
If I push the Gate the sound becomes dull (setted corner freq)
if i release the gate, the envelope starts the sound becomes brighter
and stays bright. Its going audible thru attack decay sustain, but awaits a noteOff signal which

here is my copied code, the led states the correct triggerState
void loop() {
int triggerlock;
if (triggerState == HIGH) //when tasterState is High
{
if (triggerlock == 0)
{
triggerlock == 1; //prevents envelope from being constantly re-triggered while note is held down, you only want the envelope to be triggered once per trigger.
envelope1.noteOn(); //trigger envelope1 to start envelope
}
}
else
{
if (triggerlock == 1)
{
triggerlock == 0; // locks the envelope1.noteOff() command from being continuously sent when there is no note, only one note off command is sent.
envelope1.noteOff(); //end of gate, start release
}
}
digitalWrite(L5Pin, triggerState );
}
 
So with your help the envelope modulates the filter, BUT
If I push the Gate the sound becomes dull (setted corner freq)
if i release the gate, the envelope starts the sound becomes brighter
and stays bright. Its going audible thru attack decay sustain, but awaits a noteOff signal which

here is my copied code, the led states the correct triggerState
void loop() {
int triggerlock;
if (triggerState == HIGH) //when tasterState is High
{
if (triggerlock == 0)
{
triggerlock == 1; //prevents envelope from being constantly re-triggered while note is held down, you only want the envelope to be triggered once per trigger.
envelope1.noteOn(); //trigger envelope1 to start envelope
}
}
else
{
if (triggerlock == 1)
{
triggerlock == 0; // locks the envelope1.noteOff() command from being continuously sent when there is no note, only one note off command is sent.
envelope1.noteOff(); //end of gate, start release
}
}
digitalWrite(L5Pin, triggerState );
}

Hmm, I cannot see any faults in that code, but from your description, that sounds as if the envelope is being inverted somewhere along the line.
ie the attack phase is closing the filter, then as the envelope decays, its slowly reopening the filter.
I think you need to check any variables / functions connected with the signal path between dc2, envelope1 and the filter, to see if you can find a negative variable or some function that is inverting the control signal (which this appears to be)
 
Hello graham,

more i think the triggerlock gets inverted, give me 5 min. then i will check the serial print to see what triggerlock it´s in :)
If i press the button, the sound gets instantly dull
if i release the button, the envelope starts (not inverted) but stays in the sustain phase
No noteOff seems to appear, i already tried to move different functions to differrent locations with no luck
 
Hi, so I was able to get it working with the bounce2 library,with the help from example bounce_basic
Maybe this will help someone in the future :)
 
Status
Not open for further replies.
Back
Top