I’m currently working on a project where i want to record incoming OSC data into an array.
Right now everything happens on the language side of supercollider.
Via a =OSCdef= or =OSCFunc= i receive the OSC data, which is then saved into an variable.
Via a =Task= i write this variable into an =Array=. The Task loops the writing process and it’s writing speed is controlled by a delta time value inside the loop. This works right now.
But i was wondering, how many times per second the OSCFunc is able to receive a new OSC message. Since this is on the language side, i assumed that this is happening on the =SystemClock=. But then i did read a little and now i’m not sure anymore.
// Edit: Also, what are the limits of a loop inside a Task? How many times per second is a loop happening (besides a =delta.wait= inside the loop). And how is the receiving of an OSC message synced with the execution of one task loop?
I try to compare this to the process in Csound, where everything is bound to the kontrol rate and audio rate, where audio rate is the sampling rate and the kontrol rate is equivalent to =1 / (vector-size / SR)=. Receiving OSC data in Csound is bound the k-rate, which limits the speed of receiving but makes it also controlable.
How is this managed in SuperCollider?
OSC messages are dispatched as soon as the network thread can grab the global interpreter lock. The main scheduler thread releases the lock when there are no more routines to run for the current logical system time, so it goes to sleep. This is a chance for pending OSC messages to be dispatched.
Side note: ideally, the network thread would not try to directly pass the OSC message to the OSC handlers. Instead, it should put the messages on a queue that is regularly polled in the interpreter loop. This would make sure that the network thread never has to wait for the interpreter, minimizing the risk of packet loss.
n = NetAddr("127.0.0.1", 9000);
(
x = 0;
OSCdef(\x, { x = x + 1; x.postln }, '/sendback');
fork {
n.sendMsg(\go, \reply, 1);
bench { 1e8.do { 1+1 } }
}
)
1e8.do blocks the interpreter thread for between 2 and 3 seconds on my machine. The Pd patch sends back immediately, so all of those messages will be received while the interpreter is busy.
For n > 8738, it only receives 8738 messages consistently (though I’m not doing anything here to identify which messages are being lost),
So it looks to me like packet loss is extremely rare. You would have to keep the interpreter busy for long periods of time, and flood the language with a huge number of messages in quicker succession than is probably useful for real-world applications.