scamp.session.Session

class scamp.session.Session(tempo: float = 60, default_soundfont: str = 'default', default_audio_driver: str = 'default', default_spelling_policy: SpellingPolicy | str | tuple = None, instruments: Sequence[ScampInstrument] = None, max_threads=200)[source]

Bases: Clock, Ensemble, Transcriber, SavesToJSON

A Session combines the functionality of a master Clock, an Ensemble, and a Transcriber. Since it’s a master Clock, it manages global tempo; since it’s an Ensemble, you use it to create and keep track of instruments, and since it’s a Transcriber, it allows you to transcribe and generate notation from what the instruments are playing. You can also use a Session to set up interactive callbacks for MIDI, OSC, mouse events, and keyboard events.

Parameters:
  • tempo – the initial tempo of the master clock

  • default_soundfont – the default soundfont used by instruments in this session. (Can be overridden at instrument creation.)

  • default_audio_driver – the default driver used by (soundfont) instruments to output audio. (Can be overridden at instrument creation.)

Methods

get_available_midi_input_devices()

Returns a list of available ports and devices for midi input.

print_available_midi_input_devices()

Prints a list of available ports and devices for midi input.

print_available_midi_output_devices()

Prints a list of available ports and devices for midi output.

register_keyboard_listener([on_press, ...])

Register a callback_function to respond to incoming keyboard events

register_midi_listener(...)

Register a callback_function to respond to incoming midi events from port_number_or_device_name

register_mouse_listener([on_move, on_press, ...])

Register a callback_function to respond to incoming mouse events

register_osc_listener(port, ...[, ip_address])

Register a callback function for OSC messages on a given address/port with given pattern

remove_keyboard_listener()

Remove a previously added keyboard listener.

remove_midi_listener(port_number_or_device_name)

Removes the midi listener with the given port_number_or_device_name

remove_mouse_listener()

Remove a previously added mouse listener

remove_osc_listener(port[, ip_address])

Remove OSC listener on the given port and IP address

run_as_server()

Hands this session off to a background thread that waits forever, so the calling thread stays free.

start_transcribing([...])

Starts transcribing everything played in this Session's (or by the given instruments) to a Performance.

Inherited Methods

add_instrument(instrument)

Adds an instance of ScampInstrument to this Ensemble.

apply_beat_length_function(function[, ...])

Drive this clock's beat_length from a function.

apply_rate_function(function[, ...])

Drive this clock's rate from a function.

apply_tempo_envelope(envelope[, truncate, loop])

Append the given TempoEnvelope onto this clock's internal tempo envelope, starting from the current beat.

apply_tempo_function(function[, ...])

Drive this clock's tempo (BPM) from a function.

bring_up_to_date()

Advance this clock's tempo_history to match where it currently is in scheduler time.

children()

Get all direct child clocks forked by this clock.

clock_to_scheduler_time(beat_or_time[, units])

Gets the time in the scheduler for a given beat or time in this clock, working recursively up the chain of clocks.

descendants()

Get all children, grandchildren, etc.

duplicate()

Returns a copy of this object by serializing to and from JSON.

extract_absolute_tempo_envelope([...])

Extract this clock's absolute tempo curve — its tempo as observed in master (scheduler) time, with parent rate-changes folded in.

fast_forward([on_or_off])

Turn indefinite fast-forwarding on or off.

fast_forward_in_beats(b)

Fast-forward, skipping ahead instantaneously by b beats.

fast_forward_in_time(t)

Fast-forward, skipping ahead instantaneously by t seconds.

fast_forward_to_beat(b)

Fast-forward, skipping instantaneously up to beat b on this clock.

fast_forward_to_time(t)

Fast-forward, skipping instantaneously up to time t (in seconds) on this clock, then resume real-time playback.

fork(forked_function[, args, kwargs, name, ...])

Spawns a child clock running forked_function as a coordinated parallel timeline.

get_available_midi_output_devices()

Returns an enumeration of available ports and devices for midi output.

get_instrument_by_name(name[, which])

Returns the instrument of the given name.

hold_scheduler()

Context manager that: 1) ensures that the scheduler is not executing scheduled actions — waiting if one is in flight, then preventing others from starting; 2) rouses the scheduler and updates its committed time to the current projected time.

inheritance([include_self])

Get all parent, grandparent, etc.

is_fast_forwarding()

Whether the clock is currently fast-forwarding.

is_master()

Check if this is the master clock

is_transcribing()

Checks if any transcriptions are in progress.

iterate_all_relatives([include_self])

Iterate through all related clocks to this clock.

iterate_descendants([include_self])

Iterate through all children, grandchildren, etc.

iterate_inheritance([include_self])

Iterate through parent, grandparent, etc.

json_dumps()

Dump this object as a JSON string.

json_loads(s)

Load this object from a JSON string.

kill()

End this clock (and the corresponding forked function if not master) and cascade to all descendant clocks.

load_from_json(file_path)

Load this object from a JSON file with the given path.

new_midi_part([name, midi_output_device, ...])

Creates and returns a new ScampInstrument for this Ensemble that uses a MIDIStreamPlaybackImplementation.

new_osc_part([name, port, ip_address, ...])

Creates and returns a new ScampInstrument for this Ensemble that uses a OSCPlaybackImplementation.

new_part([name, preset, soundfont, ...])

Creates and returns a new ScampInstrument for this Ensemble that uses a SoundfontPlaybackImplementation.

new_silent_part([name, ...])

Creates and returns a new ScampInstrument for this Ensemble with no PlaybackImplementations.

pop_instrument(index)

Pops the instrument at the given index, severing its ties to the ensemble.

print_default_soundfont_presets()

