4. SynthDefs & Envelopes

SC has an optimized way of taking in information about UGens and their interconnections: SynthDefs. A SynthDef tells the server how to generate audio and translates that information to byte code. More specifically, a SynthDef is the blueprint that defines a particular instance of a playing Synth. Or, if you prefer, a SynthDef is a cake recipe and a Synth is the cake you end up with by following the recipe.

What follows are two versions of the same instrument: one that sustains until receiving an off message and another which has a specific duration.

sustaining synth

SynthDef( \sin, { | amp = 0.0, freq = 440, out = 0, trig = 0 |
    var env, sig, finalSig;
    env = EnvGen.kr( Env.asr( 0.001, 0.9, 0.001 ), trig, doneAction: 0 );
    sig = SinOsc.ar( freq, 0.0, amp );
    finalSig = sig * env * 0.6;
    Out.ar( out, Pan2.ar(finalSig) );
}).add;

x = Synth( \sin, [ \freq, 400, \amp, 0.5]);

x.set(\trig, 1);
x.set(\trig, 0 );
s.scope;

Here we define a SynthDef named \sin with a sustaining envelope, or an envelope that plays continuously until receiving an off message. Variables are used to organize the code into chunks: env, short for envelope, is the portion of our code that allows us to toggle the sound on and off; sig, short for signal, is the portion of our code that defines what the sound is. Multiplying the env by the sig is what results in the "on/off" functionality above and occurs in the finalSig line.

The resulting signal is written to a Bus (in this case, our speakers) in the Out.ar line, which also converts our Mono signal to Stereo. We will revisit this line in the future so for now don't spend too much time paying attention to it. Note: I reuse the above general structure for all sustaining sounds unless something special/unusual is needed.

To hear the \sin we need to create and play an instance of it, which we accomplish using Synth. In order to turn this instance of \sin off in the future we store it to the variable x. After running the Synth line, we can turn the envelope on by setting the \trig argument to 1. Later we can turn our synth off by setting \trig to 0. Think of these two lines as a metaphorical toggle button for \sin.

deterministic synth

SynthDef( \sin, { | amp = 0.0, freq = 440, out = 0, sus = 1, trig = 0 |
    var env, sig, finalSig;
    env = EnvGen.kr( Env.linen( 0.001, sus, 0.001 ), trig, doneAction: 2 );
    sig = SinOsc.ar( freq, 0.0, amp );
    finalSig = sig * env * 0.6;
    Out.ar( out, Pan2.ar(finalSig) );
}).add;


Synth( \sin, [ \amp, 0.5, \freq, 400, \trig, 1]);

The primary difference between the sustaining and deterministic synth can be seen in their respective env lines. Here we use a different Env: .linen. Take a moment to compare the two Env (.asr and .linen) by highlighting Env and looking it up in the the Help <Command+D>.

.linen creates Envelopes in a trapezoidal shape. In order to calculate this shape, .linen needs information regarding the duration, in seconds, of each segment of its shape. One commonly refers to each segment of the shape as attack time (segment 1), sustain time (segment 2), and release time (segment 3). In other words, if we want our Synth to play for 10 seconds we would want to set each of our segments such that the total time adds up to 10. In the above Synth we accomplish this by using super tiny numbers for attack and release and setting sus to 10.

The benefit here is that the envelope (and associated Synth) will clean itself up after it is done (this is set by doneAction: 2 in the SynthDef), so we could run the Synth line repeatedly to create, for example, 5 instances of \sin each with a total duration of (approximately) 10 seconds. Note: I reuse the above general structure for all deterministic sounds unless something special/unusual is needed.