You would think so, but that’s not actually the case.
(
r = Routine {
inf.do { |count|
[thisThread.beats, count.asInteger].postln;
1.0.wait;
}
};
)
// play the routine multiple times "in parallel"
(
var nextBeat = TempoClock.beats.roundUp;
4.do { |i|
r.play(quant: [nextBeat, 0.25 * i]);
};
)
[ 186.0, 0 ] -- first time scheduled
[ 186.25, 1 ] -- second time scheduled
[ 186.5, 2 ] -- third time
[ 186.75, 3 ] -- fourth time
[ 187.0, 4 ] -- first time scheduled, 1 beat later
[ 187.25, 5 ] -- etc
[ 187.5, 6 ]
[ 187.75, 7 ]
r.stop;
That’s not parallel exactly. Based on the way the Routine is written, you would expect the counter to increment by one for each beat. But when used this way, it increments four times per beat.
True parallel streams have to be separate streams.
(
// a function to make a new Routine
r = {
Routine {
inf.do { |count|
[thisThread.beats, count.asInteger].postln;
1.0.wait;
}
}
};
)
// play 4 routines "in parallel"
(
var nextBeat = TempoClock.beats.roundUp;
t = Array.fill(4, { |i|
r.value.play(quant: [nextBeat, 0.25 * i]);
});
)
[ 468.0, 0 ]
[ 468.25, 0 ]
[ 468.5, 0 ]
[ 468.75, 0 ]
[ 469.0, 1 ]
[ 469.25, 1 ]
[ 469.5, 1 ]
[ 469.75, 1 ]
t.do(_.stop);
This idea has come up a couple of times lately – that routines “can be played multiple times” while tasks cannot, concluding that routines are more flexible – but the actual behavior of playing the same routine multiple times is probably not what you want.
Both Routines and Tasks take a quant argument when play
ed.
For the most common cases, there’s no significant difference (except that Tasks protect you from making the multiple-scheduling mistake).
When you get up to more exotic cases, such as rescheduling a thread for a different time without interrupting it – you can reschedule a routine for a later time but not an earlier time. Task/PauseStream can reschedule in either direction.
Latency: Scheduling and Server timing | SuperCollider 3.12.2 Help
// runs on the next hardware buffer boundary
// timing in a sequence may be unreliable
a = Synth(\default);
// runs at a scheduled time -- better timing in sequences
s.bind { a = Synth(\default) };
// runs at a scheduled time -- better timing in sequences
(instrument: \default, freq: 440).play;
Also, for me, the fact that events automatically release the note is a big plus.
hjh