Prints a list of presets available with the default soundfont.

print_family_tree()

Print a hierarchical representation of this clock's family tree.

print_status([verbose])

Print this clock's status() snapshot.

projected_beat()

A wall-clock-interpolated estimate of beat.

projected_time()

A wall-clock-interpolated estimate of time, advancing smoothly between events rather than holding still between them.

register_note(instrument, note_info)

Called when an instrument wants to register that it finished a note, records note in all transcriptions

save_to_json(file_path)

Save this object to a JSON file using the given path.

schedule_action(action, when[, args, kwargs])

The lightweight alternative to fork() for immediately returning functions.

scheduler_to_clock_time(scheduler_time[, ...])

Gets beats or time in this clock for a given time in the scheduler.

set_beat_length_target(beat_length_target, when)

Smoothly change this clock's beat length (seconds per beat) to beat_length_target, arriving at the moment given by when.

set_beat_length_targets(beat_length_targets, ...)

Smoothly change this clock's beat length (seconds per beat) through a series of targets, building a multi-segment tempo curve in one call — the multi-segment form of set_beat_length_target().

set_rate_target(rate_target, when[, ...])

Smoothly change this clock's rate (beats per second) to rate_target, arriving at when.

set_rate_targets(rate_targets, whens[, ...])

Smoothly change this clock's rate (beats per second; the reciprocal of beat length, so a higher rate is a faster tempo) through a series of targets — the multi-segment form of set_rate_target().

set_tempo_target(tempo_target, when[, ...])

Smoothly change this clock's tempo to tempo_target, arriving at when.

set_tempo_targets(tempo_targets, whens[, ...])

Smoothly change this clock's tempo (beats per minute) through a series of targets — the multi-segment form of set_tempo_target(), and usually the most natural of the three equivalent plural setters.

status([verbose])

A snapshot of this clock's name and position, alongside the scheduler's elapsed wall time and how far behind schedule it is currently running.

stop_tempo_loop_or_function()

Stop following any function or looping envelope previously applied to this clock's tempo.

stop_transcribing([which_performance, ...])

Stops transcribing a Performance and returns it.

terminate_forked_children()

Kill this clock's children and their descendants in turn, returning once they have finished unwinding.

use_absolute_timing_policy()

Shorthand for timing_policy = 0.0 (always catch up to absolute schedule).

use_mixed_timing_policy(absolute_relative_mix)

Shorthand for timing_policy = absolute_relative_mix (a blend between 0=absolute and 1=relative).

use_relative_timing_policy()

Shorthand for timing_policy = 1.0 (always wait the full requested delay).

wait(duration[, units])

Block this clock for duration beats (or seconds, if units="time") from now, yielding to the scheduler.

wait_for_children_to_finish()

Block this clock's own thread until all of its child clocks have finished, yielding to the scheduler so they can run, then return as soon as the last child ends.

wait_for_clock_to_finish(clock)

Block this clock's own thread until clock has finished, yielding to the scheduler so it (and everything else) keeps running.

wait_forever()

Block this clock's own thread indefinitely, yielding to the scheduler so child clocks keep running.

wait_until(when[, units])

Block this clock until the beat (or time, if units="time") indicated by when — a convenience for absolute targets given as a bare number (equivalent to wait(Moment.at_beat(when)), or Moment.at_time for units="time").

Attributes

absolute_beat_length

Beat length in true seconds, with all parent rates folded in.

absolute_rate

Rate of this clock in beats / (true) second, with all parent rates folded in.

absolute_tempo

Tempo (BPM) in true minutes, with all parent rates folded in.

alive

True if this clock is currently running (PENDING and DEAD both return False).

beat

How many beats have passed since this clock was created.

beat_length

The length of a beat in this clock in seconds.

default_spelling_policy

Default spelling policy used for transcriptions made with this Ensemble.

instruments

Returns a tuple of the instruments currently in this Ensemble.

master

The master clock under which this clock operates (possibly itself)

precise_timing

Whether to use a busy wait in the final moments leading up to a scheduled event.

rate

The rate of this clock in beats / second.

spin_guard_duration

Width (seconds) of the busy-wait guard band used when precise_timing is on.

tempo

The rate of this clock in beats / minute Note that beat_length, tempo and rate are interconnected properties, and that by setting one of them the other two are automatically set in response according to the relationship: beat_length = 1/rate = 60/tempo.

time

How much time has passed since this clock was created.

timing_policy

How the family trades off relative vs. absolute timing, as a float from 0 to 1.

transcriptions_in_progress

Tuple of all current transcriptions.

run_as_server() → Session[source]

Hands this session off to a background thread that waits forever, so the calling thread stays free. This is the approach to take when driving scamp from an interactive terminal (REPL) session, where you want the prompt to stay responsive: simply type s = Session().run_as_server().

Note the tradeoff: once handed off, the calling thread no longer owns the session’s clock (its current_clock() becomes None), so subsequent work must be scheduled on the returned object explicitly — e.g. s.fork(...) — rather than through the context-inferring module-level helpers fork() and wait(). In a normal top-to-bottom script you don’t need this at all: the thread that creates the Session owns its clock, so just use wait/fork and, if you need to keep the process alive at the end, s.wait_forever().

Returns:

self

static get_available_midi_input_devices() → Iterator[tuple[int, str]][source]

Returns a list of available ports and devices for midi input.

static print_available_midi_input_devices() → None[source]

Prints a list of available ports and devices for midi input.

static print_available_midi_output_devices() → None[source]

Prints a list of available ports and devices for midi output.

register_midi_listener(port_number_or_device_name: int | str, callback_function: Callable) → None[source]

Register a callback_function to respond to incoming midi events from port_number_or_device_name

