From 8bdb953b52b3014ed3fe89b0d6f20ac4bc092304 Mon Sep 17 00:00:00 2001 From: Jose Luis Date: Sat, 21 Mar 2026 17:57:10 +0100 Subject: [PATCH] fix: capture master clock start time from first tick callback The _masterTime was captured from Tone.now() BEFORE the clock started, but the time parameter in Tone.Clock callbacks comes from a different scheduler timeline. This caused elapsed to drift systematically. Now _masterTime is set from the first callback's own time parameter, guaranteeing both are on the exact same clock source. Zero drift. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/engine/audioEngine.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/engine/audioEngine.js b/src/engine/audioEngine.js index d962962..8e90623 100644 --- a/src/engine/audioEngine.js +++ b/src/engine/audioEngine.js @@ -35,8 +35,14 @@ export function unsubscribeTick(id) { function startMasterClock() { if (_masterClock) return; - _masterTime = Tone.now(); + _masterTime = 0; // Will be set from first tick + let _started = false; _masterClock = new Tone.Clock((time) => { + // Capture start time from the FIRST callback — guarantees same clock source + if (!_started) { + _masterTime = time; + _started = true; + } const elapsed = time - _masterTime; for (const cb of _tickListeners.values()) { cb(time, elapsed);