I didn’t, but hacked one up just now.
This works to trigger nodes that are already set up.
I didn’t find a way to re-trigger an envelope on a node that had run once, paused itself and then needed to be reawakened.
Also, I can’t find a way for one server node to address specific control inputs of a different server node. (You could conceivably map those control inputs to control buses, and the controller node could Out.kr
or ReplaceOut.kr
to set the value, but I didn’t try to do that today. I don’t expect I will try it later either, tbh.)
So, this example creates 10 paused nodes, and the c
controller synth wakes them up one by one, following a trigger in the server. You could replace the Dust.kr
by an Onsets.kr
or other analytical process to have instant response to audio triggers.
(
SynthDef(\defaultP, { arg out=0, freq=440, amp=0.1, pan=0, time = 2;
var z;
z = LPF.ar(
Mix.new(VarSaw.ar(freq + [0, Rand(-0.4,0.0), Rand(0.0,0.4)], 0, 0.3, 0.3)),
XLine.kr(Rand(4000,5000), Rand(2500,3200), 1)
) * Linen.kr(Trig1.kr(Impulse.kr(0), time), 0.01, 0.7, 0.3, doneAction: Done.freeSelf);
OffsetOut.ar(out, Pan2.ar(z, pan, amp));
}, [\ir]).add;
)
(
a = [-7, -1, 0, 2, 1, 5, 4, 8, 5, 6].collect { |degree|
Synth.newPaused(\defaultP, [freq: (degree.degreeToKey(Scale.major) + 60).midicps]);
};
b = Buffer.sendCollection(s, a.collect(_.nodeID), 1);
~dummy = { Silent.ar(1) }.play;
)
(
c = { |bufnum, neutralID|
var trig = Dust.kr(1.5); // here's the server-side trigger
var num = BufFrames.kr(bufnum);
var idSource = Demand.kr(trig, 0, Dbufrd(bufnum, Dseries(0, 1, num), loop: 0));
var stop = FreeSelfWhenDone.kr(idSource);
var id = Select.kr((trig > 0), [neutralID, idSource]);
[trig, id].poll(trig); // can remove, just for display
Pause.kr(trig, id);
}.play(outbus: 1000, args: [bufnum: b, neutralID: ~dummy.nodeID]);
)
~dummy.free; b.free;
// in case something broke, stop the others here
a.do(_.free); c.free;
The ~dummy
node is necessary because Pause
will pause that node ID when trig
becomes 0. In early tests, I found it was easy to pause node 0, in which case, everything dies. So we give it something else to pause without doing any damage.
If you want the process to run indefinitely, you could have c
do a SendReply
to have the client generate more paused nodes and update part of the buffer that isn’t being used at that moment. (Also delete var stop
.) I’m afraid I won’t have time to work that out for you, though. This is as far as I can take this for now.
hjh