I thought it might be good to add some remarks about scheduling behavior.
TempoClock.sched(1, { "oh hi".postln });
sched
takes now and adds the given number of beats (call it ‘time’), then puts the function/routine/task/event stream player into the clock’s queue at ‘time’.
When ‘time’ arrives, that “thing” gets popped out of the queue, and awake
is called on it. Since this example uses a function: Function’s awake
method just evaluates the function, passing in some time information. So it prints oh hi
.
At this point, the return value is important. If it’s not a number, then it stops here. If it is a number, then a new time is calculated = now + that number, and the same thing gets put back into the queue at the new time. (“Return value” for a routine/task is the wait
or yield
value. For an event pattern like Pbind, it’s .delta
on the event.)
SC’s timing is oriented towards time deltas, not toward metrical position.
So let’s take that 1.02 example, and call the reference barline 0.
- Awake at 0, reschedule for 1.02.
- Awake at 1.02, reschedule for 2.04.
- Awake at 2.04, reschedule for 3.06.
- Awake at 3.06, reschedule for 4.08.
But to re-sync for the bar line, you need 4.00, not 4.08.
So the pattern’s natural timing must be interrupted.
A key fact about scheduling is that there is no way to un-schedule anything: once it goes into the queue, it will awake
. So in the original event stream player is going to wake up at 4.08. (How, then, does anything stop? The state of the object may be changed so that it does nothing upon awake
.)
So to re-jigger the time, it’s necessary to deactivate the old event stream player, and schedule a new one for 4.0.
This is exactly what Pdef
does when you replace the entire source pattern. It’s an all-new pattern, so it can’t use the old stream player – must deactivate it (one part of rescheduling) – and it must make a new one, which it’s free to schedule at a different time. So this (by luck!) happens to do both of the things that are needed for rescheduling.
Pbindef has a different purpose: to keep some of the streams running continuously, while replacing others.
For the unchanged streams to run continuously, it has to keep going with the same event stream player. So it does not automatically deactivate the old and replace it. So, under “natural” usage, there is no way for Pbindef to reschedule.
So the purpose of my code examples from yesterday was to force a new stream player to be scheduled on the bar line, while pulling data from a Pbindef.
For this, there are two possible cases:
-
Maybe you want everything in the Pbindef to reset to the beginning. For kick and hi-hat, this is probably enough – if the other parameters are constant values, you can’t tell the difference between resetting and continuing. That’s my \kik and \k example.
-
Or, maybe you want only the timing to go back to the bar line, while other streams keep going, unaffected. For instance, in an arpeggiator, you might want to change the rhythm but not break the note pattern. This is where it gets complicated, because you need to isolate the non-resetting data streams away from the timing stream.
- Maybe you don’t need this yet, in which case, you could safely forget about that longer example.
- Or maybe you do need it, in which case… just be prepared: with the main pattern library, this is never going to be as easy as you want it to be.
hjh