Skip to content
C.W.K.
Stream
Lesson 03 of 05 · published

One Anchored Clock Prevents Scheduler Drift

~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
"A JavaScript timer wakes the scheduler. The audio clock decides when sound actually happens."

The Symptom: Scheduler Drift

In a playback engine, the solo, chords, and metronome must meet at the same musical moments. If each voice advances from its own start time and JavaScript callbacks, callback delays can accumulate differently. A metronome edges forward, a chord lands late, and the groove becomes too loose to trust as a practice reference.

The Fix: One Anchored Audio Clock

Choose an anchor relating source time to AudioContext.currentTime, then calculate every voice's event time from that same mapping. A lookahead scheduler may wake frequently with setTimeout or setInterval. The important distinction is that the JavaScript timer does not define the audible deadline. It finds events in the next window and schedules them ahead on the Web Audio clock.

A shared timebase prevents independent schedulers from accumulating drift, but it does not make every path sample-perfect automatically. Asset start positions, decoding, signal paths, and output-device latency can leave fixed offsets. Measure those paths and calibrate each voice separately. The clock supplies a common coordinate system; calibration aligns the paths within it.

The One-Model Idea, Applied to Time

This echoes Track 3's single source of truth. There, several views derive from one music model. Here, several voices derive event times from one timebase. A single source is not magic that erases all observed differences; it gives those differences one frame in which they can be explained and corrected. When audio drifts, check the authoritative time source first, then measure path-specific latency.

Code

Wake with a JavaScript timer; schedule on the audio clock·javascript
function audioTimeOf(srcTime, voice) {
  const shared = anchorAudio + (srcTime - anchorSrc) / playbackRate;
  return shared + voiceOffset[voice]; // measured fixed path correction
}

const SCHEDULE_AHEAD = 0.1; // seconds
const LOOKAHEAD_MS = 25;

function scheduler() {
  while (next.srcTime < currentSrcTime() + SCHEDULE_AHEAD) {
    // The audible deadline is scheduled on the AudioContext timebase.
    scheduleVoiceAt(audioTimeOf(next.srcTime, next.voice), next);
    next = advance();
  }
  // This timer wakes the scheduler; it is not the audible deadline.
  setTimeout(scheduler, LOOKAHEAD_MS);
}

External links

Exercise

Choose a system with two outputs that must stay synchronized. Determine whether each accumulates its own time or derives position from one clock. Sketch the repair as one anchor, one shared timebase, and per-path offsets. Measure scheduler drift separately from fixed latency.
Hint
setTimeout or setInterval can wake a lookahead scheduler. The bug is letting callback arrival time define the actual event deadline. Do not collapse the common clock and path calibration into one problem.

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.