LinkClock is a TempoClock based on Ableton Link, a protocol that synchronizes phase (beat-within-bar) and tempo over a local network.
Link attempts, as much as possible, to allow applications to move in their own time while synchronizing:
Link does not synchronize exact beat numbers. Two SuperCollider peers joining the same Link session, in 4/4 time, may be respectively at beats 4 and 16 (which are both barlines), but they should not be at beats 4.0 and 19.0.
Many Link-enabled applications (DAWs) can start and stop the entire timeline. SuperCollider clocks do not stop. A DAW, when starting to play, should lock into SuperCollider's phase within the bar. You can register functions to respond to other peers starting or stopping. (SuperCollider does not know which other peer started or stopped.)
Link coordinates the sounding time of given beats.
All audio applications must prepare events, and audio processing, in advance, so that the signal hits the audio interface at the right time. SuperCollider uses OSC timestamps for this purpose, calculating timestamps from the current time in seconds + a latency
offset.
To coordinate with other applications, then, the LinkClock
must run earlier than the desired sounding time, by the same fixed offset. That is, it should have the same (positive) latency offset as the server:
Server messages should then be sent with the same amount of latency. Events generated by patterns automatically apply the server object's latency. For other messages, use Server: -makeBundle.
With a positive latency, if you examine t.beats
, it will appear to be later than the beats shown in other applications. This is normal. The clock in SuperCollider must run early for the events to sound on time.
(Because the clock and server have separate latency settings, it is possible to adjust timing relative to other applications. If you find, for instance, that SuperCollider is sounding slightly late, you can increase the LinkClock's latency slightly, moving the clock earlier, without affecting messaging latency. Ideally, this should not be necessary, but inter-application coordination can be fiddly.)
This does have an impact on tempo changes. SuperCollider receives tempo changes from other peers only after they are sent, which is probably slightly late for our clock. In practice, it means that events falling within the latency gap may be slightly out of sync, but sync should recover very quickly. (So, Link is not ideal for music involving frequent tempo or meter changes.)
For every moment in time, Ableton Link knows the beat, time in seconds, and phase. Phase is measured relative to a quantum. Link peers sharing the same quantum will synchronize barlines.
For instance, assume quantum = 4. Peer A is currently at beat 33. Peer B joins the network. Peer A's last barline was beat 32, so phase = 1. Peer B's beat counter should arrange to have the same phase: in practice, it will start with -3.
Phase | Peer A beats | Peer B beats | Notes |
0 | 32 | -- | |
1 | 33 | -3 | Link calculates -3 for B |
2 | 34 | -2 | |
3 | 35 | -1 | |
0 | 36 | 0 | Barline (synced) |
If you change the quantum, Link does not guarantee that beats will keep the same duration. Beats may be shorter or longer, to try to preserve phase sync.
Therefore, you should not change the quantum in the middle of a performance. Ableton recommends to set the quantum just before beginning. Then, you can change SuperCollider's beatsPerBar
as needed, without changing the quantum, so that Link's phase reference remains consistent.
SuperCollider peers may optionally synchronize barlines and all meter changes by using LinkClock: -enableMeterSync. This is independent of Link's quantum, and is safe to use mid-performance. See MeterSync.
A LinkClock's state may be changed by other connected Link peers. LinkClock uses dependant notifications to relay the new state to other interested objects.
Notification | Event |
\tempo | Tempo changed |
\meter | The clock's beatsPerBar changed |
\linkStart | An external peer started playback |
\linkStop | An external peer stopped playback |
\numPeers | The number of connected peers changed |
\resynced | After -enableMeterSync, a \resynced notification is sent whenever a MeterSync: -resyncMeter call finishes successfully. One Boolean argument is passed: true if other SuperCollider peers were found, false if not. |
(Note that Link does not synchronize meter across peers; this notification is inherited from TempoClock. LinkClock: -isSyncingMeter is a SuperCollider-specific way to synchronize meter; it is not part of the Link protocol.)
The most convenient way to register to receive a notification is SimpleController. See the examples below.
Creates a new instance of LinkClock.
tempo |
The initial tempo. Defaults to |
beats |
The time in beats, corresponding to the reference time. Default to |
seconds |
The reference time in seconds. See TempoClock: *new. |
queueSize |
The storage size of the scheduling queue. See TempoClock: *new. |
If an existing Link session is found on the local network, the object connects to it and use its properties: the tempo
argument is discarded in favor of the session tempo, and the beat
argument will be adjusted to ensure proper beat and phase synchronization across all peers. If SuperCollider is the first to join, a new Link session is locally created and initialized with the constructor arguments.
Creates a new instance of LinkClock derived from a TempoClock.
clock |
The TempoClock used to create the LinkClock. |
The LinkClock tempo, beats, seconds and beatsPerBar values are set to those of the TempoClock. The TempoClock is then stopped and all of its tasks are rescheduled by the newly created LinkClock, so that they are now synchronized with the Link session.
Gets or sets the number of seconds of OSC messaging latency for which the LinkClock
should account. In general, this should be set to match the server object's latency.
lat |
A Float. |
Sets or gets the current session tempo at the current logical time. Note that the tempo may be changed at any time by another peer; the LinkClock broadcasts a \tempo
notification in this case (see LinkClock: Notifications).
Sets or gets the current logical time in beats. If you are trying to set the beats, Link may adjust your given value to maintain sync with other peers.
Gets the number of peers connected to the current Link session. When peers join or leave the session, the LinkClock broadcasts a \numPeers
notification (see LinkClock: Notifications).
Gets or sets Link's internal quantum (see above, beatsPerBar and quantum). Normally this should be done at the beginning of a performance, or not at all. It is risky to change quantum during a performance. Changing meter locally is the same as in TempoClock: TempoClock: -beatsPerBar.
quantum |
An Integer or Float. |
Activates SuperCollider-barline sync by creating a MeterSync object internally. (If already enabled, no new object will be created.)
id |
Optional: An integer ID, uniquely identifying this instance. If not provided, one will be chosen randomly. |
ports |
Optional: An array of port numbers, to which barline-sync messages will be sent. |
The LinkClock instance (to support chaining configuration methods, e.g. l = LinkClock.new.latency_(s.latency).enableMeterSync
, in which case you want l
to be the clock object). To get access to the MeterSync object, use -getMeterSync.
Remove all barline-sync objects.
A Boolean, true
if barline sync is active, false
if not. (If you create the barline sync object independently, this answer is likely to be incorrect.)
The MeterSync object previously created by -enableMeterSync.
clock.enableMeterSync
and m = SCClockMeterSync(clock)
. getMeterSync
has access only to the object created by clock.enableMeterSync
. Therefore, it is recommended to use clock.enableMeterSync
in all cases.