Modulate an LPF Freq cutoff using an envelope or LFO

You can definitely use the same envelope for controlling different things in the same Synth.

The adsr envelope will range between 0 and 1, which is good for amplitude, but not specifically for controlling the cutoff of a filter. You’ll need to scale the value of the envelope when setting it to control the LPF’s cutoff.

There are several ways to do this:

You can either straight up multiply and/or add values to it to get it into the range you’re after. If you want to control from 200 Hz to 700 Hz, you can multiply the envelope by 500 and add 200. This way when the envelope is at 0, the cutoff is at 200, and when the envelope peaks at 1, the cutoff will be at 700.

LPF.ar(Saw.ar(200, 0.1), env * 500 + 200);

Or you can using a scaling method like linlin, or linexp and have it do the math for you, providing the bottom and top range.

LPF.ar(Saw.ar(200, 0.1), env.linlin(0, 1, 200, 700));

I personally find both of these a bit inflexible because because if you were to break them out into arguments in your SynthDef all of a sudden you need to provide two values, which need to sync with a third- freq. Also, you’ll always need to use the envelope when calling the Synth.

The way I typically do it mimics a typical filter envelope control on any subtractive synth, I have a cutoff parameter, and then I can also apply the envelope if I want to:

LFP.ar(Saw.ar(200, 0.1), cutoff + env.linlin(0, 1, 0, envAmount));

This way you can set envAmount to be 0 and just get a regular control for the cutoff.

For envAmount you can have scaling math elsewhere so that a 0-1 value will allow you to sweep frequency, but personally I just put in the amount in Hertz. And envAmount can be negative to sweep downward.

(
SynthDef(\synth, { |out, a = 0.01, d = 0.3, s = 0.5, r = 4, gate = 1, freq = 440, cutoff = 3000, envAmount = 200, amp = 0.2|
	var env, sig;
	env = Env.adsr(a, d, s, r).kr(Done.freeSelf, gate);
	sig = Saw.ar(freq) ! 2;
	sig = LPF.ar(sig, cutoff + env.linlin(0, 1, 0, envAmount));
	sig = sig * env * amp;
	Out.ar(out, sig);
}).add
)

a = Synth(\synth, [a: 4, d: 1.2, s: 0.3, r: 4, freq: 200, cutoff: 200, envAmount: 500])  // env will sweep from cutoff to (cutoff + envAmount)
a.set(\gate, 0) // release envelope and synth

// no envelope used on filter:
a = Synth(\synth, [a: 4, d: 1.2, s: 0.3, r: 4, freq: 200 cutoff: 200, envAmount: 0])
a.set(\cutoff, 600)
a.set(\gate, 0)

You can apply the same scaling strategy to use an oscillator UGen as an LFO in place of the envelope too. You just need to know the default range it oscillates between. It’s typically in the help files, but I also stick the poll message onto things in SynthDefs to see how they behave over time. For instance in that SynthDef, sig = LPF.ar(sig, cutoff + env.linlin(0, 1, 0, envAmount).poll); will show me the envelope’s contribution. Or wrap cutoff + env in parenthesis to see how the actual cutoff frequency for the LPF.

4 Likes