Order of Execution + Audio Bus Mapping?

Hello,

I have some code (a little too big to post on here at the moment) which produces the following nodeTree:

NODE TREE Group 0
   1 group
      1001 group
         1002 time_1_phase
           i_out: 6 tempo: 1 fadeTime: 0 gate: 1
         1025 fast_1_phase
           i_out: 11 speed: 2 phaseIn: a6 fadeTime: 0 gate: 1
         1026 seq_4_sig
           i_out: 10 phaseIn: a11 step0: 100 step1: 200 step2: 300 step3: 400 fadeTime: 0 gate: 1
         1024 fast_1_sig
           i_out: 9 in: a10 fadeTime: 0 gate: 1
         1023 saw_2_sig
           i_out: 8 freq: a9 amp: a12 fadeTime: 0 gate: 1
         1008 rand_3_sig
           i_out: 12 randFreq: 4 min: 0 max: 2 phaseIn: a6 fadeTime: 0 gate: 1
         1022 out_2_sig
           i_out: 7 in: a8 vol: 0.20000000298023 gate: 1 fadeTime: 0.019999999552965

As you can see, I mapped the \amp AudioControl of the Synth saw_2_sig to Audio-Bus 12 (a12), to which the Synth rand_3_sig is writing to with a ReplaceOut-UGen. The synth writing sits AFTER the the synth reading from the Bus.
I would expect this to work, as this following minimal example does work:

(
SynthDef(\a, {ReplaceOut.ar(15, SinOsc.ar(\freq.kr(330)))}).add;
SynthDef(\b, {ReplaceOut.ar(0, \in.ar)}).add
)

(
x = Synth(\a);
y = Synth.before(x, \b, [\in, \a15])
)

// move Nodes, mapping continues to work
y.moveBefore(x)
x.moveBefore(y)

If I change the order of Nodes in my code, so that the writing synth comes first, everything works:

NODE TREE Group 0
   1 group
      1001 group
         1002 time_1_phase
           i_out: 6 tempo: 1 fadeTime: 0 gate: 1
         1025 fast_1_phase
           i_out: 11 speed: 2 phaseIn: a6 fadeTime: 0 gate: 1
         1026 seq_4_sig
           i_out: 10 phaseIn: a11 step0: 100 step1: 200 step2: 300 step3: 400 fadeTime: 0 gate: 1
         1024 fast_1_sig
           i_out: 9 in: a10 fadeTime: 0 gate: 1
         1008 rand_3_sig
           i_out: 12 randFreq: 4 min: 0 max: 2 phaseIn: a6 fadeTime: 0 gate: 1
         1023 saw_2_sig
           i_out: 8 freq: a9 amp: a12 fadeTime: 0 gate: 1
         1022 out_2_sig
           i_out: 7 in: a8 vol: 0.20000000298023 gate: 1 fadeTime: 0.019999999552965

So, my Question is: Is Mapping of Audio-Rate Inputs independent of Node Order or not?
I’m a little confused :]

EDIT: When I read-then-write on the Bus, I only get zeroes in the Audio Control

(I’m on SC 3.13.0-rc1)

All best,
moritz

Edit, I was wrong see then post for proper answer

The mapping itself works fine (if this was control-rate signals this would be different).
However, when you read-then-write, you are introducing a delay of one block size, but when you write-then-read, there is no delay.
This is because the server executes the synths in order, waiting once it gets to the bottom until the next block update. Meaning, the reading must happen on the next loop through the synths.

1 Like

Thanks for the reply! :slight_smile: A delay wouldnt be so much of a problem actually…
What happens in my case though is that I can only read zeroes from the Audio control if I read-then-write… In my minimal example this is not the case. Do you have an idea why this could be?

All best!

Woops! I was wrong, sorry about that… here is (I hope) a correct answer.

So…

Physical outputs are zeroed

Your example shows no signal when read first when I set the bus number low, but if I make the bus number high, or use the Bus allocator, it will work, producing one delay.

This is because supercollider zeros out all the buses that would be sent to the speakers every execution block.

Compare this…

SynthDef(\writer, {ReplaceOut.ar(1, SinOsc.ar(\freq.kr(330)))}).add;
SynthDef(\reader, {ReplaceOut.ar(0, \in.ar)}).add

~writer = Synth(\writer);
~reader = Synth.before(~writer, \reader, [\in, \a1])

~writer.moveBefore(~reader)
~reader.moveBefore(~writer)

… where, when ~reader is before ~writer, nothing is recevied on channel 1, to this…

~fsBus = Bus.audio(s);
SynthDef(\writer, {ReplaceOut.ar(~fsBus, SinOsc.ar(\freq.kr(330)))}).add;
SynthDef(\reader, {ReplaceOut.ar(0, \in.ar)}).add

~writer = Synth(\writer);
~reader = Synth.before(~writer, \reader, [\in, ~fsBus.asMap])

~writer.moveBefore(~reader)
~reader.moveBefore(~writer)

… which will work in all orders (but with the delay if reading first).

Channel 1 is a physical output (assuming you have two speakers).

For this reason, it is never a good idea to use manual bus numbers and the Bus class should be used instead.

However, things get more interesting…

\in.ar uses InFeedback.ar

If you use In.ar(\out_bus.kr) instead of \out.ar, it won’t work when you read first at all.

// note how the reader uses In explicitly, passing a bus number
SynthDef(\writer, {ReplaceOut.ar(~fdBus, SinOsc.ar(\freq.kr(330)))}).add;
SynthDef(\reader, {ReplaceOut.ar(0, In.ar(\inbus.kr))}).add

~writer = Synth(\writer);
~reader = Synth.before(~writer, \reader, [\inbus, ~fdBus])

~writer.moveBefore(~reader)
~reader.moveBefore(~writer)

If you want to do this, you need to explicitly use InFeedback.ar(\out_bus.kr). When you do \some_symbol.ar it automatically uses InFeedback (I did not know this!).

1 Like

Thank you for the clarification! I’ve been using \controlName.ar(0), which should work independently of Node order and the busses I used are allocated using Bus.audio(server, numChannels) (I just double checked, the relevant busses have indices far over my s.options.numOutputBusChannels)
Hmmmm…

Okay I have no idea then… Perhaps you could just use a buffer instead of a bus as a quick hack?

1 Like