sc3.base.clock module

Clock.sc

exception ClockError

Bases: RuntimeError

exception ClockNotRunning

Bases: sc3.base.clock.ClockError

class MetaClock

Bases: type

play(task, quant=None)

Schedule a Routine or Function to be evaluated in this clock.

If the return value of functions or yield value of routines is int or float the task will be rescheduled using that value as delta. This method shares semantics with other objects play methods that use clocks to schedule tasks.

Parameters
  • task (Routine | Function) – Task to be scheduled. If the argument is a common function it will be wrapped into a Function object to be scheduled.

  • quant (Quant) – A Quant object or a any value that can be cast into one with the Quant.as_quant constructor. This parameter only works for TempoClock and is ignored by other clocks.

property mode

Return the rt/nrt mode flag of the clock.

property seconds

Return the logial time of the current time thread.

property beats

Return the tempo dependent logial time of the current time thread.

beats2secs(beats)

Convert beats to seconds of the current time thread.

secs2beats(secs)

Convert seconds to beats of the current time thread.

beats2bars(beats)

Return the number of bars corresponding to the amount of beats.

bars2beats(bars)

Return the number of beats corresponding to the amount of bars.

time_to_next_beat(quant=1)

Return the duration remaining until the next beat.

class Clock

Bases: object

class MetaSystemClock(*_)

Bases: sc3.base.clock.MetaClock

class SystemClock

Bases: sc3.base.clock.Clock

Clock running on separate accurately timed thread. Singleton class object.

This is the default clock of the library, it’s an accurate scheduler based on physical time with support for routines’ logical time but without tempo control.

Note

SystemClock and TempoClock should be used only for sequencing musical tasks. Any resource intensive task that blocks the execution of the clock’s thread long enough will cause dispatch timing issues. Thus, are not recommended for tasks like GUI updates or similar, for those cases use AppClock.

classmethod elapsed_time_to_osc(elapsed: float) → int

Convert elapsed time in seconds to OSC timetag format.

classmethod osc_to_elapsed_time(osctime: int) → float

Convert time in OSC timetag format to elapsed time in seconds.

classmethod osc_time() → int

Return elapsed time as OSC timetag.

classmethod clear()

Remove all pending tasks from the scheduler queue.

classmethod sched(delta, item)

Schedule a new task item to be evaluated after delta seconds from current elapsed time.

classmethod sched_abs(time, item)

Schedule a new task item to be evaluated at a time point in the future relative to elapsed time.

class Scheduler(clock, drift=False, recursive=True)

Bases: object

play(task, quant=None)
sched(delta, item)
sched_abs(time, item)
clear()
empty()
advance(delta)
property seconds
class MetaAppClock(*_)

Bases: sc3.base.clock.MetaClock

class AppClock

Bases: sc3.base.clock.Clock

Low priority scheduler compatible with SystemClock and TempoClock. Singleton class object.

Note

Wait time drifts cumulatively when used for periodic tasks.

Note

This clock is meant to be a low priority scheduling thread, compatible with SystemClock and TempoClock, with no support for logical time. Because Python doesn’t supports threading priority it is not actually low priority but its still used for deferring non time critical tasks. Low level implementation may change in the future.

classmethod clear()

Remove all pending tasks from the scheduler queue.

classmethod sched(delta, item)

Schedule a new task item to be evaluated after delta seconds from current elapsed time.

class ClockScheduler

Bases: object

run()
add(time, clock_task)
reset()
class ClockTask(beats, clock, task, scheduler)

Bases: object

class Quant(quant: int = 1, phase: float = 0.0)

Bases: tuple

Quantization object used as argument to TempoClock’s play method.

Using Quant routines can be scheduled to the next beat or bar of the running clock. For example, to schedule a routine to the next beat use Quant(1) or, to schedule it to the next bar of the running clock use Quant(clock.beats_per_bar).

To schedule a routine to a specific beat or fraction within a bar use the phase argument. If phase is positive the routine will be scheduled to the specified beat of the next bar and if phase is negative it will be scheduled to the next specified beat within the current or next bar depending on whether the current beat is before or after the specified beat.

Setting the quant argument to zero avoids quantization.

Parameters
  • quant (int) – Quantization unit in beats. This value must be a positive number or zero, floats will be rounded up.

  • phase (int | float) – Offset from the quantization unit between -quant and quant.

Notes

To set the quantization guaranties logical time synchronicity between routines running in the same TempoClock.

def r(name, note):
    def _(inval):
        rout, clock = inval
        while True:
            if int(clock.beat_in_bar()) == 0:
                # Print logical time in beats and seconds.
                print(name, clock.beats, clock.seconds)
                play(midinote=note - 12, dur=0.3)
            else:
                play(midinote=note, dur=0.1)
            yield 1
    return _

a = Routine(r('routine A:', 60))
b = Routine(r('routine B:', 67))

clock = TempoClock()

# Both routines will start in sync at the next bar.
a.play(clock, Quant(clock.beats_per_bar))
b.play(clock, Quant(clock.beats_per_bar))

Create new instance of Quant(quant, phase)

quant: int

Alias for field number 0

phase: float

Alias for field number 1

classmethod as_quant(quant)

Return a Quant object from the value of quant.

The received object can be an int or float representing the quant paramenter or a length two collection representing quant and phase parameters. If the received object is None a Quant object with default values is created.

This method is used internally to convert the type of valid Quant’s constructor parameters values.

class MetaTempoClock(*_)

Bases: sc3.base.clock.MetaClock

property all
stop_all()
class TempoClock(tempo=None, beats=None, seconds=None)

Bases: sc3.base.clock.Clock

Tempo based scheduler.

