Indeed. The linearity of Ndef is a problem if you want to express (sig1 * env1) + (sig2 * env2)
. It’s not possible to have that as single Ndef (and still have all of sigs and envs be individually “hot-swappabe”. But Ndefs can refer to each other.
So you can can write something like (simplifying a bit the)
Ndef(\chain1)[0] = sig1;
Ndef(\chain1)[1] = \filter -> env1; // pseudocode
Ndef(\chain2)[0] = sig2;
Ndef(\chain2)[1] = \filter -> env2; // pseudocode
Ndef(\bigmix) = Ndef(\chain1) + Ndef(\chain2)
That does work because of a not so advertised feature that “Ndef math” mostly works.
You can even write
Ndef(\bigmix) = { (\wet1.kr * Ndef(\chain1).ar) + (\wet2.kr * Ndef(\chain2).ar) }
to give yourself mixer level controls for each. The simpler “Ndef math” version right above just does that as if you had written { Ndef(\chain1).ar + Ndef(\chain2).ar }
.
But \bigmix
will not have all the controls that \chain1
and \chain2
have in a single convenient location, because it’s a different Ndef on a different Group. Basically Ndef’s can’t really wrap one another as plain Groups can. Ndefs can only refer to another Ndefs.
You can just wrap all 3 Ndef groups \bigmix
, \chain1
and \chain2
in a single Group using the rather obscure parentGroup
feature of Ndef, so can set
parameters in one place form the command line, but that Group wont be a Ndef itself, so you’ll have this unpleasant asymmetry in interfaces, e.g. it won’t be representable as a NdefGui.
What you really need to consider in cases like this is whether you really need the ability to swap the filters on each chain at runtime, while the “base” signal is still running. Because if you don’t need that much flexibility, and e.g. you can restart the 'base" signal when the filter changes, then it’s much simpler to write a single Ndef (or SynthDef) for each chain so that it includes both the “base” signal and the filter. Basically, the difference between:
Ndef(\combo1) { sig1 * env1}
and
Ndef(\chailn)[0] = { sig1 }
Ndef(\chailn)[1] = \filter -> env1 // pseudocode
is that in the latter case you can later do just
Ndef(\chailn)[1] = \filter -> something else // pseudocode
and the phase of sig1 will stay exactly the same during the change, so no “drop outs” etc. In the case of Ndef(\combo1)
changes you’d probably have to do at least a cross fade for things to sound acceptable, and the xfade will sound different than merely changing filter.
Yeah, it really depends. Sometimes it does matter, but mostly in cases where you need to keep phase alignment.