This may or may not be relevant to this specific problem, but one area that SynthDef doesn’t optimize well is repeated creation of the same deterministic operation.
(
d = SynthDef(\test, { |lo = 0, hi = 1, outLo = 0, outHi = 10|
Out.kr(0,
Array.fill(2, {
Rand(lo, hi).linlin(lo, hi, outLo, outHi)
})
)
});
d.dumpUGens;
)
[ 0_Control, control, nil ]
[ 1_Rand, scalar, [ 0_Control[0], 0_Control[1] ] ]
[ 2_Clip, scalar, [ 1_Rand, 0_Control[0], 0_Control[1] ] ]
[ 3_-, control, [ 0_Control[3], 0_Control[2] ] ]
[ 4_-, control, [ 0_Control[1], 0_Control[0] ] ]
[ 5_/, control, [ 3_-, 4_- ] ]
[ 6_*, control, [ 5_/, 0_Control[0] ] ]
[ 7_-, control, [ 0_Control[2], 6_* ] ]
[ 8_MulAdd, control, [ 5_/, 2_Clip, 7_- ] ]
[ 9_Rand, scalar, [ 0_Control[0], 0_Control[1] ] ]
[ 10_Clip, scalar, [ 9_Rand, 0_Control[0], 0_Control[1] ] ]
[ 11_-, control, [ 0_Control[3], 0_Control[2] ] ]
[ 12_-, control, [ 0_Control[1], 0_Control[0] ] ]
[ 13_/, control, [ 11_-, 12_- ] ]
[ 14_*, control, [ 13_/, 0_Control[0] ] ]
[ 15_-, control, [ 0_Control[2], 14_* ] ]
[ 16_MulAdd, control, [ 13_/, 10_Clip, 15_- ] ]
[ 17_Out, control, [ 0, 8_MulAdd, 16_MulAdd ] ]
11-15 are the same as 3-7.
I have some experimental code that collapses this to:
[ 0_Control, control, nil ]
[ 1_Rand, scalar, [ 0_Control[0], 0_Control[1] ] ]
[ 2_Clip, scalar, [ 1_Rand, 0_Control[0], 0_Control[1] ] ]
[ 3_-, control, [ 0_Control[3], 0_Control[2] ] ]
[ 4_-, control, [ 0_Control[1], 0_Control[0] ] ]
[ 5_/, control, [ 3_-, 4_- ] ]
[ 6_*, control, [ 5_/, 0_Control[0] ] ]
[ 7_-, control, [ 0_Control[2], 6_* ] ]
[ 8_MulAdd, control, [ 5_/, 2_Clip, 7_- ] ]
[ 9_Rand, scalar, [ 0_Control[0], 0_Control[1] ] ]
[ 10_Clip, scalar, [ 9_Rand, 0_Control[0], 0_Control[1] ] ]
[ 11_MulAdd, control, [ 5_/, 10_Clip, 7_- ] ]
[ 12_Out, control, [ 0, 8_MulAdd, 11_MulAdd ] ]
… producing two chains of Rand → Clip → MulAdd (required, because there are two distinct Rand units whose results will be different), but only one set of coefficient calculations based on the control inputs.
Since you’re working with a matrix, probably every chain traces back to something different, which this would not be able to optimize. But it’s possible that, if you’re collapsing control inputs down to other values, and this is inside a loop, maybe some of those operations are duplicated.
To try the linked gist, save the .sc file into your extensions directory, recompile, and do UGenCache.optimize = true;
before building your SynthDef (once in a session).
hjh