TimeSpec


Objects for implementing more flexible quantized scheduling using TempoClock-play. Applies to any object that plays using TempoClock (such as Pbind).


NilTimeSpec -- always schedules for now.

BasicTimeSpec -- like standard scheduling: quant, phase, timing offset (see Quant).

AbsoluteTimeSpec -- schedules for a specific, precalculated beat number. This time spec is valid until the given time passes; once the clock's beat counter goes past that time, an error will be thrown.

AbsoluteTimeSpecLeadTime -- for use with BP in chucklib, and subtracts the leadTime of the process from the given time. See the [BP] help file for details.

DelayTimeSpec -- schedules for the given number of beats from now. You can give a pattern instead of a constant number for a different delay on each call.

DelayTimeSpecLeadTime -- subtracts the lead time from the delay.


Most of the time, you will use BasicTimeSpec. The Nil, Absolute and Delay TimeSpecs are provided for cases when one process has to schedule events on the same clock that it's using. In that case, "now" is a meaningful reference. This is not true when you're starting a process interactively in the interpreter or from an external control.


The following time spec objects have been deprecated. They still exist, but their behavior has been rolled up into BasicTimeSpec. If your code uses them, you'll see a deprecation warning but the behavior should not have changed. (There is one exception: QuantOffsetLatencyWrapTimeSpec did not prove to be useful so its behavior is no longer available.)


QuantOffsetTimeSpec -- like Basic, but adds an offset to the next multiple

QuantOffsetLatencyTimeSpec -- takes server-side latency into account; latency is in beats (not seconds)

QuantOffsetLatencyWrapTimeSpec -- takes latency into account; if the latency pushes the onset before the current time, it will be scheduled for (quant) beats later


- A single TimeSpec object can be shared among multiple processes (see especially BP in the chucklib addon, where a TimeSpec can be stored in the ~quant variable). If you change the instance variables of the time spec without replacing the object, you can change the quantization of multiple processes simultaneously.


Usage:

asTimeSpec should be implemented for every type of object that should be able to be converted into a TimeSpec by playing a process. Current implementations are:


nil --> NilTimeSpec

quant --> NilTimeSpec if 0, BasicTimeSpec otherwise (compatibility with standard syntax)

[quant, offset] --> BasicTimeSpec

[quant, offset, latency] --> BasicTimeSpec


Example:


SynthDescLib.global.read;

c = Pbind(\freq, Pseq(#[5000, 2500, 2500, 2500], inf), \delta, 1, \legato, 0.01, \instrument, \default);

p = Pbind(\freq, Pfunc({ rrand(200, 800) }), \delta, 0.25, \legato, 0.6, \instrument, \default);


c.play(quant: 4); // start a metronome


e = p.play(quant: nil); // not synced with metronome

e.stop;


e = p.play(quant: 4); // synced -- this is standard SC play syntax, so no old stuff is broken

e.stop;


e = p.play(quant: BasicTimeSpec(4));

e.stop;


[4, 2].asTimeSpec.dump;


e = p.play(quant: [4, 2].asTimeSpec); // synced, on "beat 3 of the measure"

e.stop;


// cmd-. to stop metronome


Extensibility:


You can write your own TimeSpecs. They need to respond to nextTimeOnGrid(clock) and return the absolute number of beats when the event should be scheduled (suitable for TempoClock-schedAbs). See the class definitions for the above timespecs for examples of how to do it. For chucklib compatibility, you should also implement bpSchedTime(bp), which gets the next time on grid and subtracts the input process's lead time. The BP process is passed into bpSchedTime so that any values in the BP object can be used to calculate the scheduling time.