Timelines
A Timeline
schedules and executes events following a clock.
By default, a Timeline creates its own internal clock at a specified tempo:
timeline = iso.Timeline(120)
timeline.run()
You can set and query the tempo using the tempo
property:
>>> timeline.tempo = 140
>>> print(timeline.tempo)
140
Sync from clock in
A Timeline can be synchronised from an external MIDI clock:
midi_in = MidiInputDevice()
timeline = iso.Timeline(clock_source=midi_in)
timeline.run()
MIDI start
and stop
events will be followed. Querying the timeline's tempo
will give an estimate of the current bpm based on a moving average.
Sync to clock out
You can also drive external MIDI clocks from a Timeline, by specifying the send_clock
argument when creating the output device.
output_device = iso.MidiOutputDevice(send_clock=True)
timeline = iso.Timeline(120, output_device=output_device)
timeline.run()
Scheduling events
Scheduling events is done by passing a dict to the Timeline.schedule()
method, which creates a new Track
on the timeline. A timeline can have an unlimited number of tracks (unless you specify a limit with the max_tracks
property).
#--------------------------------------------------------------------------------
# Play a series of 5 notes with random velocities.
# Delay by 1 beat before playback.
#--------------------------------------------------------------------------------
timeline = iso.Timeline(120)
timeline.schedule({
"note": iso.PSequence([ 60, 67, 72, 77, 84 ], 1),
"duration": 0.5,
"amplitude": iso.PWhite(0, 128)
}, delay=1)
timeline.run()
Scheduling can be quantized or delayed by passing args to the schedule()
method:
quantize=N
: quantize to the nextN
beats before beginning playback. For example,quantize=1
will quantize to the next beat.quantize=0.25
will quantize to a quarter-beat.delay=N
: delay byN
beats before beginning playback. Ifquantize
anddelay
are both specified, quantization is applied, and the event is scheduleddelay
beats after the quantization time.sel_track_idx=N
(optional): When utilizing multitrack output, this parameter enables the selection of the MIDI track to which a specific event needs to be assigned.
To limit the number of iterations of an event, pass the count
property:
timeline.schedule({
"note": iso.PSeries(0, 1) + 60
}, count=4)
Clock resolution and accuracy
isobar-ext's internal clock by default has a resolution of 480 ticks per beat (PPQN), which equates to a timing precision of 1ms at 120bpm.
High-precision scheduling in Python is inherently limited by Python's global interpreter lock (GIL), which means that sub-millisecond accuracy is unfortunately not possible. The good news is that, when using Python 3+, jitter is pretty low: the unit test suite verifies that the host device is able to keep time to +/- 1ms, and passes on Linux and macOS.
Nonlinear time
Time warping and nonlinear time is a work in progress.