Parameters:
  • port_number_or_device_name – either the port number to be used, or an device name for which the port number will be determined. (Fuzzy string matching is used to pick the device with closest name.)

  • callback_function – the callback function used when a new midi event arrives. Should take either one argument (the midi message) or two arguments (the midi message, and the dt since the last message)

remove_midi_listener(port_number_or_device_name: int | str) → None[source]

Removes the midi listener with the given port_number_or_device_name

Parameters:

port_number_or_device_name – either the port number to be used, or an device name for which the port number will be determined. (Fuzzy string matching is used to pick the device with closest name.)

register_osc_listener(port: int, osc_address_pattern: str, callback_function: Callable, ip_address: str = '127.0.0.1') → None[source]

Register a callback function for OSC messages on a given address/port with given pattern

Parameters:
  • port – port on which to receive messages

  • osc_address_pattern – address pattern to respond to (e.g. “/gesture/start”)

  • callback_function – function to call upon receiving a message. The first argument of the function will be the address, and the remaining arguments will be those passed along in the osc message.

  • ip_address – ip address on which to receive messages

remove_osc_listener(port: int, ip_address: str = '127.0.0.1') → None[source]

Remove OSC listener on the given port and IP address

Parameters:
  • port – port of the listener to remove

  • ip_address – ip_address of the listener to remove

register_keyboard_listener(on_press: Callable = None, on_release: Callable = None, suppress: bool = False, **kwargs) → None[source]

Register a callback_function to respond to incoming keyboard events

Parameters:
  • on_press – function taking two arguments: key name (string) and key number (int) called on key down

  • on_release – function taking two arguments: key name (string) and key number (int) called on key up

  • suppress – if true, keyboard events are consumed and not passed on to other processes

remove_keyboard_listener() → None[source]

Remove a previously added keyboard listener.

register_mouse_listener(on_move: Callable = None, on_press: Callable = None, on_release: Callable = None, on_scroll: Callable = None, suppress: bool = False, relative_coordinates: bool = False, **kwargs) → None[source]

Register a callback_function to respond to incoming mouse events

Parameters:
  • on_move – callback function taking two arguments (x, y) called when the mouse is moved

  • on_press – callback function taking three arguments: (x, y, button), where button is one of “left”, “right”, or “middle”

  • on_release – callback function taking three arguments: (x, y, button), where button is one of “left”, “right”, or “middle”

  • on_scroll – callback function taking four arguments: (x, y, dx, dy)

  • relative_coordinates – if True (requires tkinter library), x and y values are normalized to screen width and height and are floating point. Otherwise they are ints in units of pixels.

  • suppress – if true, mouse events are consumed and not passed on to other processes

remove_mouse_listener() → None[source]

Remove a previously added mouse listener

start_transcribing(instrument_or_instruments: ScampInstrument | Sequence[ScampInstrument] = None, clock: Clock = None, units: str = 'beats') → Performance[source]

Starts transcribing everything played in this Session’s (or by the given instruments) to a Performance. Defaults to using this Session as the clock.

Parameters:
  • instrument_or_instruments – which instruments to transcribe. Defaults to all session instruments

  • clock – which clock to record on, i.e. what are all the timings notated relative to

  • units – one of [“beats”, “time”]. Do we use the beats of the clock or the time?

Returns:

the Performance we will be transcribing to

property absolute_beat_length: float

Beat length in true seconds, with all parent rates folded in. (Read-only property; the pre-1.1 clock.absolute_beat_length() spelling still works, with a DeprecationWarning.)

property absolute_rate: float

Rate of this clock in beats / (true) second, with all parent rates folded in.

(Read-only property. Before clockblocks 1.1 this was a method; the clock.absolute_rate() spelling still works, with a DeprecationWarning.)

property absolute_tempo: float

Tempo (BPM) in true minutes, with all parent rates folded in. (Read-only property; the pre-1.1 clock.absolute_tempo() spelling still works, with a DeprecationWarning.)

add_instrument(instrument: ScampInstrument) → ScampInstrument

Adds an instance of ScampInstrument to this Ensemble. Generally, creating of and instrument and adding it to an ensemble are done simultaneously via one of the “new_instrument” methods.

Parameters:

instrument – instrument to add to this ensemble

Returns:

self

property alive: bool

True if this clock is currently running (PENDING and DEAD both return False).

apply_beat_length_function(function: Callable, domain_start: float = 0, domain_end: float = None, duration_units: str = 'beats', truncate: bool = True, loop: bool = False, extension_increment: float = 2.0, **kwargs) → None

Drive this clock’s beat_length from a function. See apply_function() for the full parameter list (passed via **kwargs).

apply_rate_function(function: Callable, domain_start: float = 0, domain_end: float = None, duration_units: str = 'beats', truncate: bool = True, loop: bool = False, extension_increment: float = 2.0, **kwargs) → None

Drive this clock’s rate from a function.

apply_tempo_envelope(envelope: TempoEnvelope, truncate: bool = True, loop: bool = False) → None

Append the given TempoEnvelope onto this clock’s internal tempo envelope, starting from the current beat. With loop=True the envelope repeats indefinitely until stop_tempo_loop_or_function(). truncate first discards any tempo curve already projected past the current beat so the envelope begins cleanly from now.

apply_tempo_function(function: Callable, domain_start: float = 0, domain_end: float = None, duration_units: str = 'beats', truncate: bool = True, loop: bool = False, extension_increment: float = 2.0, **kwargs) → None

Drive this clock’s tempo (BPM) from a function.

property beat: float

How many beats have passed since this clock was created. Note that this is quantized to the scheduler’s event stream; for a live estimate when outside the clock system use projected_time().

