Timing is Everything

Audio Scheduling & Rhythm

25 min read Intermediate Sequencer Demo

Direct answer

Schedule game music and repeating beats on audioCtx.currentTime, a few notes ahead of the speaker. Do not start each sound from a setInterval callback. Hit sounds can still fire on the event; a rhythm cannot.

What you need first

The Web Audio basics lesson, including the rule that audio starts after a user click.

After this lesson

You can explain why Snake beeps on eat, but a drum loop must be scheduled ahead of time.

The Two Clocks

JavaScript has Date.now(), but Web Audio has audioCtx.currentTime. The audio clock is highly precise (double precision) and hardware-driven. Always use currentTime for music scheduling.

scheduling.js
// Play a sound 1 second from NOW
const now = audioCtx.currentTime;
oscillator.start(now + 1.0);

// Schedule a rhythm
for (let i = 0; i < 4; i++) {
    playKick(now + i * 0.5); // Play every 0.5 seconds (120 BPM)
}

8-Step Sequencer

A simple drum machine. Click the boxes to enable steps. Synthesized sounds (Kick, Snare, HiHat).

KICK
SNARE
HIHAT
120 BPM

Look-ahead, not setInterval

The demo does not wait for the exact beat and then scramble to start a node. A timer wakes every 25ms, and any note whose time is less than currentTime + 0.1 is scheduled immediately. The speaker still plays it at the audio-clock time. That is the look-ahead scheduler from the Web Audio timing model.

If you start the oscillator inside setInterval(..., 500), the beat will drift as soon as the main thread is busy drawing Canvas. The audio clock does not wait for that thread.

How InstantGames uses this

Snake does not need this scheduler. Eating food is a one-shot beep: create a short oscillator, ramp the gain, stop. The only shared rule from the previous lesson is “one AudioContext, unlocked by a key or tap.”

Use this page when a sound must stay in time with itself: a metronome, a looping drum, a warning pulse that should not bunch up if a frame hitch happens. Background music that must stay locked to a beat belongs here. A brick-hit blip in Breakout does not.

Common mistake

Creating a new AudioContext for every scheduled note, or scheduling far into the future and never cancelling when the player pauses. Pause should stop the look-ahead timer and leave already-scheduled notes alone, or call audioCtx.suspend().

Compatibility: Web Audio scheduling works in current Chrome, Firefox, Safari, and Edge after a user gesture. This page does not claim a measured latency number beyond the local sequencer.

Source and update: Reviewed against the MDN Web Docs Web Audio API and Chris Wilson’s look-ahead scheduling pattern. Updated 2026-08-13.