TempoClock is a scheduler like SystemClock, but it schedules relative to a tempo in beats per second.

Parameters
  • tempo (int | float) – The initial tempo. Defaults to 1.

  • beats (int | float) – The time in beats, corresponding to the reference time given with the seconds argument. Defaults to 0.

  • seconds (int | float) – The reference time in seconds, to which the beats argument corresponds. Defaults to the current Thread’s logical time.

Notes

The TempoClock will be created as if it started counting beats at the time given in the seconds argument with the starting amount given in the beats argument. The current count of beats will thus be equal to that starting amount plus the amount of beats that would be counted since the given reference time in seconds, according to the given tempo.

The default arguments create a TempoClock that starts counting beats with 0 at the current logical time.

@routine.run()
def example(inval):
    _, clock = inval
    print('the example is running in SystemClock:', clock is SystemClock)
    # Starts from zero by default.
    t = TempoClock(1)
    print('current beats:', t.beats)
    # Starts counting beats from 5.
    t = TempoClock(1, 5)
    print('current beats:', t.beats)
    # Counting beats as if it started 5 seconds ago from 0.
    t = TempoClock(1, 0, clock.seconds - 5)
    print('current beats:', t.beats)

# Use CmdPeriod afterwards to stop all created TempoClocks.
# CmdPeriod.run()

If the above example was run without a souronding routine the actual beats value will not be precise. When running in real time, the base time reference is physical time and every call that requires current time is relativelly synced to it. The same happens in sclang when each instruction is evaluated separatelly, the difference is that sclang updates the base time only once per intepreter call which is not possible to do in a Python library.

mode = 0
stop()

Stop the clock’s scheduling thread.

Note

TempoClock objects need to be stopped in order to be gc collected.

play(task, quant=None)

Schedule a Routine or Function to be evaluated in this clock.

If the return value of functions or yield value of routines is int or float the task will be rescheduled using that value as delta. This method shares semantics with other objects play methods that use clocks to schedule tasks.

Parameters
  • task (Routine | Function) – Task to be scheduled. If the argument is a common function it will be wrapped into a Function object to be scheduled.

  • quant (Quant) – A Quant object or a any value that can be cast into one with Quant.as_quant constructor.

play_next_bar(task)

Schedule a Routine or Function to be evaluated at the next bar.

property tempo

Return the tempo in beats per second at the current logical time.

etempo(value)

Set the current tempo at the current elapsed time.

Warning

Using this method tempo can be negative and beats will go backguard. This behaviour will cause default scheduling mechanisms to fail.

property beat_dur

Beat duration in seconds.

elapsed_beats()

Return the beats for this clock relative to main elapsed time.

beats = 2.663724899291992
seconds = 2.664196014404297
sched(delta, item)

Schedule a new task item to be evaluated after delta beats from current clock’s beat.

sched_abs(beat, item)

Schedule a new task item to be evaluated at a beat point in the future relative this clock’s current beat.

clear()

Remove all pending tasks from the scheduler queue.

property beats_per_bar

Number of beats grouped as a measure, default is 4.

Get or set the beats per bar for quantization. When setting this property, the reference base_bar_beat value will be set to whatever beat fraction is at that time within the scheduled time thread, i.e., the new bar will start at that time and may truncate the previous one.

Note

This value should only be changed from within the scheduling thread of the same clock, otherwise a ClockError will be thrown.

property base_bar

Return the bar at which beats_per_bar was last changed.

If beats_per_bar has not been changed since the clock was created return 0.0.

property base_bar_beat

Return the beat at which the beats_per_bar was last changed.

If beats_per_bar has not been changed since the clock was created it returns 0.0.

beats2secs(beats)

Convert beats to seconds of the current time thread.

secs2beats(seconds)

Convert seconds to beats of the current time thread.

dump()

Print the state of the clock for debugging purposes.

next_time_on_grid(quant=1, phase=0, refbeat=None)

Return the next quantized beat.

Quantization rounds the reference beat to the next integer multiple of quant. If refbeat is None it will be set to the current beat of this clock counting from the last beats_per_bar change.

Parameters
  • quant (int) – Quantization unit applied to refbeat. This value must be a positive number or zero, floats will be rounded up.

  • phase (int | float) – Offset from the quantization unit between -quant and quant.

  • refbeat (int | float) – Reference beat for the quantization. If None the current value of this clock’s beats is used.

Notes

With default values for quant, phase and refbeat it returns the next whole beat. The quant parameter is relative to base_bar_beat, such that

clock = TempoClock()
clock.next_time_on_grid(clock.beats_per_bar) == clock.next_bar()

Together quant and phase are useful for finding the next n beat in a bar, e.g. clock.next_time_on_grid(clock.beats_per_bar, 2) may return the next third beat of the current or next bar depending on whether the current beat is before or after the third beat of the current bar, whereas if refbeat = clock.next_bar() refbeat - 2 may return an elapsed beat and refbeat + 2 will always return the third beat of the next bar only.

time_to_next_beat(quant=1)

Return the duration remaining until the next beat in logical time.

The quant parameter is relative to base_bar_beat.

beats2bars(beats)

Return the bar number relative to base_bar_beat.

bars2beats(bars)

Return the number of beats relative to base_bar.

bar()

Return the current bar number.

next_bar(beat=None)

Given a beat number, return the beat number of the next bar line.

If beat is the start beat of a bar return the same number.

beat_in_bar()

Return the current beat of the bar as a float.

Range is from 0 to < beats_per_bar.

running()

Return True if the clock is running.

defer(func, delta=None, clock=None)

Convenience function to defer lambda functions on a clock without creating a Routine or sched call. Default value for delta is 0.0, default clock is AppClock. Argument func can be any callable.