(Read-only property. Before clockblocks 1.1 this was a method; the clock.beat() spelling still works, with a DeprecationWarning.)

property beat_length: float

The length of a beat in this clock in seconds. Note that beat_length, tempo and rate are interconnected properties, and that by setting one of them the other two are automatically set in response according to the relationship: beat_length = 1/rate = 60/tempo. Also, note that “seconds” refers to actual seconds only in the master clock; otherwise it refers to beats in the parent clock.

bring_up_to_date()

Advance this clock’s tempo_history to match where it currently is in scheduler time.

Called before mutating tempo from a foreign thread: if we don’t, the tempo setter’s truncate() cuts at the last committed beat (whatever the clock last woke at), causing the new tempo to retroactively reshape the segment the clock is currently napping through. From the owning thread this is a no-op since committed == current.

children() → Sequence[Clock]

Get all direct child clocks forked by this clock.

Returns:

tuple of all child clocks of this clock

clock_to_scheduler_time(beat_or_time, units='beats')

Gets the time in the scheduler for a given beat or time in this clock, working recursively up the chain of clocks.

Parameters:
  • beat_or_time – the beat or time of interest in this clock

  • units – one of (“beats”, “time”), determining the units for the first argument

Returns:

how much time should pass in the scheduler

property default_spelling_policy: SpellingPolicy

Default spelling policy used for transcriptions made with this Ensemble.

descendants() → Sequence[Clock]

Get all children, grandchildren, etc. of this clock

Returns:

tuple of all descendants

duplicate() → T

Returns a copy of this object by serializing to and from JSON.

extract_absolute_tempo_envelope(start_beat: float = 0, end_beat: float | None = None, step_size: float = 0.1, tolerance: float = 0.005) → TempoEnvelope

Extract this clock’s absolute tempo curve — its tempo as observed in master (scheduler) time, with parent rate-changes folded in. Used when building a Score from this clock’s perspective.

Extracts over [start_beat, end_beat], where end_beat defaults to this clock’s current beat. When all ancestors are pure, flat tempos, they simply scale this clock’s tempo curve directly. When the ancestors are changing, there is no exact solution, so we sample every step_size beats. Sampling is aligned to the tempo break points of every clock in the chain, so an instantaneous tempo change stays sharp rather than smearing into a short accelerando or ritardando.

fast_forward(on_or_off: bool = True) → None

Turn indefinite fast-forwarding on or off. While on, all waiting is instantaneous. (Only valid on the master clock.)

Parameters:

on_or_off – True to start fast-forwarding, False to stop.

fast_forward_in_beats(b: float) → None

Fast-forward, skipping ahead instantaneously by b beats. (Only valid on the master clock.)

Parameters:

b – number of beats to fast-forward by

fast_forward_in_time(t: float) → None

Fast-forward, skipping ahead instantaneously by t seconds. (Only valid on the master clock.)

Parameters:

t – number of seconds to fast-forward by

fast_forward_to_beat(b: float) → None

Fast-forward, skipping instantaneously up to beat b on this clock. (Only valid on the master clock.)

Parameters:

b – beat to fast-forward to

fast_forward_to_time(t: float) → None

Fast-forward, skipping instantaneously up to time t (in seconds) on this clock, then resume real-time playback. (Only valid on the master clock.)

Parameters:

t – time to fast-forward to

fork(forked_function: Callable, args: Sequence = (), kwargs: dict = None, name: str = None, initial_rate: float = None, initial_tempo: float = None, initial_beat_length: float = None, when: ResolvableMoment | None = None, done_callback: Callable[[], None] = None)

Spawns a child clock running forked_function as a coordinated parallel timeline.

The child runs on its own thread but stays synchronized under this clock’s master scheduler — “parallel” here means parallel musical time (like a separate voice or layer), not simultaneous CPU execution; the scheduler runs one clock’s code at a time.

Parameters:
  • forked_function – the function to be run on the new child clock

  • args – positional arguments to be passed to the forked function. (Unlike legacy clockblocks, clockblocks does not inject the child clock as an extra first argument when the signature is one short — call current_clock() from inside the forked function if you need a reference to it.)

  • kwargs – keyword arguments to be passed to the forked function

  • name – name to be given to the spawned child clock

  • initial_rate – starting rate of this clock (if set, don’t set initial tempo or beat length)

  • initial_tempo – starting tempo of this clock (if set, don’t set initial rate or beat length)

  • initial_beat_length – starting beat length of this clock (if set, don’t set initial tempo or rate)

  • when – when the forked function should begin, as a ResolvableMoment. None (default) starts it immediately. Otherwise pass an explicit Moment — at_beat() (or at_time()) for an absolute point, or after_beats() (or after_time()) for an offset from now. Unlike wait and wait_until, a bare number is rejected here, since it’s not clear whether it would be relative or absolute. Also possible is a MetricPhaseTarget which starts it at the next matching point in a cycle.

  • done_callback – a callback function to be invoked when the clock has terminated

Returns:

the spawned child clock

static get_available_midi_output_devices() → enumerate

Returns an enumeration of available ports and devices for midi output.

get_instrument_by_name(name: str, which: int = 0)

Returns the instrument of the given name.

Parameters:
  • name – name of the instrument to return

  • which – If there are multiple with the same name, this parameter specifies the one returned. (If none match the number given by which, the first name match is returned)

hold_scheduler()

Context manager that: 1) ensures that the scheduler is not executing scheduled actions — waiting if one is in flight, then preventing others from starting; 2) rouses the scheduler and updates its committed time to the current projected time. Code under this context manager therefore acts like an immediately scheduled action, holding exclusive access to an up-to-date scheduler.

