This file is indexed.

/usr/share/SuperCollider/HelpSource/Classes/EnvGen.schelp is in supercollider-common 1:3.8.0~repack-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
class:: EnvGen
summary:: Envelope generator
related:: Classes/Linen, Classes/Env
categories::  UGens>Envelopes


Description::

Plays back break point envelopes. The envelopes are instances of the
link::Classes/Env:: class. The envelope and the arguments for  code::levelScale:: ,
code::levelBias:: , and  code::timeScale::
are polled when the EnvGen is triggered and remain constant for the
duration of the envelope.

code::
{ PinkNoise.ar(EnvGen.kr(Env.perc, doneAction: 2)) }.play
::

classmethods::

private::convertEnv

method::ar, kr

argument::envelope

An link::Classes/Env:: instance, or an Array of Controls.
(See link::Classes/Control::  and the example below for how to use
this.)

The envelope is polled when the EnvGen is triggered. The Env inputs can be other UGens.


argument::gate

This triggers the envelope and holds it open while > 0. If the
Env is fixed-length (e.g. Env.linen, Env.perc), the gate argument
is used as a simple trigger. If it is an sustaining envelope
(e.g. Env.adsr, Env.asr), the envelope is held open until the
gate becomes 0, at which point is released.

If strong::gate:: < 0, force release with time code:: -1.0 - gate ::. See link::#Forced release:: below.

argument::levelScale

Scales the levels of the breakpoints.


argument::levelBias

Offsets the levels of the breakpoints.


argument::timeScale

Scales the durations of the segments.


argument::doneAction

An integer representing an action to be executed when the env is
finished playing. This can be used to free the enclosing synth,
etc. See link::Reference/UGen-doneActions::  for more detail.

discussion::
note::
The actual minimum duration of a segment is not zero, but one sample step for audio rate and one block for control rate. This may result in asynchronicity when in two envelopes of different number of levels, the envelope times add up to the same total duration. Similarly, when modulating times, the new time is only updated at the end of the current segment - this may lead to asynchronicity of two envelopes with modulated times.
::

code::

// as amplitude envelope
(
{
	var env = Env([0, 1, 0.5, 1, 0], [0.01, 0.5, 0.02, 0.5]);
	SinOsc.ar(470) * EnvGen.kr(env, doneAction: 2)
}.play
)

// as amplitude and modulation envelope
(
{
	var env = Env([0, 1, 0.5, 0.8, 0, 1.2, 0], [0.01, 0.5, 0.02, 0.5, 0.2, 0.5]);
	var gate = Impulse.kr(MouseX.kr(0.2, 3), 0.5);
	var gen = EnvGen.kr(env, gate);
	SinOsc.ar(270, SinOsc.ar(gen * 473)) * gen * 0.2
}.play
)
// EnvGen multichannel expands when passed a multichannel envelope
(
{
	SinOsc.ar(
		EnvGen.kr(
			Env.circle([0, 1, 0, (2..4), 0, LFNoise1.kr(0.1 ! 5) * 10, 0], [0.01, 0.6])
		)
		* 240 + 300
	).sum * 0.2
}.play;
)
::

Examples::

code::
// retriggered envelope by Dust
(
{
	var env = Env([0.0, 0.5, 0.0, 1.0, 0.9, 0.0], [0.05, 0.1, 0.01, 1.0, 1.5], -4);
	var envgen = EnvGen.ar(env, Dust.ar(1));
	SinOsc.ar(
		envgen * 1000 + 440
	) * envgen * 0.1
}.play
);

// two channels
(
{
	var env = Env([0.0, [-0.2, 0.5], 0.0, 1.0, [-0.4, 0.9], 0.0], [0.05, 0.1, 0.01, 1.0, 1.5], -4);
	var envgen = EnvGen.ar(env, Dust.ar([1, 1]));
	SinOsc.ar(
		envgen * 440 + 550
	) * envgen * 0.1
}.play
);

// an envelope in a SynthDef can be used to limit the synth's lifetime (doneAction: 2)

(
SynthDef(\env_help, { | out, gate = 0, freq = 440 |
    var z;
    z = EnvGen.kr(Env.perc, doneAction: 2) * SinOsc.ar(freq, 0, 0.1);
    Out.ar(out, z)
}).add;
)

(
fork {
	10.do {
		Synth(\env_help);
		0.2.rand.wait;
	}
}
)


// using a gated envelope to gate a sound:
(
SynthDef(\env_help, { | out, gate = 0, freq = 440, doneAction = 0 |
    var z = EnvGen.kr(Env.adsr, gate, doneAction: doneAction) * SinOsc.ar(freq, 0, 0.1);
    Out.ar(out, z)
}).add;
)

a = Synth(\env_help);


// turn on
a.set(\gate, 1);

// turn off
a.set(\gate, 0);

