How do I read from a control bus from a synth?

I have this synthdef:

SynthDef.new(\sine, | freq|
var sig=SinOsc.ar(freq);
Out.ar(0,sig);
}).add;

SynthDef.new(\mousewrite,{
var x=MouseX.kr(50,200);
Out.kr(~k,x);
}).add;

SynthDef.new(\readbus,{
var val=In.kr(~k);
var sig=SInOSc.ar(val ,mul:0.3);
Out.ar(0,sig!2);
}).add;

~k=Bus.control(s,1);
a=Synth(\sine);
b=Synth(\readbus);
c=Synth(\mousewriteX,[\bus:~k]);

For some reason, readbus doesn’t seem to read from ~k, the control bus. Why doesn’t it do that ?

It turns out, that if you do a In.ar(~k); It automatically gets a bus number, but upon reaching ~k=Bus.control(s,1), a different bus number gets allocated, so there isn’t any data sent. But doing a arg bus; In.kr(bus) works fine, with ~k getting allocated a bus number later works fine.

This is a synchronisation issue: you need to s.sync between and wrap all the code in s.waitForBoot or some other routine.

You are probably sending nil the first time.

Also, please you backticks ‘`’ to encapsulate inline code, and triple backticks for blocks - makes things easier to read.

Actually, for buses, there is nothing to sync… because there’s no bus allocation message. So sync is irrelevant in this case (though it would be relevant for buffers).

More or less correct.

Many many SC users get confused about variables.

When you write ~k, maybe you thought it was a placeholder throughout the system, so that you update ~k anywhere and the new value immediately appears everywhere.

This is not how variables work.

~k in an expression immediately resolves to its current value – and the downstream recipient of this value has no idea that the value is associated with ~k at all.

So you’re really creating In.kr(nil, 1). Nil is nil. When you assign ~k later, nil is still nil.

Using synth arguments to pass in the bus number is a better way.

hjh

I keep forgetting this…

How do multiple clients on a single server work then?

In a simple version, you can pass the bus as parameter of your synths:

SynthDef.new(\sine, { 
	| freq|
	var sig=SinOsc.ar(freq);
	Out.ar(0,sig);
}).add;

SynthDef.new(\mousewrite,{
	|bus| // bus to which write the info
	var x=MouseX.kr(50,200);
	Out.kr(bus,x);
}).add;

SynthDef.new(\readbus,{
	|bus| // bus from which read the info
	var val=In.kr(bus);
	var sig=SinOsc.ar(val ,mul:0.3);
	Poll.kr(Impulse.kr(2),val);
	Out.ar(0,sig!2);
}).add;

~k=Bus.control(s,1);
a=Synth(\sine);
b=Synth(\readbus,[\bus:~k]);
c=Synth(\mousewrite,[\bus:~k]);

There is also a BusDef in some quarks (but I can’t find which one), which has a similar approach as the Ndef but for busses.

Syncing has nothing to do with the number of clients. sync only makes sure that a previous asynchronous command, e.g. loading a Buffer or sending a SynthDef, has completed.

Sorry, how do buffers work across multiple clients without sync? Surely there must be some process to ensure that A’s reverb bus isn’t B’s feedback bus?

Sorry, how do buffers work across multiple clients without sync?

Again, sync has nothing to do with syncing between Clients. This is an entire different process.

Regarding your question: clients themselves are responsible for this. Every client assigns itself a particular range of node IDs, Buffer numbers, Bus numbers, etc. The range itself can be derived from the client ID and the max. number of clients allowed on the Server. For example, if a Server may have max. 4 client and max. 1024 node IDs in total, each client may allocate up to 256 node IDs - with a different start index for each client.

Ah now I see. Having never used multiple clients, I assumed the bus numbers would be interleaved and therefore require syncing between.

…and this might be going off topic given this thread was actually about declaration and assignment ordering…

So, just for my own clarity here (correct me if I’m wrong?), a client gets the max number of clients and its client id from the server when connecting. From these numbers it derives a range of nodes ids, buffers, and busses that it can safely use. This is done through a ContiguousBlockAllocator, created inside the Server class.

No checks are done on the server’s end to ensure that a specific client is only modifying its own resources.

So how are shared Busses dealt with? Is this something that must be agreed upon before hand? Or is there some other mechanism for discovering global/public busses?

Yes. For more information, see the “Multi-client Setups” guide in the help browser.

So how are shared Busses dealt with? Is this something that must be agreed upon before hand?

I guess so. But I have to admit that I have never used Multi-client setups myself.

I was thinking to myself why I’d have the idea the SynthDef would use ~k from a later definition. And, it’s in other languages having a variable that is defined as global means references to the global variable changing are propogated throughout. But since SC is a client server architecture, the design choice is to have synthdefs on being defined immediately resolving placeholder symbols.

I think this is still a misunderstanding, though.

(
var a = 1;
var b = a + 2;

a = 5;

b  // here, what is b?
)

According to the idea of “variable changing are propogated throughout,” the new value of a would propagate to a + 2 and then b would update to 7.

But when you run it, you’ll find that b remains 3. So the new a value did not propagate.

This is standard behavior in almost all programming languages – Pascal, C, Java, Python, Ruby, Lua.

What is true is that changing the variable a means that the next time(s) a is accessed from anywhere in the code, it will resolve to the new value rather than the old. But expressions that had previously resolved the variable to an older value will not automatically update themselves.

Try this too, which is closer to your In usage:

(
var x = 1, y = 2;
var p = Point(x, y);

x = 22;

p.x  // is still 1
)

But here, everything is in the client – so the non-propagation is not a client/server limitation.

It’s just the way variables work in imperative languages (though not in some functional languages like Haskell). That expression Point(x, y) just looks up the current values of x and y and stuffs them into a Point object – only the values. There is no hidden link between the Point and the var x. The Point does not know where its values came from, so it cannot update automatically.

hjh

Yeah, i was thinking of references to the variable really, not the variable itself, but yes that’s how assignments work.