Note that, when used from within the clock system, this context manager is a no-op, since the current thread already holds exclusive access to an up-to-date scheduler. In fact, invoking clock.scheduler.held() in that context would cause deadlock, which is why this method exists as the main entry point.

inheritance(include_self: bool = True) → Sequence[Clock]

Get all parent, grandparent, etc. of this clock up until the master clock

Parameters:

include_self – whether or not to include this clock in the iterator or start with the parent

Returns:

tuple containing the clock’s inheritance

property instruments

Returns a tuple of the instruments currently in this Ensemble.

is_fast_forwarding() → bool

Whether the clock is currently fast-forwarding. Since fast-forwarding is a scheduler-wide state, this is true for every clock in the family whenever it’s true for any of them.

is_master() → bool

Check if this is the master clock

Returns:

True if this is the master clock, False otherwise

is_transcribing() → bool

Checks if any transcriptions are in progress.

iterate_all_relatives(include_self: bool = False) → Iterator[Clock]

Iterate through all related clocks to this clock.

Parameters:

include_self – whether or not to include this clock in the iterator

Returns:

iterator going through all clocks in the family tree, starting with the master

iterate_descendants(include_self: bool = False) → Iterator[Clock]

Iterate through all children, grandchildren, etc. of this clock

Parameters:

include_self – whether or not to include this clock in the iterator

Returns:

iterator going through all descendants

iterate_inheritance(include_self: bool = True) → Iterator[Clock]

Iterate through parent, grandparent, etc. of this clock up until the master clock

Parameters:

include_self – whether or not to include this clock in the iterator or start with the parent

Returns:

iterator going up the clock family tree up to the master clock

json_dumps() → str

Dump this object as a JSON string. This uses a custom encoder that recognizes and appropriately converts any attributes that are object inheriting from SavesToJSON.

classmethod json_loads(s: str) → T

Load this object from a JSON string. This uses a custom decoder that looks for a “_type” key in any object/dictionary being parsed and converts it to the class specified (assuming it a subclass of SavesToJSON).

Parameters:

s – a string representing this object in JSON format

kill() → None

End this clock (and the corresponding forked function if not master) and cascade to all descendant clocks.

Pending scheduled work for this clock and its descendants is canceled and the clocks are marked dead. A clock currently blocked in wait() raises ClockKilledError; any later wait() or fork() made through a reference to a dead clock raises DeadClockError.

Killing the master also tears down the family’s scheduler, and releases its owning thread: that thread’s current_clock() becomes None, so the module-level helpers (wait(), fork(), get_beat(), …) raise NoActiveClockError there rather than reporting a dead clock.

Returns once the killed clocks have finished unwinding to ensure synchronicity. Emits a warning if this takes more than a few seconds.

Safe to call from any thread, and killing an already-dead clock is a no-op.

(See the “Clock termination / lifecycle paths” note near the top of this module for how the five termination paths work internally.)

classmethod load_from_json(file_path: str) → T

Load this object from a JSON file with the given path. This uses a custom decoder that looks for a “_type” key in any object/dictionary being parsed and converts it to the class specified (assuming it a subclass of SavesToJSON).

Parameters:

file_path – path for loading the file

property master: Clock

The master clock under which this clock operates (possibly itself)

new_midi_part(name: str = None, midi_output_device: int | str = None, num_channels: int = 8, midi_output_name: str = None, max_pitch_bend: int = 'default', start_note_fixed: bool = True, default_spelling_policy: SpellingPolicy | str | tuple = None, clef_preference='from_name', start_channel: int = 0, volume_cc_num: int = 11, note_on_and_off_only: bool = False) → ScampInstrument

Creates and returns a new ScampInstrument for this Ensemble that uses a MIDIStreamPlaybackImplementation. This means that when notes are played by this instrument, midi messages are sent out to the given device.

Parameters:
  • name – name used for this instrument in score, etc. for a preset of the appropriate name.

  • midi_output_device – name or number of the device used to output midi. Call get_available_midi_output_devices to check what’s available.

  • num_channels – maximum of midi channels available to this midi part. It’s wise to use more when doing microtonal playback, since pitch bends are applied per channel.

  • midi_output_name – name of this part

  • max_pitch_bend – max pitch bend to use for this instrument

  • start_note_fixed – default start_note_fixed for notes started with start_note() on this part.

  • default_spelling_policy – the default_spelling_policy for the new part

  • clef_preference – the clef_preference for the new part

  • start_channel – the first channel to use. For instance, if start_channel is 4, and num_channels is 5, we will use channels (4, 5, 6, 7, 8). NOTE: channel counting in SCAMP starts from 0, so this may show up as channels 5-9 in your MIDI software.

  • volume_cc_num – The cc value used for volume changes. Defaults to 11 (expression).

  • note_on_and_off_only – Deprecated; use start_note_fixed.

Returns:

the newly created ScampInstrument

new_osc_part(name: str = None, port: int = None, ip_address: str = '127.0.0.1', message_prefix: str = None, osc_message_addresses: dict = 'default', default_spelling_policy: SpellingPolicy | str | tuple = None, clef_preference='from_name', start_note_fixed: bool = True) → ScampInstrument

Creates and returns a new ScampInstrument for this Ensemble that uses a OSCPlaybackImplementation. This means that when notes are played by this instrument, osc messages are sent out to the specified address

