Clocks and clips#

A domain clock is a named beat clock owned by the engine. You create and steer it through YSE::System(): createClock, destroyClock, clockExists, setTempo, beatPosition and currentTempo (see Core). A clip plays a looping list of beat-timed notes against one of those clocks, into synths or MIDI output ports.

Clocks and clips walks through both, and Time, scheduling and clocks shows how a patch uses the same clocks. The C API equivalents are in C ABI (language bindings) (yse_clip.h and the clock functions in yse_system.h).

namespace YSE

Public API of libYSE — sound playback, mixing, and 3D positional audio.

Entry points: YSE::System (lifecycle and audio device), YSE::Listener (3D origin), YSE::sound (a playable source), YSE::channel (mixing tree), YSE::reverb (positioned reverb zone), YSE::patcher (modular DSP graph), YSE::player (note sequencer). Sub-namespaces group domain-specific types: YSE::DSP for signal processing, YSE::MIDI for MIDI I/O, YSE::MUSIC for note / chord / motif primitives.

Note

Apart from their constructors, the oscillator and vcf classes must only be invoked from inside a DSP callback / process body.

class clip#

A looping clip transport: plays a timed note-event list against a domain clock, dispatched from the audio thread.

The clip binds to a named domain clock (see System().createClock). It owns an immutable list of clipEvent and a loop length in beats. Every audio block it converts that block’s boundaries into a beat window on the clock and fires exactly the events whose crossings fall inside it — so the UI thread never dispatches a note, and tempo changes on the clock bend the clip with no rescheduling.

The event list is replaceable while playing: setEvents publishes a new list that the transport swaps in at the next block boundary, lock-free with respect to the audio thread. Sounding-note bookkeeping survives the swap — a note that vanished from the new list still gets its note-off on time.

Output targets one or more YSE::synth instances (block-accurate, on the audio thread, via the RT-safe internal event queues) and — on builds with YSE_ENABLE_MIDI_DEVICE — one or more external MIDI output ports (issue #350): fired messages are stamped with an absolute send time and drained by a dedicated sender thread, so the RtMidi send never happens on the audio callback.

Multiple clips run concurrently, each on its own clock. Non-copyable / non-movable — wrap in a unique_ptr if you need transferable ownership.

Public Functions

clip()#
~clip()#
clip(const clip&) = delete#
clip &operator=(const clip&) = delete#
clip(clip&&) = delete#
clip &operator=(clip&&) = delete#
bool create(const std::string &clockName)#

Bind the clip to a domain clock by name.

Binding shares the clock’s lifetime (issue #707), so the two can be destroyed in either order: destroyClock on a bound clock stops it advancing, and a clip on a stopped clock simply stops firing rather than reading a freed object. Control thread only.

Parameters:

clockName – Name of a live domain clock (System().createClock).

Returns:

true on success; false if no live clock owns the name.

clip &setEvents(const std::vector<clipEvent> &events)#

Replace the event list.

Takes effect at the next block boundary, lock-free with respect to the audio thread. Control thread only.

clip &loopLength(double beats)#

Set the loop length in beats.

Values <= 0 disable looping (events fire once). Control thread only.

clip &connect(YSE::synth &synth)#

Route this clip’s playback into a synth.

Every note / pitch-bend it fires is delivered to synth block-accurately on the audio thread. May be called for several synths.

Warning

synth must outlive the connection: disconnect it (or destroy this clip) before destroying the synth. Control thread only.

clip &disconnect(YSE::synth &synth)#

Stop routing this clip’s playback into synth.

clip &play()#

Start (or restart) playback from the clock’s current beat.

clip &stop()#

Stop playback; emits note-offs for everything currently sounding.

bool isPlaying() const#

Whether the clip is currently playing.

Private Members

CLIP::transport *pimpl#
struct clipEvent#

One timed note event in a clip, positioned in beats.

Times are beat offsets on the clip’s bound domain clock, not absolute seconds — the transport evaluates them against the clock every audio block, so a tempo change on the clock bends the clip immediately with no rescheduling. startBeat is taken modulo the clip’s loop length, so an event repeats every loop.

Public Members

double startBeat = 0.0#

Beat within the loop at which the note starts (>= 0).

double durationBeats = 0.0#

Note length in beats.

The note-off fires durationBeats after each note-on, independent of the event list — so a note still sounding when the list is swapped is released on time even if it vanished from the new list.

int channel = 1#

MIDI channel, 1..16.

int pitch = 60#

MIDI note number, 0..127.

float velocity = 0.8f#

Velocity, normalized to [0, 1].

float pitchBend = 0.0f#

Optional per-note pitch bend, normalized to [-1, 1] (0 = none).

Emitted as a channel pitch-wheel just before the note-on — Phi voices fractional / microtonal pitch as nearest semitone + bend.