If you’re merely asking about the meaning of those fields. that is actually simple, at least after the SynthDef is fully built. Here’s an example with a deliberate dupe:
d = SynthDef(\aa, { arg x = #[1, 2, 3], y = #[55, 66]; Control.names(\x).kr(44) })
d.allControlNames do: _.postln
/* ->
ControlName P 0 x control [ 1, 2, 3 ]
ControlName P 3 y control [ 55, 66 ]
ControlName P 5 x control 44
*/
The index
field (first thing printed after “P”) is the index in the SynthDef control array as will be
stored on the server. So the “x” at index 0 is not the same as the “x” at index 5.
As for argNum
, which isn’t actually printed above:
d.allControlNames collect: _.argNum
// -> [ 0, 1, 2 ]
argNum
is redundant when you have access to allControlNames
, but not when you look at a single ControlName object in separation. argNum
basically maps back to the array index in allControlNames
. The main reason why argNum
exists as a field is probably that SynthDef.buildControls
code (which is only called for controls built from function arg
s) is structured to split the work by type of Control, e.g. there are separate chunks of code to deal with triggers, audio etc. and these chunks access subcollectons as in:
var arguments = Array.newClear(controlNames.size);
// ...
var trControlNames = controlNames.select {|cn| cn.rate == 'trigger' };
// ...
trControlNames.do {|cn, i|
cn.index = index;
index = index + cn.defaultValue.asArray.size;
arguments[cn.argNum] = controlUGens[i];
By the way, you can see there that the size of the sub-array of a given Control only explicitly stored in cn.defaultValue.asArray.size
, i.e. the size of the defaultValue
array for a given Control.
Since controlNames
is actually cleared when the SynthDef is built and only allControlNames is retained, we should probably check what happens with argName in a SynthDef wrap situation, while things are still being built.
Yeah, those argNum
s are relative to the innermost SynthDef being wrapped, i.e. index into controlNames
not allControlNames
really:
(
SynthDef(\aa, { arg x = #[5, 7], y = #[66, 77], a_i;
SynthDef.wrap { arg t_t = 1, z = #[111, 222];
UGen.buildSynthDef.controlNames do: _.postln;
UGen.buildSynthDef.controlNames.do { |cn| cn.argNum.postln };
UGen.buildSynthDef.allControlNames do: _.postln;
};
UGen.buildSynthDef.allControlNames.do { |cn| cn.argNum.postln };
})
)
/*
ControlName P 5 t_t trigger 1
ControlName P 6 z control [ 111, 222 ]
0
1
ControlName P 1 x control [ 5, 7 ]
ControlName P 3 y control [ 66, 77 ]
ControlName P 0 a_i audio 0.0
ControlName P 5 t_t trigger 1
ControlName P 6 z control [ 111, 222 ]
0
1
2
0
1
*/
In a wrapping situation argNum
is meaningless in the outside synthDef except for its own controlNames. For the interior SynthDefs, it’s basically garbage info once it reached the outer def because the inner arrays are destroyed by that point. Basically, argNum
s are temp numbers, not really useful after the stack of SynthDef.wrap
stack is popped one or more times. (You could actually use it to detect that the SynthDef used wrap
inside, by detecting non-monocities in final argNum
s, but I’m not sure how that info is useful.)
Also noteworthy that buildControls
emits controls ControlName.index
-grouped by type, so those indexes don’t necessarily coincide with the function argument order that was passed to SynthDef and also not with the array order in the allControlNames
. You can see that above happen with a_i
that gets ControlName.index
-reordered (to index 0) before the kr-rate controls. The ControlName.index
order is always: ir, tr, ar, kr. I’m not sure if this was done merely for esthetic reasons or if the sever has some such ordering expectation. I strongly suspect it was merely for esthetic reasons because it doesn’t index-group past wrap
boundaries, e.g.
(
d = SynthDef(\aa) { arg x = #[5, 7]; SynthDef.wrap {
arg z = #[111, 222], a_i; Out.ar(0, 0) }}
)
d.allControlNames do: _.postln
/*
ControlName P 0 x control [ 5, 7 ]
ControlName P 3 z control [ 111, 222 ]
ControlName P 2 a_i audio 0.0
*/