Parameters:
  • name – name used for this instrument in score, etc. for a preset of the appropriate name.

  • port – port osc messages are sent to

  • ip_address – ip_address osc messages are sent to

  • message_prefix – prefix used for this instrument in osc messages

  • osc_message_addresses – dictionary defining the address used for each type of playback message. defaults to using “start_note”, “end_note”, “change_pitch”, “change_volume”, “change_parameter”. The default can be changed in playback settings.

  • default_spelling_policy – the default_spelling_policy for the new part

  • clef_preference – the clef_preference for the new part

  • start_note_fixed – default start_note_fixed for notes started with start_note() on this part.

Returns:

the newly created ScampInstrument

new_part(name: str = None, preset='auto', soundfont: str = 'default', num_channels: int = 8, audio_driver: str = 'default', max_pitch_bend: int = 'default', start_note_fixed: bool = True, default_spelling_policy: SpellingPolicy | str | tuple = None, clef_preference='from_name', volume_cc_num: int = 11, note_on_and_off_only: bool = False) → ScampInstrument

Creates and returns a new ScampInstrument for this Ensemble that uses a SoundfontPlaybackImplementation. Unless otherwise specified, the default soundfont for this Ensemble/Session will be used, and we will search for the preset that best matches the name given.

Parameters:
  • name – name used for this instrument in score, etc.

  • preset – if an int, assumes bank #0; can also be a tuple of form (bank, preset). If “auto”, searches for a preset of the appropriate name.

  • soundfont – the name of the soundfont to use for fluidsynth playback

  • num_channels – maximum of midi channels available to this midi part. It’s wise to use more when doing microtonal playback, since pitch bends are applied per channel.

  • audio_driver – which audio driver to use for this instrument (defaults to ensemble default)

  • max_pitch_bend – max pitch bend to use for this instrument

  • start_note_fixed – default start_note_fixed for notes started with start_note() on this part.

  • default_spelling_policy – the default_spelling_policy for the new part

  • clef_preference – the clef_preference for the new part

  • volume_cc_num – The cc value used for volume changes. Defaults to 11 (expression).

  • note_on_and_off_only – Deprecated; use start_note_fixed.

Returns:

the newly created ScampInstrument

new_silent_part(name: str = None, default_spelling_policy: SpellingPolicy | str | tuple = None, clef_preference='from_name', start_note_fixed: bool = True) → ScampInstrument

Creates and returns a new ScampInstrument for this Ensemble with no PlaybackImplementations.

Parameters:
  • name – name of the new part

  • default_spelling_policy – the default_spelling_policy for the new part

  • clef_preference – the clef_preference for the new part

  • start_note_fixed – the start_note_fixed default for the new part. Only relevant if adding a MIDI playback implementation.

Returns:

the newly created ScampInstrument

pop_instrument(index)

Pops the instrument at the given index, severing its ties to the ensemble.

Parameters:

index – which instrument

property precise_timing: bool

Whether to use a busy wait in the final moments leading up to a scheduled event. The busy wait fully occupies a CPU core and lasts at most spin_guard_duration seconds per event. (Forwards to the scheduler, settable only on the master clock)

print_default_soundfont_presets() → None

Prints a list of presets available with the default soundfont.

print_family_tree() → None

Print a hierarchical representation of this clock’s family tree.

print_status(verbose: bool = False) → None

Print this clock’s status() snapshot.

projected_beat() → float

A wall-clock-interpolated estimate of beat. See projected_time().

Returns:

the estimated elapsed beats.

projected_time() → float

A wall-clock-interpolated estimate of time, advancing smoothly between events rather than holding still between them. For readers outside the clock system; see the section comment above. (A method rather than a property, because it is a live sample: every call returns a different value.)

This is an estimate, and it can step backward — see projected_time().

Returns:

the estimated elapsed time, in the same units as time.

property rate: float

The rate of this clock in beats / second. Note that beat_length, tempo and rate are interconnected properties, and that by setting one of them the other two are automatically set in response according to the relationship: beat_length = 1/rate = 60/tempo. Also, note that “seconds” refers to actual seconds only in the master clock; otherwise it refers to beats in the parent clock.

register_note(instrument: ScampInstrument, note_info: dict) → None

Called when an instrument wants to register that it finished a note, records note in all transcriptions

Parameters:
  • instrument – the ScampInstrument that played the note

  • note_info – the note info dictionary on that note, containing time stamps, parameter changes, etc.

save_to_json(file_path: str) → None

Save this object to a JSON file using the given path. This uses a custom encoder that recognizes and appropriately converts any attributes that are object inheriting from SavesToJSON.

Parameters:

file_path – path for saving the file

schedule_action(action: Callable, when: ResolvableMoment, args: Sequence = (), kwargs: dict = None) → None

The lightweight alternative to fork() for immediately returning functions. Schedules action to run once at when, as a leaf event on the scheduler thread — without spawning a child clock. For functions that don’t wait, this is much more performant: there is no thread creation, no scheduler/clock handoff; just a callable fired at the right musical time.

For work that needs to wait, fork() a child clock instead. The function scheduled here will not have an active clock to wait on, and will hold up the entire scheduler if it sleeps.

Parameters:
  • action – the callable to run (exceptions are caught and logged by the scheduler)

  • when – when to run it, as a ResolvableMoment — same convention as fork(): an explicit Moment (Moment.at_beat/at_time for an absolute point, Moment.after_beats/ after_time for an offset from now) or a MetricPhaseTarget. Unlike wait and wait_until, a bare number is rejected here, since it’s not clear whether it would be relative or absolute.

  • args – positional arguments to pass to action

  • kwargs – keyword arguments to pass to action

scheduler_to_clock_time(scheduler_time, desired_units='beats')

Gets beats or time in this clock for a given time in the scheduler.

Parameters:
  • scheduler_time – the time of interest in the scheduler

  • desired_units – one of (“beats”, “time”), whether we’re looking for beats or time in this clock

Returns:

