Link

clocks

the clock library provides a way to create timed function calls: loops, repetition, and delays. synchronization is possible and time base can come from a variety of sources. the clock library uses lua coroutines.

curious to see it all work together in realtime? here’s an introduction to working with clocks + softcut:

commands

  • id = clock.run( func ) — start a new coroutine with function func. returns id
  • clock.cancel( id ) — cancel coroutine id
  • clock.sleep( time ) — resume in time seconds
  • clock.sync( beats ) — resume at beats count according to global tempo
  • beats = clock.get_beats() — returns current time in beats
  • tempo = clock.get_tempo() — returns current tempo
  • beat_sec = clock.get_beat_sec() — returns length of a single beat at current tempo in seconds

callbacks

these functions can be script defined and are called by system events:

  • clock.transport.start — called by transport start
  • clock.transport.stop — called by transport stop

use

simple delay

clock.run starts a new coroutine with the function you provide:

function init()
  print("starting now")
  clock.run(later)
  print("done with init")
end

function later()
  clock.sleep(2)
  print("now awake")
end

when executed, you will see starting now, done with init, (two seconds delay and then): now awake. clock.run starts a coroutine with the function later. this function immediately sleeps for two seconds, which means the init function resumes and finishes before later is able to print its output.

repetition and sync

you can sleep according to units of tempo (beats) by using clock.sync instead of clock.sleep.

engine.name = 'PolyPerc'

function strum()
  for i=1,8 do
    clock.sync(1/4)
    engine.hz(i*100)
  end
end

function key(n,z)
  if n==3 and z==1 then
    clock.run(strum)
  end
end

this script starts a new coroutine when K3 is pressed. the strum function plays eight notes, sleeping for 1/4 of a beat (= 1/16th note in 4/4) between notes, synced to the global tempo.

you can change the global tempo using parameters via command or menu. see the later section.

arguments

pass arguments to a clock function by appending them within the clock.run call:

engine.name = 'PolyPerc'

function strum(n,speed)
  for i=1,n do
    clock.sync(1/speed)
    engine.hz(i*100)
  end
end

function key(n,z)
  if n==3 and z==1 then
    clock.run(strum, math.random(16), math.random(8))
  end
end

now each strum is executed with different arguments. note that you can overlap multiple runs by pressing the key rapidly! a new coroutine is started with each run, so you can have numerous processes running at once.

clock.sync sleeps until the next subdivision specified arrives, so the timing is effectively quantized to the global tempo (which is the goal of this use case).

loop

so far all of our coroutines end by themselves, by reaching the end of their own execution. we can create forever-running loops using a while true inner loop. these will continue running until you launch a new script or cancel them manually with clock.cancel.

to cancel a coroutine, you need to store the id generated by clock.run. we later use this id with clock.cancel.

engine.name = 'PolyPerc'

function forever(freq)
  while true do
    clock.sync(1/4)
    engine.hz(freq)
  end
end

function init()
  clock_id = clock.run(forever, 220)
end

function key(n,z)
  if n==3 and z==1 then
    clock.cancel(clock_id)
  end
end

multiples

you can run lots of coroutines at once: up to 100.

in this script we capture ids using a table so we can cancel them in the future.

engine.name = 'PolyPerc'

function forever(freq,rate)
  while true do
    clock.sync(1/rate)
    engine.hz(freq)
  end
end

function init()
  voice = {}
  voice[1] = clock.run(forever,333,3)
  voice[2] = clock.run(forever,666,1)
  voice[3] = clock.run(forever,999,2)
  voice[4] = clock.run(forever,111,0.33)
end

use maiden’s command line to cancel individual voices, eg clock.cancel(voice[3])

complex timing

multiple clock.sync and clock.sleep commands are allowed within the same function. this script creates a swing rhythm:

engine.name = 'PolyPerc'

function forever(freq)
  while true do
    clock.sync(2/3)
    engine.hz(freq)
    clock.sync(1/3)
    engine.hz(freq)
  end
end

function init()
  clock.run(forever,333)
end

query

you can query the current tempo, beats, and seconds-per-beat:

print(clock.get_tempo())
t = clock.get_beats()
softcut.loop_start(1,clock.get_beat_sec())

callbacks

scripts can define their own callback functions for transport start and stop:

engine.name = 'PolyPerc'

function pulse()
  clock.sync(1/4)
  engine.hz(333)
end

function clock.transport.start()
  print("we begin")
  id = clock.run(pulse)
end

function clock.transport.stop()
  clock.cancel(id)
end

remote start/stop events can be generated by link or external midi.

nb. from Ableton: Link currently provides tempo sync and a grid to which apps can align. In Live 9, there are no Song Position or Start/Stop messages sent via Link, nor can any other MIDI data be sent. In Live 10 the feature “Start Stop Sync” (which can be found Live’s Link/MIDI preferences) additionally shares Transport Start and Stop Commands.

parameters

the CLOCK menu is available in the PARAMETERS screen.

source

this sets the sync source for the global tempo.

  • internal sets norns as the clock source
  • midi takes any external midi clock via connected USB midi devices
  • link enables ableton link sync for the connecting wifi network
  • crow takes sync from input 1 of a connected crow device

link has a link quantum parameter to set the quantum size.

crow additionally has a crow in div parameter to specify the number of sub-divisions per beat.

the tempo parameter sets the internal and link tempos. this tempo will be automatically updated if set by an external source (midi, crow, or remote link device).

you can set the tempo in your script by the normal method of setting parameters:

params:set("clock_tempo",100)

out

clock signals can be transmitted via midi or crow.

midi out sets the port number (which midi device, via SYSTEM > DEVICES) on which to transmit.

crow out sets the output number, and also has a crow out div setting for beat subdivisions.