Cycles & Time
Resonon measures musical time in cycles. A cycle is one repeating window — think of it as a bar of music. A pattern doesn’t carry a tempo or a list of timestamps; it describes what happens within one cycle, and the runtime repeats that cycle forever. Put four notes in a pattern and they’re quarter-notes; put eight and they’re eighths. This page is the mental model for how that window is sized, how the clock advances it, and why your live edits always land in time.
Cycles, Beats & BPM
Section titled “Cycles, Beats & BPM”A cycle is divided into beats. The two tempo controls are the cycle’s beats and its speed:
use "std/instruments" { Sampler, Kit };
set_bpm(120); // 120 BPM, 4 beats per cycle (the default)
let drums = AudioTrack("drums");drums.set_instrument(Sampler(Kit("CR-78")));
drums << [bd sd bd sd];
PLAY;A cycle is a number of beats, so its length is plain arithmetic. By default that’s 120 BPM at 4 beats per cycle, so one cycle lasts 2 seconds and the four hits above fall one per beat, half a second apart. Add a fifth element and the cycle still lasts 2 seconds — every event simply gets a thinner slice. The cycle is the fixed frame; the pattern decides how to fill it.
The Scheduler Advances Cycles
Section titled “The Scheduler Advances Cycles”Patterns are timeless on their own — [bd sd bd sd] is the same description whether
you play it fast or slow. What turns that description into sound at a tempo is the
scheduler: it walks wall-clock time forward, and each time enough real time has
elapsed for one cycle, it advances the cycle counter and queries every playing
pattern for that cycle’s events.
cycle 0 cycle 1 cycle 2 ┌──────────┐ ┌──────────┐ ┌──────────┐ │ bd sd … │ │ bd sd … │ │ bd sd … │ ← pattern queried per cycle └──────────┘ └──────────┘ └──────────┘ 0s 2s 4s 6s ← wall-clock at 120/4So tempo isn’t baked into your patterns — it’s the rate at which the scheduler
consumes them. Change set_bpm and the same patterns simply stream by faster or
slower.
Quantized Swaps
Section titled “Quantized Swaps”This is the property that makes live coding feel musical rather than chaotic. When you re-send a pattern to a track that’s already playing:
drums << [bd bd sd bd];the swap does not happen the instant you press execute. It’s quantized — held until the start of the next cycle, then applied cleanly on the downbeat. Your edit lands in time no matter when you trigger it mid-cycle, so the groove never tears. This is automatic and applies to every pattern update; there’s no mid-cycle swap to opt into.
It is the same idea as launch quantization in a clip-launching DAW: an edit is queued and fires on the next bar. Because every edit waits for the same boundary, you can evaluate whenever you like — a new pattern, a new layer on another track — and trust it to land on the downbeat, in time with everything already playing.
Code That Runs Every Cycle
Section titled “Code That Runs Every Cycle”The same boundary is where code can run. A callback registered with
on_cycle runs once per cycle, on the interpreter
thread, just before that cycle is needed — so it can compute the next pattern from the cycle number.
Whatever it sends is quantized like any other edit, and lands on the cycle it was computed for.
Change a Pattern Every Cycle
shows how.
Related
Section titled “Related”- Pattern Basics — how events divide a cycle
- Events & Notes — what fills each slice
- The Audio Graph — what the scheduler drives
- Patterns, Tracks & Effects — hearing swaps land on the cycle