Other things on this site...

Evolutionary sound
Listen to Flat Four Internet Radio
Learn about
The Molecules of HIV
Make Oddmusic!
Make oddmusic!

Efficiency in SuperCollider: pausing synths

When I use SuperCollider I often create synths and when they're done I free them, but I don't often pause them. For example, if you've got a synth playing back a recorded audio Buffer, and the Buffer ends, hey ho, no problem, I can leave it running and send a trigger when I want the sound to play again. But since I'm currently working with mobile devices I need to be more careful about that kind of thing.

Here's an example of what I mean. Run this code block to define two synthdefs, a playback one and a "supervisor":

SynthDef(\supervisor, { |targetid=0, trigbus=0, rate=0.25|
    var cycle, pausegate;
    cycle = LFPulse.kr(rate);
    Out.kr(trigbus, Trig1.kr(cycle, 0));
    Pause.kr(cycle, targetid); 

SynthDef(\player, { |buf=0, trigbus=0|  
    // Some meaningless extra cpu-load so we can see the difference
    var heavycruft = 400.collect{[WhiteNoise, PinkNoise, BrownNoise].choose.ar}.squared.mean;
    Out.ar(0, PlayBuf.ar(1, buf, trigger: In.kr(trigbus)) + (heavycruft * 0.00001))

Now when I use the player synth like normal...

b = Buffer.read(s, "sounds/a11wlk01.wav")   
t = Bus.control(s);
x = Synth(\player, [\buf, b, \trigbus, t])

...I can see the CPU load on my machine shoots up to 40% (because of the pointless extra load I deliberately added into that second SynthDef), and it stays there even when the Buffer ends.

(Often you'd tell your synth to free itself when the Buffer ends using doneAction:2 - that works fine, but in this case I want the synth to keep running so I can retrigger it.)

Having run the above code, now start the supervisor running:

y = Synth(\supervisor, [\targetid, x.nodeID, \trigbus, t], x, addAction: \addBefore)

This should repeatedly pause-and-restart the playback. When the sound is silent, the CPU load drops from 40% down to 0.1%. So, clearly it makes a saving!

So in order to do this I had to use Pause.kr() in the supervisor, and also to tell the supervisor which node to pause/unpause (using x.nodeID). The supervisor is also sending triggers to a control bus, and the player is grabbing those triggers to reset playback to the start.

| supercollider | Permalink