how much time should pass in the scheduler

set_beat_length_target(beat_length_target: float, when: ResolvableMoment, curve_shape: float = None, truncate: bool = True, align_to: ResolvableMoment = None) → None

Smoothly change this clock’s beat length (seconds per beat) to beat_length_target, arriving at the moment given by when. This is the underlying representation behind set_tempo_target() and set_rate_target(); a longer beat length means a slower tempo.

Parameters:
  • beat_length_target – the beat length to arrive at, in seconds per beat.

  • when – when the target should be reached, as a Moment (e.g. Moment.after_beats(4), Moment.at_time(10)) or a MetricPhaseTarget (the next point matching a particular phase within the beat cycle). after_* moments count from the clock’s current position. A plain number is rejected; wrap it in a Moment to clarify beat/time and relative/absolute.

  • curve_shape – the bend of the transition. 0 (the default) is a straight line; > 0 keeps the old tempo longer and changes late; < 0 changes early then eases in. When align_to solves for the curvature (see below) this acts only as a starting hint, and with a fixed align_to, it is ignored entirely (and a warning is issued if set).

  • truncate – if True (the default), any tempo curve already scheduled past the current beat is discarded first, so the change starts from where the clock is right now. If False, this target is appended after whatever is already scheduled.

  • align_to – optional. If when is an arrival beat, this specifies the desired arrival time. If when is an arrival time, this specifies the desired arrival beat. A MetricPhaseTarget can be given instead of a singular time/beat, to express when we should arrive within a time/beat cycle. Note that the coordination of beat and time is done via mutating the curve shape, so an explicit curve shape is only a hint (ignored completely if align_to is a fixed point rather than a metric phase target).

Raises:

ValueError – if when/align_to share an axis, or if no curvature can reach the requested align_to (in which case the tempo curve is left unchanged).

set_beat_length_targets(beat_length_targets: Sequence[float], whens: Sequence[ResolvableMoment], curve_shapes: Sequence[float] = None, truncate: bool = True, align_to: ResolvableMoment | Sequence[ResolvableMoment | None] = None) → None

Smoothly change this clock’s beat length (seconds per beat) through a series of targets, building a multi-segment tempo curve in one call — the multi-segment form of set_beat_length_target(). This is non-looping; to apply a looping tempo shape, build a TempoEnvelope and use apply_tempo_envelope().

Parameters:
  • beat_length_targets – the beat lengths (seconds per beat) to arrive at, one per segment.

  • whens – when each target is reached (same length as beat_length_targets), each a Moment or MetricPhaseTarget. Note that every when is resolved against the clock’s current position, so an after_* moment counts from now, not from the previous segment’s. Beats- and time-axis moments may be freely mixed across the list, so long as the whens come out in strictly increasing clock-time.

  • curve_shapes – optional per-segment bends (same length as beat_length_targets), each as in set_beat_length_target(). None for the whole argument (the default), or a per-element None, means linear (0) for that segment.

  • truncate – if True (the default), any tempo curve already scheduled past the current beat is discarded first, so the run starts from where the clock is now; if False the run is appended after whatever is already scheduled.

  • align_to –

    optional curvature-solved alignment, extending set_beat_length_target()’s align_to to runs of segments. Either:

    • a single Moment/MetricPhaseTarget — align the whole call as one run, landing its end on the target; or

    • a per-segment list/tuple (same length as beat_length_targets) of None/targets — each non-None entry closes a run (all segments since the previous alignment, or the start) and bends them collectively so the run lands on that target.

    A group-aligned run of more than one segment must have its whens on a single axis (all beats or all time), with the alignment target on the opposite (free) axis.

Raises:

ValueError – if whens/curve_shapes/align_to lengths are inconsistent with beat_length_targets; if the whens do not come out strictly increasing in clock-time (the error names the offending index); if a multi-segment aligned run mixes beat- and time-axis whens; or if an alignment target is unreachable by curvature adjustment. On any failure the tempo curve is left unchanged.

set_rate_target(rate_target: float, when: ResolvableMoment, curve_shape: float = None, truncate: bool = True, align_to: ResolvableMoment = None) → None

Smoothly change this clock’s rate (beats per second) to rate_target, arriving at when. Rate is the reciprocal of beat length: a higher rate is a faster tempo.

Parameters:
Raises:

ValueError – see set_beat_length_target().

set_rate_targets(rate_targets: Sequence[float], whens: Sequence[ResolvableMoment], curve_shapes: Sequence[float] = None, truncate: bool = True, align_to: ResolvableMoment | Sequence[ResolvableMoment | None] = None) → None

Smoothly change this clock’s rate (beats per second; the reciprocal of beat length, so a higher rate is a faster tempo) through a series of targets — the multi-segment form of set_rate_target().

Parameters:
Raises:

ValueError – see set_beat_length_targets().

set_tempo_target(tempo_target: float, when: ResolvableMoment, curve_shape: float = None, truncate: bool = True, align_to: ResolvableMoment = None) → None

Smoothly change this clock’s tempo to tempo_target, arriving at when. Tempo is measured in beats per minute; this is usually the most natural of the three equivalent ways to set a target (see also set_rate_target() and set_beat_length_target()).

Parameters:
Raises:

ValueError – see set_beat_length_target().

set_tempo_targets(tempo_targets: Sequence[float], whens: Sequence[ResolvableMoment], curve_shapes: Sequence[float] = None, truncate: bool = True, align_to: ResolvableMoment | Sequence[ResolvableMoment | None] = None) → None

Smoothly change this clock’s tempo (beats per minute) through a series of targets — the multi-segment form of set_tempo_target(), and usually the most natural of the three equivalent plural setters.

