Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 21 of 21

Thread: Basic Envelope to Filter question

  1. #1
    Junior Member
    Join Date
    Sep 2021
    Posts
    14

    Basic Envelope to Filter question

    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.

    envelope-filterTest2.ino

    Any help would be appreciated
    Thanks in advance
    Stefan

  2. #2
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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
    }

  3. #3
    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 by grahamguitarman; 09-07-2021 at 01:58 PM.

  4. #4
    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!

  5. #5
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    Quote Originally Posted by grahamguitarman View Post
    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

  6. #6
    Quote Originally Posted by degu234 View Post
    Thatīs all? Nothing more? Ok i will try that at home. Thank you so far
    Yep that's all there is to it :-)

  7. #7
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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

  8. #8
    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.

  9. #9
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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

  10. #10
    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:

    Click image for larger version. 

Name:	Screenshot 2021-09-10 at 09.41.46.png 
Views:	11 
Size:	34.9 KB 
ID:	25790

    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.

  11. #11
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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?

  12. #12
    Quote Originally Posted by degu234 View Post
    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:

    Click image for larger version. 

Name:	Screenshot 2021-09-10 at 12.03.43.png 
Views:	10 
Size:	22.0 KB 
ID:	25792

    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:

    Click image for larger version. 

Name:	Screenshot 2021-09-10 at 12.08.14.png 
Views:	9 
Size:	21.2 KB 
ID:	25793

    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.

  13. #13
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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)
    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 :/

  14. #14
    Quote Originally Posted by degu234 View Post
    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)
    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!

  15. #15
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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

  16. #16
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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 );
    }

  17. #17
    Quote Originally Posted by degu234 View Post
    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)

  18. #18
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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

  19. #19
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    triggerlock and triggerstate are both 1 while i push the button for gate In

  20. #20
    Junior Member
    Join Date
    Sep 2021
    Posts
    14
    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

  21. #21
    Quote Originally Posted by degu234 View Post
    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
    Ah yes, always a good idea to debounce your switches!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •