Env.adsr: meaning of decayTime parameter

Hello,

this is straight from the Env helpfile

// a)
Env.adsr(0.02, 0.2, 0.25, 1, 1, -4).test(2).plot;

I hear a tone with a satisfying envelope and see the latter’s shape plotted on a graph.

The second parameter is decayTime. If I raise it like this:

// b)
Env.adsr(0.02, 30, 0.25, 1, 1, -4).test(2).plot;

I’d expect to hear a tone that takes much longer (30 seconds!) to ‘decay’ down from its peak amplitude before being released. This is what the plot also seems to show. (I’m assuming the the x-axis shows time in seconds.) But what I hear is a tone that, whie marginally louder than the previous one, still seems to last no longer.

On closer examination, I see that the plot for (a) shows a tone that lasts for little more than a second. But the ones I hear, for (a) and (b), both last for about three seconds.

What am I misunderstanding?

Hm, perhaps I’m overlooking the .test(2) method.

Decay is the time that it takes to fall from 1.0 (full scale) down to sustainLevel.

When the note is released, then the release time takes effect.

This matches the behavior of standard ADSR envelopes in a majority of synthesizers.

hjh

1 Like

Yes. The key bit I was missing is there in your expression “when the node is released”. If I understand correctly, there is no parameter you can pass to the Env.adsr itself that controls when this will occur. But there is one you can pass to the .test method; it’s there in the helpfile example I was using.

Thanks for the help!

I still wonder though: what is being plotted by .plot? It would seem not the envelope as sounded, since that might be about three seconds long (given .test(2)) while the plot shows an envelope lasting 30 seconds. The envelope as it would be under certain conditions?

The sound of a gated envelope depends on the duration of the gate.

Env:plot doesn’t have a gate or a duration, so it just plots the durations given in the envelope.

We don’t have an envelope GUI that accurately shows a gated envelope (for that matter, neither does VCV Rack or Vital or Serum or…), so it’s best not to get hung up on that; better to work with the numbers directly.

hjh

You could plot the accurate gated envelope like e.g.

(
{ 
  var gate = Env([1, 1, 0], [2, 0]).ar;  // 2 second gate
  Env.adsr(0.02, 30, 0.25, 1, 1, -4).ar(2, gate);
}.plot(3); // plot over 3 seconds to capture the release
)
1 Like

Thank-you both for the input. I can see I need to look up some tutorials on envelopes, triggers, gates, sustains and releases; this stuff has long confused me and I’d like to sort it out a bit.

1 Like

A key point that’s often overlooked is that an envelope segment always starts at the envelope generator’s current output level, and moves from there toward the segment’s target value. (“Current output level” doesn’t exist at the beginning – which is why levels has one extra item: an initializer.)

In your example, the attack quickly reaches 1.0, and then the decay segment takes 30 seconds to go toward 0.25. Assuming the gate is held open for 2 seconds: 0.02 of that is for the attack, leaving 2.98 seconds. EnvGen calculates the decay segment as if it’s going to take 30 seconds (it doesn’t know how long the gate will be open), so its value after 2.98 seconds is probably not far below 1.0. When the gate drops to 0, EnvGen jumps to the release segment but starts with that “just below 1.0” value. Then it seems like the decay isn’t doing much, but it is.

hjh

1 Like

Another thing that was confusing me was some examples I’d seen of Pbinds with a \sustain control. I think I’ve figured it out now though:

(
SynthDef(\sine, { |gate = 1|
	var 
	env = Env.adsr(\atkT.ir(0.2), \decT.ir(1)).kr(doneAction: 2, gate: gate),
    // or, equivalently:
    // env = EnvGen.kr(Env.adsr(\atkT.ir(0.2), \decT.ir(1)), gate: gate, doneAction: 2),
	sig = SinOsc.ar(\freq.ir(300)) * env;
	Out.ar(0, sig * \amp.ir(0.01))
}).add
;
Pdef(\pat, 
	Pbind(
		\instrument, \sine,
		\dur, 3,
		\freq, Pseq([1, 3/2, 2/3, 1], 1) * 300,
		\atkT, 0.5,
		\decT, 1,
		\sustain, 5,
)).play;
)

Current understanding: the \sustain control doesn’t communicate with Env:adsr’s sustainTime control but with an argument to -kr or EnvGen, and it only works if that argument is named ‘gate’. And yet you don’t use \sustain to send a 1 or 0 to open or close the gate, you use it to specify a number of seconds at the expiry of which the gate will close. Maybe intuitive once you get the hang of it!

I guess I was working on the assumption that the control inputs in a SynthDef and the ‘names used to identify controls’ in an Event like Pbind would be the same. (The Pbind documentation says ‘The SynthDef’s control names (found in its SynthDesc) are looked up in the event and the corresponding values included in the command.’) But \sustain, or presumably, \legato, apparently don’t work this way. Are there other Pbind controls that are like that that I should be watching out for?

See Pattern Guide 07: Value Conversions | SuperCollider 3.12.2 Help

hjh

1 Like