Parameters:
Raises:

ValueError – see set_beat_length_targets().

property spin_guard_duration: float

Width (seconds) of the busy-wait guard band used when precise_timing is on. (Forwards to the scheduler, settable only on the master clock)

status(verbose: bool = False) → str

A snapshot of this clock’s name and position, alongside the scheduler’s elapsed wall time and how far behind schedule it is currently running.

stop_tempo_loop_or_function() → None

Stop following any function or looping envelope previously applied to this clock’s tempo.

stop_transcribing(which_performance=None, tempo_envelope_tolerance=0.001) → Performance

Stops transcribing a Performance and returns it. Defaults to the oldest started performance, unless otherwise specified.

Parameters:
  • which_performance – which performance to stop transcribing; defaults to oldest started

  • tempo_envelope_tolerance – error tolerance when extracting the absolute tempo envelope for the Performance

Returns:

the created Performance

property tempo: float

The rate of this clock in beats / minute Note that beat_length, tempo and rate are interconnected properties, and that by setting one of them the other two are automatically set in response according to the relationship: beat_length = 1/rate = 60/tempo. Also, note that “seconds” refers to actual seconds only in the master clock; otherwise it refers to beats in the parent clock.

terminate_forked_children() → None

Kill this clock’s children and their descendants in turn, returning once they have finished unwinding. At the natural end of a forked clock that has (or might have) still-active children, either this or wait_for_children_to_finish() should be called, making explicit what to do with those forked children. (The default is termination with a warning, in case it’s not what the user wants.)

property time: float

How much time has passed since this clock was created. Either in seconds, if this is the master clock, or in beats in the parent clock, if this clock was the result of a call to fork. Note that this is quantized to the scheduler’s event stream; for a live estimate when outside the clock system use projected_time().

(Read-only property. Before clockblocks 1.1 this was a method; the clock.time() spelling still works, with a DeprecationWarning.)

property timing_policy: float

How the family trades off relative vs. absolute timing, as a float from 0 to 1.

At 1.0 (relative) each wait is kept as faithful as possible to its requested duration, timed from when the previous event fired (callback runtime does not count against the wait). This can still let the clock fall behind real time: if a wait overruns (e.g. through a callback that runs longer than its own wait or the OS waking late) that lateness is never made up. At 0.0 (absolute) the clock instead stays faithful to the time elapsed since it began — a wait that ran long is followed by shorter waits to catch up, at the cost of some relative-timing accuracy. A value in between clamps the catch-up: the clock attempts to stay on the absolute schedule but can only compress a wait to wait_dur * timing_policy (or stretch it to wait_dur / timing_policy if trying to compensate for being ahead). (Forwards to the scheduler, settable only on the master clock)

property transcriptions_in_progress: tuple[Performance]

Tuple of all current transcriptions.

use_absolute_timing_policy() → None

Shorthand for timing_policy = 0.0 (always catch up to absolute schedule).

use_mixed_timing_policy(absolute_relative_mix: float) → None

Shorthand for timing_policy = absolute_relative_mix (a blend between 0=absolute and 1=relative).

use_relative_timing_policy() → None

Shorthand for timing_policy = 1.0 (always wait the full requested delay).

wait(duration: float | ResolvableMoment, units: str = 'beats') → None

Block this clock for duration beats (or seconds, if units=”time”) from now, yielding to the scheduler. duration may also be any ResolvableMoment (a Moment or MetricPhaseTarget), in which case it is resolved directly and units is ignored — e.g. wait(Moment.at_beat(8)) or wait(MetricPhaseTarget(0, 4)). wait_until() is just a convenience for absolute targets given as a bare number; passing an absolute Moment to wait() does the same thing.

wait_for_children_to_finish() → None

Block this clock’s own thread until all of its child clocks have finished, yielding to the scheduler so they can run, then return as soon as the last child ends.

If this clock is itself killed while waiting, raises ClockKilledError rather than returning — so a normal return always means the children genuinely finished.

wait_for_clock_to_finish(clock: Clock) → None

Block this clock’s own thread until clock has finished, yielding to the scheduler so it (and everything else) keeps running. The counterpart to wait_for_children_to_finish() for a specific clock rather than one’s own children — clock may be any other clock in the same family (a sibling, a descendant, an unrelated fork), so long as it shares this clock’s scheduler.

Returns as soon as clock finishes, whether it ended on its own or was killed. If clock has already finished, returns immediately. If this clock is itself killed while waiting, raises ClockKilledError rather than returning.

Parameters:

clock – the clock to wait on. Must belong to the same family (raises ValueError otherwise), and must not be this clock itself (which would wait forever).

wait_forever() → None

Block this clock’s own thread indefinitely, yielding to the scheduler so child clocks keep running. Typically called once a clock has forked its work and has nothing left to do itself (e.g. the master clock keeping the main thread alive).

This only ever unblocks via kill(), at which point it raises ClockKilledError. For a forked clock, this is caught by the fork wrapper and it cleanly unwinds. For a master clock it would need to be caught. A built-in way to do this is by using the clock as a context manager, which does exception handling and teardown for you. (run_as_server() also absorbs the exception automatically within the spawned thread).

That said, typically this is used at end of script and killed via ctrl-c/process exit, so no explicit catching of this exception is necessary.

wait_until(when: float | ResolvableMoment, units: str = 'beats') → None

Block this clock until the beat (or time, if units=”time”) indicated by when — a convenience for absolute targets given as a bare number (equivalent to wait(Moment.at_beat(when)), or Moment.at_time for units=”time”). when may also be any ResolvableMoment, in which case the units are ignored and behavior is identical to wait(). If when is in the past, returns essentially immediately.

description: str | None