Input-spec / output-spec

hello everybody, I am slowly building the Pharo front end for SuperCollider :slight_smile:
here in theSynth Definition File Format what I dont understand is

an input-spec is :

  • int32 - index of unit generator or -1 for a constant
  • if (unit generator index == -1) :
    • int32 - index of constant
  • else :
    • int32 - index of unit generator output

an output-spec is :

  • int8 - calculation rate

// what are the [input-spec] and the [output-spec] of a Ugen? where can I find more information about them?

thanks a lot.
d

UGens usually have inputs, generally given as arguments to ar, kr or ir methods. These inputs and their sources need to be communicated to the server in the binary format. This is the input-spec.

UGens usually have outputs. The server needs to know the rate of each output.

Maybe the most straightforward way to talk about it is to annotate a very simple def’s binary representation:

(
d = SynthDef(\io, {
	var freq = NamedControl.kr(\freq);
	Out.ar(0, SinOsc.ar(freq));
});
)

d.dumpUGens

[ 0_Control, control, nil ]
[ 1_SinOsc, audio, [ 0_Control[0], 0.0 ] ]
[ 2_Out, audio, [ 0, 1_SinOsc ] ]

d.asBytes  // annotated below

83, 67, 103, 102, "SCgf"
0, 0, 0, 2,  version
0, 1,  1 def

2, 105, 111,   "io" defname
0, 0, 0, 1,  number of constants
0, 0, 0, 0,  only constant is 0 -- it's used twice below

0, 0, 0, 1,  num params
0, 0, 0, 0,  param init value (1st and only one)

0, 0, 0, 1,  num param names
4, 102, 114, 101, 113, param name (1st, only) = "freq"
0, 0, 0, 0,  param index

0, 0, 0, 3,  num UGens

7, 67, 111, 110, 116, 114, 111, 108,  UGen name (Control)
1,  kr
0, 0, 0, 0,  0 inputs
0, 0, 0, 1,  1 output
0, 0,  "special index"
input specs are skipped because num = 0
1,  output is kr

6, 83, 105, 110, 79, 115, 99,  UGen name SinOsc
2,  ar
0, 0, 0, 2,  2 inputs
0, 0, 0, 1,  1 output
0, 0,  special index
0, 0, 0, 0,  1st input, index of UGen --> Control
0, 0, 0, 0,  1st input -- index of Control's output = 0 (1st, only Control output)
-1, -1, -1, -1,  2nd input (SinOsc phase) = 0xFFFFFFFF = -1 --> constant
0, 0, 0, 0,  use the first constant
2,  output = ar

3, 79, 117, 116,  Out
2,  ar
0, 0, 0, 2,  2 inputs
0, 0, 0, 0,  no outputs
0, 0,  special index
-1, -1, -1, -1,  1st input = constant
0, 0, 0, 0,  constant index 0
0, 0, 0, 1,  2nd input comes from UGen 1 = SinOsc
0, 0, 0, 0,  1st output from SinOsc

0, 0  num variants = 0

hjh

1 Like

thank you really much for your reply, that really helps! I didnt know the .dumpUGens method :slight_smile:
now another question comes.
how are ‘ordered’ the UGens when I call .dumpUgens?
I noticed that if I add other controls to that simple SynthDef they come after 2_Out. I tried with different simple synthdefs and I cant understand it.
thanks.
d

This is normal and expected.

SynthDef tries to arrange the UGens depth-first. It begins with the first UGen in the list of children that is taking no input from any other UGen. (If it isn’t taking input from another UGen, then there is no UGen that needs to be calculated before this one. Thus this UGen is eligible to go into the final ordering – “available,” in the code.)

Then it follows the input-output chain as far down as it can, before moving on to any other “available” UGens that hadn’t been resolved yet.

In my example SynthDef, the topological sort cannot resolve SinOsc until its input, Control, is resolved. And it cannot resolve Out until its input, SinOsc, is resolved. So it can get only one result: Control → SinOsc → Out.

When you added another Control, if it’s not connected to anything, then its order is arbitrary. Order comes from the inputs and outputs – no connections, order is meaningless. It happens that the sort will follow the chain down from the first control all the way to the end, before noticing the other Control. Thus the second Control goes to the bottom.

You are used to seeing Control near the top because normally its outputs are feeding into other units, pushing those other units later in the order. (What’s the point of a Control that isn’t controlling anything?) But there is no rule that Controls must precede other units. The typical ordering is a consequence of normal usage, in which other units depend on data from Control, so those other units must follow after Control. If you break that typical usage pattern, then typical ordering is not guaranteed.

hjh

great explanation. thanks for it. now it’s time for me to go back to Pharo and try to build SynthDef from there with a pure OOP syntax :slight_smile: