Can someone please explain the use of SynthDef.wrap for developing more modular code? I’ve seen the method reference and I understand how I could use it to more conveniently add effects, but I feel like I’m not really able to take full advantage its use. I’ve seen Mads’ example but I still don’t really understand the rationale for its use.
// Filter functions organized in a dictionary (Event)
// The signal of our synth will be passed in as the first argument
f = (
hpf: { |in, cutoff=1000, rq=1|
RHPF.ar(in, cutoff, rq)
},
bpf: { |in, cutoff=1000, rq=1|
BPF.ar(in, cutoff, rq)
},
lpf: { |in, cutoff=1000, rq=1|
RLPF.ar(in, cutoff, rq)
}
);
// Iterate over all the filters we defined above and use them in a SynthDef
f.keysValuesDo{|filtername, filterfunction|
var synthdefname = "saw" ++ filtername.asString;
SynthDef.new(synthdefname, { |freq=220, out=0|
var sig = Saw.ar(freq, mul:0.1);
sig = SynthDef.wrap(
filterfunction,
prependArgs: [sig] // Pass signal in to the filter
// NOTE: prependArgs HAVE to be inside of []
);
Out.ar(out, sig)
}).add;
};
)
So I tried to use this design pattern to make a simple subtractive synth:
(
var osc, filt, defName;
osc = (
sin: { |freq = 261.63|
SinOsc.ar(freq);
},
tri: { |freq = 261.63|
LFTri.ar(freq);
},
sqr: { |freq = 261.63|
LFPulse.ar(freq).unipolar;
},
saw: { |freq = 261.63|
LFSaw.ar(freq);
}
);
filt = (
lpf: { |in, cutoff = 1000, rq = 1|
RLPF.ar(in, cutoff, rq);
},
bpf: { |in, cutoff = 1000, rq = 1|
BPF.ar(in, cutoff, rq);
},
hpf: { |in, cutoff = 1000, rq = 1|
RHPF.ar(in, cutoff, rq);
}
);
osc.keysValuesDo{|oscName, oscFunc|
filt.keysValuesDo{|filtName, filtFunc|
var defName = oscName.asString ++ filtName.asString[0].toUpper ++ filtName.asString[1..];
SynthDef(defName, {
var sig = SynthDef.wrap(oscFunc);
sig = SynthDef.wrap(filtFunc, prependArgs:[sig]);
Out.ar(\out.kr(0), sig!2);
}).add;
};
}
)
But why do this? Now I just have a bunch of SynthDefs that I can access with \osc_filt
. I could just as easily do this:
~build = {|osc, freq, filt, cutoff|
{
var sig = osc.ar(freq:freq);
sig = filt.ar(in: sig, freq: cutoff);
}.play;
}
How do others use SynthDef.wrap, when, and why? It seems like it could be incredibly useful, but I feel like I’m missing something.