C.W.K.
Stream
Lesson 03 of 05 · published

One Anchored Clock Kills the Jitter

~13 min · shared-clock, web-audio, scheduler

Level 0Cold Ash
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Give every voice its own timer and they drift. Give them one clock and they lock."

The Symptom: Drift

In the v1 playback engine, the solo, the chords, and the metronome each need to sound at the right musical moment. The naive build gives each its own timer — and they slowly slide apart, because independent timers accumulate independent error. The metronome ticks a hair early, the chords lag, and what should be locked feels loose. That's jitter, and it's the death of a practice tool: you can't play along with something that won't hold still.

The Fix: One Anchored Audio Clock

The fix is a single source of truth — for time. Pick one anchor (a moment where audio-time and source-time are pinned together), and map every voice's source position to audio-time through the same function. Add a syncOffset knob to nudge alignment by ear. Then run a lookahead scheduler: wake on a short interval, and schedule everything due in the next window against the AudioContext's own clock — never against setTimeout, which is far too jittery for musical timing. Because every voice reads the one clock, they physically cannot drift apart.

It's the One-Model Idea, Applied to Time

Notice the shape: this is exactly Track 3's single-source-of-truth, wearing a different hat. There, one music model and many views that can't disagree. Here, one timebase and many voices that can't drift. The same principle — a single authoritative source that everything derives from — solves fragmentation whether the thing being fragmented is data (the model) or time (the clock). When you see drift, look for the missing single source.

Code

One clock, many voices — the anchored audio timebase·javascript
// One anchored clock. Every voice maps source-time -> audio-time through
// the SAME function, so they physically cannot drift apart.
function audioTimeOf(srcTime) {
  return anchorAudio + (srcTime - anchorSrc) / tempo + syncOffset;
}

// Lookahead scheduler: wake on a short interval and schedule everything
// due in the next window against the audio clock -- never setTimeout,
// which is far too jittery for musical timing.
const LOOKAHEAD = 0.1;  // seconds
setInterval(() => {
  while (next.srcTime < currentSrcTime() + LOOKAHEAD) {
    scheduleVoiceAt(audioTimeOf(next.srcTime), next);  // solo / chord / metronome
    next = advance();
  }
}, 25);

External links

Exercise

Find any system where two things are supposed to stay in sync but slowly drift (two animations, two progress bars, two timers). Ask: do they each track time independently, or do they read one shared clock? Sketch the fix as 'one anchor + derive both from it.' That's the same move that locked Bonfire's voices together.
Hint
Anything scheduled with setInterval/setTimeout and its own start time will drift. The fix is always a single authoritative clock that both consumers derive their positions from — not two timers you hope stay aligned.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Pippawarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.