Build with this node

Start with a prompt in Studio, or copy it into your own coding agent.

Ask Studio

@maruaudio/dsp/control/musical-clock turns musical time into frames at the Processor's prepared sample rate. Pure conversions take the rate and tempo as arguments, each in one fixed operation order: frames per beat is (sampleRate × 60) / bpm, milliseconds are (ms × sampleRate) / 1000. A beat is a quarter note and tempo is quarter notes per minute, the units of the host transport contract. The stateful clock keeps an anchor beat and a whole-frame count since it, so every position and grid boundary is computed from the anchor in one expression and rounded once, half up: it never drifts more than half a frame however long it runs.

Parameters

PathSetterRange as codedDefaultUnit
sampleRateprepareMusicalClockFinite and above 0, else refused (returns false, no change)48000 placeholder until preparedHz
bpmsetMusicalClockTempo, syncMusicalClockFinite and above 0, else refused; range policy (such as 20 to 300) is the owner's120quarter notes per minute
beatssetMusicalClockPosition, syncMusicalClockNon-finite → 00quarter notes

Lifecycle

createMusicalClock(bpm) builds one record → prepareMusicalClock(state, rate) → setMusicalClockTempo, setMusicalClockPosition or syncMusicalClock(state, tempo, ppqPosition) per host block → advanceMusicalClock(state, frames) after rendering, with musicalClockFramesToBoundary(state, stepBeats) and the conversion queries in between. Prepare and tempo changes re-anchor at the current position, so the beat position is continuous across both and only the frames still to come are re-derived. There is no reset; seek to beat 0 instead.

When to use it

Anything authored in beats, milliseconds or seconds: a step sequencer's grid, an arpeggiator's rate, a strum's spread, a timeout. It replaces hard-coded ms × 48 or 48000 placeholders (musical time). musicalGridFrame(index, framesPerStep) gives the same rounding law to owners that walk their own step index.

Limits

  • advanceMusicalClock floors its count and ignores counts of 0 or less.
  • musicalClockFramesToBoundary returns 0 on a boundary and −1 for a step of 0 or less. Exact ties within MUSICAL_CLOCK_TIE_FRAMES (10⁻⁶ frame) resolve up.
  • musicalBpmFromPulseFrames returns 0 for a non-positive period or pulse count; MIDI beat clock is MUSICAL_CLOCK_MIDI_PPQ (24).
  • syncMusicalClock takes the position even when it refuses the tempo.
  • f64 scalar arithmetic; no allocation after create.

Algorithm properties and proofs

No Lean 4 proof is mapped to this node.

Explore proofs alongside performance

Parameters

ParameterTypeSetter
Bpm bpm

Change tempo at the current frame. The beat position is continuous; beats after this frame run at the new tempo. Returns false (and changes nothing) for a non-positive or non-finite tempo. Range policy (e.g. 20-300 BPM) is the owning module's and is applied before calling.

floatsetMusicalClockTempo
Beats beats

Seek: the current frame is at beat `beats` from now on.

floatsetMusicalClockPosition

Dependencies

None: this node imports no other node.

Dependents

Used by