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