Make GUI refresh not freeze language?

Hi all and wishing everyone a happy new year…

Wondering if anyone has a strategy in a case like this, where a GUI refresh is hanging up sclang and therefore resulting in choppy audio. (Beyond, of course, making the drawFunc more efficient.)

Is there a way to guarantee that GUI stuff will never hang up the rest of sclang? (I had sort of thought that’s what defer was meant to do, but I was clearly wrong)

(Also, throttling the rate of window refresh does not solve things – it just makes the hiccups less frequent)

(Edit: also I specifically need the audio scheduling to happen in sclang rather than on the server)

(
~synth = { SinOsc.ar(\freq.kr(100)); }.play;
~window = Window().front;
UserView(~window, Rect(0, 0, 400, 400)).drawFunc_({
  Pen.use {
    20000.do {
      Pen.moveTo(1.0.rand@1.0.rand * 400);
      Pen.lineTo(1.0.rand@1.0.rand * 400);
      Pen.color = Color.rand;
      Pen.stroke;
    }
  }
});
fork {
  200.do { |i|
    ~synth.set(\freq, i + 100);
    defer { ~window.refresh }; // comment this line for smooth audio
    0.03.wait;
  }
}
)

Within one sclang process, I don’t think so.

What you’re looking for is preemptive thread scheduling. Sclang doesn’t have this feature.

You could run two sclang processes and pass OSC messages between them. Then the OS will handle the threads preemptively (almost certainly running them on separate cores, on a multicore system, which is basically every computer now).

hjh

the idea of multiple clients on the same machine is interesting - I’ve used multiple clients on a network but never on one machine… this might help me with some performance problems…fyi basic guide is here: Multi-client Setups | SuperCollider 3.12.2 Help though without the OSC messaging part…

1 Like

Hm, my suggestion isn’t really “multi-client” though because only one of the sclang processes would be using the server. The other one would be doing graphics, but if it’s not connecting to the server, then it isn’t really a “client” and you would not need to worry about maxNumClients or such.

FWIW, when I was using SC as a MIDI clock source, I ran two sclang instances, one for live coding and one only for MIDI clock out, because I didn’t want MIDI clock timing to be affected by sequencing activities. It worked a treat.

hjh

(smacks head) ahh yes of course…

Yeah I had thought of running a separate instance… feels like a bit of a shame because at the moment I’m trying to make tools that are drop-in / non-prescriptive in how they’re used. (I find when I make a tool that is too dependent on a particular workflow or setup I never actually use it) – but I guess that might mean I should focus on making the GUIs more efficient, at least during playback… I wonder if there’s a way to abort the drawFunc at a certain point if things are taking too long

@jamshark70 when you ran two instances did you use a separate IDE instance as well or do you have tips for running a second sclang instance from the same IDE session? I guess it could be as simple as starting sclang from the command line with a particular port number and running a script that listens for OSC messages containing SC code and then evaluates them… though this sounds suspiciously like a security risk? (If this is the way I go I at least want to avoid building some monolithic GUI server.)

also, just because I’m curious, and this may be over my head – what is the reason for AppClock / defer if not to protect other Clocks from timing problems?

I guess it’s cool that I’ve been using custom GUIs for so long without running into this problem :slight_smile: I really always thought defer implied TempoClock timing immunity

My MIDI clock script doesn’t need to run arbitrary code, because it has just the one job. So there was no security risk in that case.

If you have a tempoclock that needs to do something at time point x, and something else on appclock at time point x (same time), you want the tempoclock to do its thing first. This was definitely a thing when I started with SC on a G4 iBook – single-core – if the server was busy, GUI updates could be delayed by up to half a second. On today’s multicore machines, this kind of contention is rare / non-existent.

SC has no way to interrupt a long-running function for a higher priority activity – it’s never had this. There is no timing immunity in SC. Normally this isn’t an issue because in most cases you can structure your code to run in very short bursts. A 20000-cycle drawFunc can’t be split up though… which is why you’re seeing the issue now (long running, un-splittable task with a high frame rate).

hjh

1 Like

Does this include the situation of defining SynthDefs in sclang and using another client in another language to send messages to the server? I remember I had problems trying that in the past, I was probably missing something like this.