// it does not matter to what value the gate is set, as long as it is > 0
a.set(\gate, 2);

a.set(\doneAction, 2, \gate, 0); // set doneAction to two to let the synth free itself

a.free; // alternatively, free it directly.
::

subsection:: Specifying an envelope for each new synth
code::
(
SynthDef(\help_Env_newClear, { |out = 0|
	var env, envctl;
	// make an empty 4 segment envelope
	env = Env.newClear(4);
	// create a control argument array
	envctl = \env.kr(env.asArray);
	Out.ar(out,
		SinOsc.ar(EnvGen.kr(envctl, \gate.tr), 0, 0.3) // the gate control is a trigger
	);
}).add;
)

Synth(\help_Env_newClear, [\gate, 1, \env, Env([700,900,900,800], [1,1,1], \exp)]); // 3 segments

// reset then play again:
Synth(\help_Env_newClear, [\gate, 1, \env, Env({ rrand(60, 70).midicps } ! 4, [1,1,1], \exp)]);

// the same written as an event:
(instrument: \help_Env_newClear, gate: 1, env: Env({ rrand(60, 70).midicps } ! 4, [1,1,1], \exp)).play;

::

subsection:: Forced release
If the gate of an EnvGen is set to -1 or below, then the envelope will cutoff immediately.
The time for it to cutoff is the amount less than -1, with -1 being as fast as possible, -1.5 being a cutoff in 0.5 seconds, etc.
The cutoff shape is linear.
code::
(
SynthDef(\stealMe, { |out, gate = 1|
    Out.ar(out, {BrownNoise.ar}.dup * EnvGen.kr(Env.asr, gate, doneAction:2))
}).add;
)

a = Synth(\stealMe);
a.release(3); //  // cutoff in 3 seconds

// this is how the OSC data looks like:
s.sendMsg(\s_new, \stealMe, 1001, 1, 0);
s.sendMsg(\n_set, 1001, \gate, -1.1); // cutoff in 0.1 seconds
::

If the synthDef has an arg named "gate", the convenience method of Node can be used: code::node.release(releaseTime)::
code::
d = { arg gate=1; {BrownNoise.ar}.dup * EnvGen.kr(Env.asr, gate, doneAction:2) }.play;
d.release(3);
::

subsection:: Fast triggering tests
code::
(
{
    EnvGen.kr(
        Env.new([ 0.001, 1, 0.5, 0 ], [ 0.01, 0.3, 1 ], -4, 2, nil),
        Impulse.kr(10)
    ) * SinOsc.ar(440, 0, 0.1)
}.play;
)

(
{
    EnvGen.kr(
        Env.perc( 0.1, 0.0, 0.5, 1, \welch ),
        Impulse.kr(100),
        timeScale: 0.1
    ) * SinOsc.ar(440, 0, 0.3)
}.play;
)
::

subsection:: Modulating the levelScale
code::
// no, it doesn't take a ugen in ...
(
{
    EnvGen.kr(
        Env.asr( 0.1, 1.0, 0.5, \welch ),
        1.0,
        FSinOsc.ar(1.0).range(0.0, 1.0),
        timeScale: 0.1
    ) * SinOsc.ar(440, 0, 0.3)
}.play;
)

// ...but an .ir rate input, a float or an ir rate ugen like Rand would work
(
{
    EnvGen.kr(
        Env.asr( 0.1, 1.0, 0.5, \welch ),
        1.0,
        Rand(0.1, 1.0),
        timeScale: 0.1
    ) * SinOsc.ar(440, 0, 0.3)
}.play;
)
::

subsection::More examples

For more information about the emphasis::control bus mapping:: used in the line code::a = Synth(\sine, [freq: f.asMap]);::, see link::Classes/Node#-map:: and link::Classes/Bus#-asMap::.

code::

// Changing an Env while playing
(
SynthDef(\env, { arg i_outbus=0;
	var env, envctl;

	// make a dummy 8 segment envelope
	env = Env.newClear(8);

	// create a control argument array
	envctl = \env.kr( env.asArray );

	ReplaceOut.kr(i_outbus, EnvGen.kr(envctl, doneAction: 2));
}).add;
)

(
SynthDef(\sine, { |freq = 0|
	Out.ar(0, SinOsc.ar(freq, 0, 0.2));
}).add;
)

f = Bus.control(s, 1);
f.set(800);

// use f's control bus value for frequency
// i.e. *map* the control to read from the bus
a = Synth(\sine, [freq: f.asMap]);

Synth(\env, [i_outbus: f, env: Env([700, 900, 900, 800], [1, 1, 1]*0.4, \exp)]);

Synth(\env, [i_outbus: f, env: Env([1000, 1000, 800, 1000, 900, 1000], [1, 1, 1, 1, 1]*0.3, \step)]);

a.free;
f.free;
::