Assigning bus to variable

Hello,

I noticed the following problem and I cant get my head around it.
When I run the following code, the variable ~newValue is not the same number as ~value.
Any ideas why this is happening? Thank you :slight_smile:

// e.g. 
// ~value = 1.5157480314961
// ~newValue = 1.4960629940033

(
~value = Bus.control(s, 1).set(0);

MIDIdef.cc(\midi, {|val, ccNum|
	switch(ccNum,
		19, {~value.set(val.linlin(0, 127, 0, 2.5));
                     ~newValue = ~value.getSynchronous;
		},
)});
)

getSynchronous is not really synchronous. You can’t rely on it for this.

The only value it can access is the bus’s value at the last hardware buffer boundary.

Also, it takes some time for the set message to be delivered over the network (even on the same machine – it’s fast, but not instantaneous). The way this code is written, you’re guaranteed to get old data from polling the bus.

hjh

1 Like

I had to double check this but, getSynchronous is definitely synchronous - it returns the value immediately. The problem isn’t exactly that getSynchronous is fetching an “old” value - in fact, you have a guarantee of a very up-to-date value, much more than any OTHER way of accessing a bus value (it’s only old in terms of nanosecond-level thread memory synchronization). It’s old insofar as ANY instantaneous value from something that’s continuously changing is old as song as you ask for it, because it’s… changing continuously.

But James is right regarding the set message: doing ~value.set is actually saying “schedule a task to set the bus to this value” - it’s effectively setting the value in the (very near) future, but not immediately. If you wanted to fetch the value when it’s written, you can bundle a set and a get message together, which gives you a guarantee that your get happens after your set. This looks something like:

s.makeBundle(-1, {  // -1 here means "execute this bundle immediately, don't wait"
	var value = rrand(0, 100);
	"Value should be: %".format(value).postln;
	~b.set(value);
	~b.get({
		|v|
		"Value is: %".format(value).postln;
	})
})

I used get instead of getSynchronous because get schedules a task to get a value of the server, and does so AFTER set, which is what we want. The function passed in as an argument is what gets executed after the get is finished.

2 Likes

True – but its name leads users to expect that it will instantaneously access the value at any moment, and that isn’t the case.

Because the server calculates audio in hardware-buffer-sized batches, the only time points you can be reasonably sure of accessing by getSynchronous are the hardware buffer boundaries. I remember some users trying to call getSynchronous very quickly, with a relatively large buffer size, and being surprised that the value wasn’t continuously changing.

If you call getSynchronous mid-buffer, you won’t get the mid-buffer value.

hjh

1 Like