2 summary:: Specification for a segmented envelope
3 related:: Classes/EnvGen, Classes/InterplEnv
4 categories:: Control, Envelopes
7 An Env is a specification for a segmented envelope. Envs can be used both server-side, by an link::Classes/EnvGen:: within a link::Classes/SynthDef::, and clientside, with methods such as link::#-at:: and link::#-asStream::, below.
9 An Env can have any number of segments which can stop at a particular value or loop several segments when sustaining. It can have several shapes for its segments.
12 Env.new([0,1,0.9,0], [0.1,0.5, 1],[-5,0,-5]).plot;
15 The envelope is conceived as a sequence of emphasis::nodes:: (not to be confused with a synthesis-Node) each of which has three parameters: a target level, a time duration from the previous node, and a shape. The three parameters for each node are kept in separate arrays as explained below.
18 In some other computer music systems and situations we deal with control points or breakpoints. If these control points have associated x positions (say in an envelope GUI, see link::Classes/EnvelopeView::) they must be converted to time differences between points to be used as nodes in a Env object.
26 Create a new envelope specification.
29 an array of levels. The first level is the initial value of the envelope.
32 an array of durations of segments in seconds. There should be one fewer duration than there are levels.
35 a link::Classes/Symbol::, link::Classes/Float::, or an link::Classes/Array:: of those. Determines the shape of the envelope segments.
37 The possible values are:
39 ## code::\step:: || || flat segments
40 ## code::\linear:: || code::\lin:: || linear segments, the default
41 ## code::\exponential:: || code::\exp:: || natural exponential growth and decay. In this case, the levels must all be nonzero and have the same sign.
42 ## code::\sine:: || code::\sin:: || sinusoidal S shaped segments.
43 ## code::\welch:: || code::\wel:: || sinusoidal segments shaped like the sides of a Welch window.
44 ## code::\squared:: || code::\sqr:: || squared segment
45 ## code::\cubed:: || code::\cub:: || cubed segment
46 ## a link::Classes/Float:: || || a curvature value for all segments. 0 means linear, positive and negative numbers curve the segment up and down.
47 ## an link::Classes/Array:: of symbols or floats || || curvature values for each segment.
51 an link::Classes/Integer:: or nil. The envelope will sustain at the release node until released.
54 an link::Classes/Integer:: or nil. If not nil the output will loop through those nodes startign at the loop node to the node immediately preceeding the release node, before back to the loop node, and so on. Note that the envelope only transitions to the release node when released. Examples are below. The loop is escaped when a gate signal is sent, when the output transitions to the release node, as described below.
57 Creates a new envelope specification with strong::numSegments:: for filling in later.
59 This can be useful when passing Env parameters as args to a link::Classes/Synth::. Note that the maximum number of segments is fixed and cannot be changed once embedded in a link::Classes/SynthDef::. Trying to set an Env with more segments than then this may result in other args being unexpectedly set. See link::#newClear:: example below.
61 subsection::Standard Shape Envelope Creation Methods
62 The following class methods create some frequently used envelope shapes based on supplied durations.
65 Creates a new envelope specification which has a trapezoidal shape.
68 the duration of the attack portion.
71 the duration of the sustain portion.
74 the duration of the release portion.
77 the level of the sustain portion.
80 the curvature of the envelope.
85 Env.linen(1, 2, 3, 0.6).test.plot;
86 Env.linen(0.1, 0.2, 0.1, 0.6).test.plot;
87 Env.linen(1, 2, 3, 0.6, 'sine').test.plot;
88 Env.linen(1, 2, 3, 0.6, 'welch').test.plot;
89 Env.linen(1, 2, 3, 0.6, -3).test.plot;
90 Env.linen(1, 2, 3, 0.6, -3).test.plot;
94 Creates a new envelope specification which has a triangle shape.
97 the duration of the envelope.
100 the peak level of the envelope.
104 Env.triangle(1, 1).test.plot;
108 Creates a new envelope specification which has a hanning window shape.
111 the duration of the envelope.
114 the peak level of the envelope.
118 Env.sine(1, 1).test.plot;
122 Creates a new envelope specification which (usually) has a percussive shape.
125 the duration of the attack portion.
127 argument::releaseTime
128 the duration of the release portion.
131 the peak level of the envelope.
134 the curvature of the envelope.
138 Env.perc(0.05, 1, 1, -4).test.plot;
139 Env.perc(0.001, 1, 1, -4).test.plot; // sharper attack
140 Env.perc(0.001, 1, 1, -8).test.plot; // change curvature
141 Env.perc(1, 0.01, 1, 4).test.plot; // reverse envelope
144 subsection::Sustained Envelope Creation Methods
145 The following methods create some frequently used envelope shapes which have a sustain segment.
148 Creates a new envelope specification which is shaped like traditional analog attack-decay-sustain-release (adsr) envelopes.
151 the duration of the attack portion.
154 the duration of the decay portion.
156 argument::sustainLevel
157 the level of the sustain portion as a ratio of the peak level.
159 argument::releaseTime
160 the duration of the release portion.
163 the peak level of the envelope.
166 the curvature of the envelope.
170 Env.adsr(0.02, 0.2, 0.25, 1, 1, -4).test(2).plot;
171 Env.adsr(0.001, 0.2, 0.25, 1, 1, -4).test(2).plot;
172 Env.adsr(0.001, 0.2, 0.25, 1, 1, -4).test(0.45).plot; //release after 0.45 sec
176 As link::#*adsr:: above, but with it's onset delayed by strong::delayTime:: in seconds. The default delay is 0.1.
179 Creates a new envelope specification which is shaped like traditional analog attack-sustain-release (asr) envelopes.
182 the duration of the attack portion.
184 argument::sustainLevel
185 the level of the sustain portion as a ratio of the peak level.
187 argument::releaseTime
188 the duration of the release portion.
191 the curvature of the envelope.
195 Env.asr(0.02, 0.5, 1, -4).test(2).plot;
196 Env.asr(0.001, 0.5, 1, -4).test(2).plot; // sharper attack
197 Env.asr(0.02, 0.5, 1, 'linear').test(2).plot; // linear segments
201 Creates a new envelope specification which has no attack segment. It simply sustains at the peak level until released. Useful if you only need a fadeout, and more versatile than link::Classes/Line::.
203 argument::releaseTime
204 the duration of the release portion.
207 the peak level of the envelope.
210 the curvature of the envelope.
214 Env.cutoff(1, 1).test(2).plot;
215 Env.cutoff(1, 1, 4).test(2).plot;
216 Env.cutoff(1, 1, 'sine').test(2).plot;
224 Blend two envelopes. Returns a new Env. See link::#blend:: example below.
229 argument::blendFraction
230 a number from zero to one.
233 Returns a new Env based on the receiver in which the start value will be held for strong::delay:: number of seconds.
236 The amount of time to delay the start of the envelope.
240 a = Env.perc(0.05, 1, 1, -4);
245 a = Env([0.5, 1, 0], [1, 1]).plot;
250 circle from end to beginning over the time specified, with the curve specified.
256 Env([6000, 700, 100], [1, 1], ['exp', 'lin']).circle.postcs)
258 + Impulse.ar(1) }.play;
264 Env([6000, 700, 100], [1, 1], ['exp', 'lin']).circle(1).postcs,
267 + Impulse.ar(1) }.play;
272 Test the envelope on the default link::Classes/Server:: with a link::Classes/SinOsc::.
274 argument::releaseTime
275 If this is a sustaining envelope, it will be released after this much time in seconds. The default is 3 seconds.
278 Plot this envelope's shape in a window.
281 The size of the plot. The default is 400.
284 the size of the plot window.
287 the minimum value in the plot. Defaults to the lowest value in the data.
290 the maximum value in the plot. Defaults to the highest value in the data.
293 a window to place the plot in. If nil, one will be created for you.
296 Returns a link::Classes/Signal:: of size strong::length:: created by sampling this Env at strong::length:: number of intervals.
299 Converts the Env to an link::Classes/Array:: in a specially ordered format. This allows for Env parameters to be settable arguments in a SynthDef. See example below under link::#newClear::.
302 Returns true if this is a sustaining envelope, false otherwise.
304 method::range, exprange
305 Returns a copy of the Env whose levels have been mapped onto the given linear or exponential range.
310 a.range(42, 45).levels;
311 a.exprange(42, 45).levels;
314 // Mapping an Env to an exponential frequency range:
316 SinOsc.ar(EnvGen.ar(Env.perc(0.01, 0.2).exprange(40, 10000), doneAction: 2)
322 subsection::Client-side Access and Stream Support
323 Sustain and loop settings have no effect in the methods below.
326 Returns the value of the Env at strong::time::.
329 Env.triangle(1, 1).at(0.5);
332 method::embedInStream
333 Embeds this Env within an enclosing link::Classes/Stream::. Timing is derived from code::thisThread.beats::.
336 Creates a Routine and embeds the Env in it. This allows the Env to function as a link::Classes/Stream::.
341 e = Env.sine.asStream;
352 s.boot; //.test below will run a synthesis example
353 // to demonstrate the envelope, so the Server must be on
355 // different shaped segments: .plot graphs the Env
356 Env.new([0,1, 0.3, 0.8, 0], [2, 3, 1, 4],'linear').test.plot;
357 Env.new([0.001, 1, 0.3, 0.8, 0.001], [2, 3, 1, 4],'exponential').test.plot;
358 Env.new([0, 1, 0.3, 0.8, 0], [2, 3, 1, 4],'sine').test.plot;
359 Env.new([0.001, 1, 0.3, 0.8, 0.001],[2,3,1,4],'welch').test.plot;
360 Env.new([0, 1, 0.3, 0.8, 0], [2, 3, 1, 4],'step').test.plot;
361 Env.new([0, 1, 0.3, 0.8, 0], [2, 3, 1, 4], -2).test.plot;
362 Env.new([0, 1, 0.3, 0.8, 0], [2, 3, 1, 4], 2).test.plot;
363 Env.new([0, 1, 0.3, 0.8, 0], [2, 3, 1, 4], [0, 3, -3, -1]).test.plot;
366 If a release node is given, and the gate input of the EnvGen is set to zero, it outputs the nodes after the release node:
369 // release node is node 1; takes 0.5 seconds to go from 0 to 1,
370 // sustains at level of 1, then released after three seconds
371 // (test causes the release after three seconds, given the argument 3),
372 // taking 2 seconds to finish
373 Env.new([0,1,0],[0.5,2],'linear',1).test(3).plot
375 // more complex examples
376 // release node is node 2; releases after 5 sec
377 Env.new([0.001,1,0.3,0.8,0.001],[2,3,1,4] * 0.2, 2, 2).test(5).plot;
378 Env.new([0.001,1,0.3,0.8,0.5,0.8,0],[2,3,1,2,2,1] * 0.2, 2, 2).test(5).plot;
380 // early release: goes straight onto the release node after 0.1 seconds
381 Env.new([0.001,1,0.3,0.8,0.5,0.8,0],[2,3,1,2,2,1] * 0.2, 2, 2).test(0.1).plot;
384 If a loop node is given, the EnvGen outputs the nodes between the loop node and the release node (not including the release node itself) until it is released:
387 // release node is node 2, loop node is node 0: so loops around nodes 0 (lvl 1, dur 0.5)
388 // and 1 (lvl 0.1, dur 0.5) //until released after 3.5 seconds
389 Env.new([0,1,0.1,0],[0.5,0.5,2], 'lin', 2, 0).test(3.5).plot;
391 // this just sustains at node 0, because there is no other node to loop around!
392 Env.new([0,1,0],[0.5,2], 'lin', 1, 0).test(3.5).plot;
394 // more complex example: release node is node 3, loop node is node 1
395 Env.new([0.001,1,0.3,0.8,0.5,0.8,0],[2,1,1,2,3,1] * 0.1, 'lin', 3, 1).test(3).plot;
399 The starting level for an envelope segment is always the level you are at right now. For example when the gate is released and you jump to the release segment, the level does not jump to the level at the beginning of the release segment, it changes from whatever the current level is to the goal level of the release segment over the specified duration of the release segment.
401 There is an extra level at the beginning of the envelope to set the initial level. After that each node is a goal level and a duration, so node zero has duration equal to times[0] and goal level equal to levels[1].
403 The loop jumps back to the loop node. The endpoint of that segment is the goal level for that segment and the duration of that segment will be the time over which the level changed from the current level to the goal level.
409 SynthDef(\help_Env_newClear, { |i_outbus=0, t_gate|
411 // make an empty 4 segment envelope
412 env = Env.newClear(4);
413 // create a control argument array
414 envctl = Control.names([\env]).kr( env.asArray );
415 Out.ar(i_outbus, SinOsc.ar(EnvGen.kr(envctl, t_gate), 0, 0.3));
420 // must not have more segments than the env above
421 e = Env([700,900,900,800], [1,1,1], \exp); // 3 segments
422 x = Synth(\help_Env_newClear, [\t_gate, 1]);
423 x.setn(\env, e.asArray);
427 // reset then play again
428 e = Env([800,300,400,500,200], [1,1,1,1], \exp); // 4 segments
429 x.setn(\env, e.asArray);
437 a = Env([0, 0.2, 1, 0.2, 0.2, 0], [0.5, 0.01, 0.01, 0.3, 0.2]).test.plot;
438 b = Env([0, 0.4, 1, 0.2, 0.5, 0], [0.05, 0.4, 0.01, 0.1, 0.4]).test.plot;
444 blend(a, b, u).test.plot;
446 Window.allWindows.pop.close; // close last opened window
451 // blend in a SynthDef
453 SynthDef(\help_EnvBlend, { | fact = 0 |
454 Out.ar(0, EnvGen.kr(Env.perc.blend(Env.sine, fact), 1.0, doneAction: 2)
455 * SinOsc.ar(440,0,0.1)
462 f.do({|fact| Synth(\help_EnvBlend, [\fact, fact.postln]); 1.wait;});