Yes, really.
The point might not be emphasized strongly enough in the tutorial, but SynthDef structures are set in stone. You can replace a SynthDef with a completely new definition, and this can have a different structure. You can’t write one SynthDef where the design changes dynamically.
This question comes up a lot:
-
“I’m passing a synth argument for the number of channels and it’s complaining” – changing the number of channels changes the synth structure, so nope.
-
“I’m passing an array argument and the synth doesn’t adjust to the size of the array” – same thing.
-
“I want to pass in an oscillator at runtime” – changing the structure…
-
“I have a pvcollect synth and I want it to adjust to different buffer sizes” – nope.
You can get the result, just in a different way. The following will sound exactly the same as “passing in an oscillator,” but the SynthDefs are static. It’s totally idiomatic for SC.
(
[
{ |freq| SinOsc.ar(freq) },
{ |freq| Saw.ar(freq) },
{ |freq| Pulse.ar(freq, Rand(0.1, 0.5)) },
{ |freq| VarSaw.ar(freq, 0, Rand(0.1, 0.5)) },
{ |freq| Ringz.ar(PinkNoise.ar, freq, 1) }
].do { |oscillator, i|
SynthDef(("synth" ++ i).asSymbol, { |out, freq = 440, decay = 0.1, pan = 0, amp = 0.1|
var eg = EnvGen.kr(Env.perc(0.01, decay), doneAction: 2);
var sig = oscillator.value(freq);
Out.ar(out, Pan2.ar(sig, pan, eg * amp));
}).add;
};
)
(
var defnames = Array.fill(5, { |i| ("synth" ++ i).asSymbol });
p = Pbind(
\instrument, Prand(defnames, inf),
\freq, Pstutter(Pwhite(5, 20, inf).asStream, Pexprand(200, 800, inf)),
\dur, 0.1,
\amp, 0.1,
).play;
)
p.stop;
hjh