Retriggering/Resetting a Sustained Envelope

I’m hoping to be able to retrigger a sustained envelope as its being sustained. I couldn’t find a method for it.

I was able to figure out how to do it using two envelopes, while fading between them:

(
SynthDef(\retrigEnv, { |out|
	var sig, env1, env2, toggleEnv, hold1, hold2, env, hold, trig, flux;

	
	//// parameter controls
	///////////////////////
	var att = \att.kr(0.01),
	dec = \dec.kr(0.3),
	sus = \sus.kr(0.5),
	rel = \rel.kr(1),
	crv = \crv.kr(-2),
	del = \del.kr(0),
	timeScale = \timeScale.kr(1),
	offset = \offset.kr(0),
	peak = \peak.kr(1);


	//// inputs
	///////////
	hold = \hold.kr(1);
	trig = \trig.tr;
	toggleEnv = ToggleFF.kr(trig);
	hold1 = hold.min(ToggleFF.kr(trig + Impulse.kr(0))); // start high
	hold2 = hold.min(toggleEnv);


	//// signal generation
	//////////////////////
	env = Env.adsr(att, dec, sus, rel, 1, crv);
	env2 = env.kr(0, hold2, timeScale, peak, offset);
	env1 = env.kr(0, hold1, timeScale, peak, offset);
	
	sig = LinXFade2.kr(env1, env2, toggleEnv.lag2(0.015) * 2 - 1);

	//// output
	///////////
	Out.kr(out, sig)
}).add
)

z = Bus.control;
a = { SinOsc.ar ! 2 * \amp.kr }.play(args: [amp: z.asMap])
b = Synth(\retrigEnv, [att: 0.5, dec: 0.5, sus: 0.7, peak: 0.1, out: z])
b.set(\trig, 1)
b.set(\trig, 1)
b.set(\trig, 1)
b.set(\trig, 1)
b.set(\hold, 0) // gate - release control
b.set(\hold, 1) // gate - release control
z.free

But I’m wondering if there’s a better way?

I think you can cook something up with an “upside-down” trigger argument…does this do what you’re envisioning?

s.boot;

(
x = {
	var env, sig;
	sig = PinkNoise.ar(0.2!2);
	env = EnvGen.kr(
		Env.adsr(0.01, 0.5, 0.1, 1, 1, -2),
		(1 - \trig.tr(1)) * \end.kr(1),
		doneAction: 2
	);
	sig = sig * env;
}.play;
)

x.set(\trig, 1); //retrigger
x.set(\end, 0); //fade
1 Like

I works the same as my example, so it’s great and much simpler. Thank you Eli!

What’s confusing for me is that I figured that (1-\trig.tr(1)) * \end.kr(1) would null out and wouldn’t trigger at all, so I didn’t even try something as streamlined…

Is there a reason that on code evaluation, 1-1 * 1 still sneaks in as a positive going signal?

Boris

The expression (1 - \trig.tr(1)) is only equal to 0 for one control cycle. Trigger-rate arguments snap back to zero on the next control cycle after they are set to a non-zero value.

Ahh of course! Didn’t consider it over time.

Actually, I didn’t ask the my follow up question correctly-

Since (1- \trig.tr(1)) * \end.kr(1) does null out, even for one control cycle, how does that not trigger the doneAction?

Obviously it works. Just wondering why – I was about to go and re-edit a couple of SynthDefs when I remembered the doneAction was set to 2 (I was thinking of adding a FreeSelf.kr(1 - \end.kr(1))) when I remembered that your example works completely fine with the DA 2 in the EnvGen itself.

When the gate becomes zero, the release is triggered, but the doneAction is only executed if the release is able to finish. Because the gate pops right back to 1, the envelope restarts almost immediately.

Ohh. Ok, now that clears it all up. Of course! the doneAction doesn’t kick in until after the release segment.

Thank you!