There are a couple of ways to do this. Which one is best depends on what you're trying to do.
If you have a large number of distinct envelopes (say, every synth should have a radically different envelope shape), see the EnvGen help file for an example of using an array of synth control to define the shape. (This technique got a little easier in the current SVN development build, since you should not have to do .setn explicitly for the envelope control points -- that code still new and may change, though.)
If the envelopes have the same basic contours, but just different levels and times, you can create the envelope using synth arguments:
SynthDef(\xyz, { |attack, decay, sustain, release, gate = 1 /* other args */|
var env = Env.adsr(attack, decay, sustain, release),
envg = EnvGen.kr(env, gate, doneAction: 2);
...
});
But my favorite is to use Instr.
Instr("plainsin", { |freq, gate, env|
SinOsc.ar(freq) * EnvGen.kr(env, gate, doneAction: 2)
}, [\freq, \gate, EnvSpec(Env.adsr(0.1, 0.5, 0.4, 0.2))]);
mydef = Patch("plainsin").asSynthDef; // use default envelope
// replace with a different envelope
myOtherDef = Patch("plainsin", [nil, nil, Env.asr(0.8, 1, 1.8)]).asSynthDef;
Now you have two synthdefs from the same template, with different envelopes, and without a lot of extra Controls that you might not be using.
If Instr is too confusing, you can write functions to generate synthdefs.
makeADef = { |name, env|
SynthDef(name, { |freq, gate = 1 /* other args */|
var envg = EnvGen.kr(env, gate, doneAction: 2);
...
});
};
makeADef.("s1", Env(....)).send(s);
Why can't I use envelopes like Line.kr?
Because a SynthDef is a fixed, predefined arrangement of UGens. There is no way to add new UGens to a synth while it's playing. It's not only envelopes -- that's true of any UGen.
James