I’d like to suggest a feature for scsynth that could be very helpful in machine learning and other automated workflows: a persistent non-realtime (NRT) mode where the server stays running after rendering a score, and continues accepting new NRT render requests via OSC.
Currently, starting a new process for each render adds significant overhead, especially when generating large numbers of audio files, for example, in training loops with PyTorch or TensorFlow. A scsynth instance that can handle multiple NRT scores would make this much more efficient.
Is there already a way to achieve something like this? Or has this been discussed before?
This idea was suggested many years ago. It’s a good one.
But never implemented. The most effective workaround, I think, involves avoiding NRT mode, maintaining a persistent real-time server, and just using Recorder.
As I understand it, SuperCollider’s entire architecture revolves around the question “What comes next?” rather than “What happens between time X and Y?”
. In SC, there’s no built-in concept of absolute time positioning - to know what happens at time Y, you must iterate through everything from the start.
When SC generates an offline audio file, it processes everything sequentially, just like real-time playback, but without waiting. You can’t say “render me just seconds 30-40” without processing 0-30 first. The system has no way to “seek” to a time position because patterns maintain internal state that depends on their entire history.
I don’t know if the new Clock architecture being discussed was just to make things faster (seems to be the case), or, it would support things like time-indexed queries, en enormous change in software design
Such Clock could do:
efficient partial rendering (render just a specific section)
true random access to pattern data
parallel processing of different time segments|
[[ EDIT: I don’t know much about the project, I noticed some notes about something along those lines, but it was not a central issue there ]]
What I was trying to say is: The obstacles to implementing a /render_nrt command would be relatively light, since most of the functionality exists already. The obstacles to a new clock architecture for NRT are significantly greater, and unsurprisingly not researched in the last 13 years since the feature request was logged.
I’m not denying the benefits of a fast-trackable clock, but it’s also worth considering the practical developer load.
If you could boot up a NRT server, load a bunch of buffers and SynthDefs, and run multiple NRT score files in succession, that would already help the stated use case.
One example of such a Clock with time as a field of each event is Tidal. I think that’s the main difference between patterns in SC and Tidal.
My first try to implement patterns in Haskell, I used a Time field in the Event type. Later, I noticed that supercollider does not work like this, and hsc3-lang Pattern version, either. But Tidal has something that can be related.
I just read the notes to try to understand their “why.” I think what has been seen as the main limitation with the NRT clock is that it prevents any bidirectional communication between client and server during rendering. This restriction makes it impossible to use reply messages, SendTrig functionality, dynamic buffer manipulation, etc.
/nrt_advance and /nrt_advanced message protocol would create a bidirectional handshake, allowing, for example, Routines to execute at “turbo” speeds while maintaining correct timing.
The justification is strong, but the implementation is too profound too. World_NonRealTimeSynthesis in SC_World.cpp would need to implement stateful operations, for example, and logical time.
NRT overhead problem now is basically at startup, so for certain workflows (rendering a large number of small sounds) this is a pain in the ass.
There are tools to help with that, like batchNRT Quark. But it will not solve the startup situation.