Just noticed something ā if you intend to play
the outer routine, then arg arrs
is incorrect.
(
r = Routine {
arg arrs = Array.rand(10, 48, 72).dup;
"I expect this to be an array of arrays:".postln;
arrs.postln;
}.play;
)
I expect this to be an array of arrays:
745.04022751
A routine/task/EventStreamPlayer thatās being played uses the threadās input value for the clock time. You arenāt allowed to use it for anything else.
If you want to pass arrays into the routine, then you can only use next
on it, not play
. But then your ?.wait
would be invalid, so I suspect this isnāt what you mean. (And then, you would have to be aware of how to pass in the second, third etc. values by nextInputValue = returnValue.yield
ā this is discussed in the pattern internals reference ā if youāre not clear on this, thenā¦ nowās not the time for this way.)
If you want to parameterize the arrs and play
the Routine, then you would have to wrap it in a function:
f = {
arg arrs = Array.rand(10, 48, 72).dup;
Routine {
...
}
};
Thenā¦ the further peculiarity is: If the requirement is to stream out one arrayās worth of notes, and in sequence, stream out the next, and so on, then the simplest way is: Donāt use an inner Routine at all.
Routine {
arg arrs = Array.rand(10, 48, 72).dup;
arrs.do {
arg arr;
arr.do {
arg midi;
Synth(\help_sinegrain, [\freq, midi.midicps]);
rrand(0.1, 1).wait;
};
// if you just use a nested loop,
// then the 'wait' problem here
// completely disappears!
}
}
That is, if possible, itās better to avoid complication ā fewer moving parts = fewer opportunities for bugs.
Jordanās approach is valid but assumes that all of the arrays will be running at the same time, which looks like a different requirement. (That one could be simplified a bit by using a predicate in CondVar.) BTW I can guess why Jordan went that way ā because, in the original problem statement, thereās not really a good reason to introduce an inner Routine unless you want concurrency.
If you want a sequence of phrases, and youāre absolutely sure you must have an independent inner player for each phrase (I doubt that itās necessary, but letās roll with it), probably the clearest way is with a thread-sync object like CondVar:
(
r = Routine {
var arrs = Array.rand(10, 48, 72).dup;
var cond = CondVar.new;
arrs.do {
arg arr;
Routine {
arr.do {
arg midi;
Synth(\help_sinegrain, [\freq, midi.debug("note").midicps]);
rrand(0.1, 1).wait;
};
cond.signalAll;
}.play;
cond.wait;
};
}.play;
)
That is, where āis there a possibility to get a signal or get notifiedā suggests passive receipt of an automatically generated signal, itās clearer IMO to produce the end-signal explicitly in the code (cond.signalAll
).
I did also work up a Task version using the automatic notifications, but this ends up being worse, because you still need the CondVar logic, just invoked indirectly rather than directly = more code = more confusing relationships = harder to maintain. So I wonāt even post that one.
hjh