I need help to free this EnvGen

Hi, I was trying the SC-808 SynthDefs made by Yoshinosuke Horiuchi with Patterns. Despite the EnvGen has a doneAction: 2 the synth is not cleared and therefore it generates infinite nodes.If I replace the Env.new with a Env.perc they are correctly cleared. So how can I also free the synth using Env.new?

(
SynthDef.new(\bd, {
	arg decay=30, amp=2, gate=0, tone=56;
	var fenv, env, trienv, sig, sub, punch, pfenv;
	env = EnvGen.kr(Env.new([0.11, 1, 0], [0, decay], -225),doneAction:2);
	trienv = EnvGen.kr(Env.new([0.11, 0.6, 0], [0, decay], -230),doneAction:0);
	fenv = Env([tone*7, tone*1.35, tone], [0.05, 0.6], -14).kr;
	pfenv = Env([tone*7, tone*1.35, tone], [0.03, 0.6], -10).kr;
	sig = SinOsc.ar(fenv, pi/2) * env;
	sub = LFTri.ar(fenv, pi/2) * trienv * 0.05;
	punch = SinOsc.ar(pfenv, pi/2) * env * 2;
	punch = HPF.ar(punch, 350);
	sig = (sig + sub + punch) * 2.5;
	sig = Limiter.ar(sig, 0.5) * amp;
	sig = Pan2.ar(sig, 0);
	Out.ar(0, sig);
}).add;

Pbindef(\bd, \i, \bd, \a, 1, \d, 1/4).play;

A 30 second decay with a sharp curve (-225) will drop to near-silence very quickly but will not release the envelope until after the full 30 seconds. That’s a rather strange approach.

If you want the synth to disappear in a few hundred ms then decay should be on the order of 0.1, 0.2, 0.3.

Then the envelope curve value will need to have a much smaller magnitude (try different values until it sounds right).

hjh

James’ solution is simpler but if you don’t want to mess with the original decay curve you could change the doneAction in the original line to 0 and then add something like:
env = env * Env([1,1,0],[0.5,0.1]).kr(doneAction:2)
to fade the synth out and free it

Playing with the envelope math:

e = Env([1, 0], [30], -225);

// hi-lo game to find the x value (time)
// where this envelope has decayed by 60 dB
(
f = { |env, target = 0.001|
	var lo = 0, hi = 1, mid;
	
	while { (hi - lo) > 0.000001 } {
		mid = (hi + lo) * 0.5;
		if(env[mid] > target) {
			lo = mid;  // assuming decay here
		} {
			hi = mid;
		}
	};
	
	mid
};
)

f.(e, 0.001)
-> 0.92103481292725

e[0.921]
-> 0.0010002553115686  // OK!

// what is the midpoint of that curve?
e[0.921 * 0.5]
-> 0.031626813174403

// some maths I worked out years ago,
// to calculate curve factor based on
// start y, midpoint y, end y
(
~curve = { |minval, midval, maxval|
    var a, b, c, sqrterm, qresult, sgn = sign(maxval - minval);
       // the formula is unstable just above the average of minval and maxval
       // so mirror the midval around the average
    if(midval > ((maxval + minval) * 0.5)) {
       midval = minval + maxval - midval;
       sgn = sgn.neg;
    };
    a = midval - minval;
    b = minval - maxval;
    c = maxval - midval;
    sqrterm = sqrt(b.squared - (4 * a * c));
    qresult = (sqrterm - b) / (2 * a);
    if(qresult.abs != 1) {
       log(qresult.squared).abs * sgn
    } {
       log(((b.neg - sqrterm) / (2 * a)).squared).abs * sgn
    };
};
)

e = Env([1, 0], [0.921], ~curve.(1, 0.031626813174403, 0));
e.curves
-> -6.843224515159

e[0.921 * 0.5]
-> 0.031626813174403  // spot on

a = Env([1, 0], [30], -225).discretize(1024 * 30);
a = a[0 .. (a.size * 0.921 / 30).asInteger].resamp1(512);

b = Env([1, 0], [0.921], -6.843224515159).discretize(512);

[a.as(Array), b.as(Array)].lace(a.size * 2).plot(numChannels: 2);
// plots are very nearly identical

So you can use Env([0.11, 1, 0], [0, 0.921], -6.843224515159) and the kick synth should cut off in 921 ms, and the curve is practically the same.

hjh

1 Like

Thank you for all your solutions. I have tried them all and they work as a charm.

@jamshark70 Those maths are amazing. No fail possible with those calculations.