From 56e352fe65bf9ccf7f41c27a5e63e3a7222aa162 Mon Sep 17 00:00:00 2001 From: BenStullsBets Date: Fri, 26 Jun 2026 13:34:16 -0700 Subject: [PATCH] diag(audio): status shows resolved url + ring source + scale (pinpoints null soundtrack url) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The operator's 'PAUSED readyState 0' (no error) means soundtrackUrl() returned null — the running app's /api/ring has no audio for the scale, the signature of a STALE uvicorn server (Python predates the audio code; static reload doesn't restart it). Status now shows url=<…|NONE>, ring=server|SYNTH, scale id so it's unambiguous. Fresh server verified: ▶ playing rs=4. Co-Authored-By: Claude Opus 4.8 (1M context) --- simulator/static/app.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/simulator/static/app.js b/simulator/static/app.js index 7cba5a1..92bee4f 100644 --- a/simulator/static/app.js +++ b/simulator/static/app.js @@ -927,20 +927,24 @@ const FADE_MS = 500; const AUD_ERR = ["", "aborted", "network", "decode", "format-not-supported"]; function audioStatusText() { if (!$("audio").checked) return "audio: off"; - if (aud.error) return `audio: MEDIA ERROR ${aud.error.code} (${AUD_ERR[aud.error.code] || "?"})`; - if (audLastErr) return "audio: " + audLastErr; - if (aud.paused) return `audio: on, PAUSED (readyState ${aud.readyState})`; - return `audio: ▶ playing ${aud.currentTime.toFixed(1)}s · vol ${Math.round(aud.volume * 100)}% · rs ${aud.readyState}`; + const s = ring && ring.scales[ringIndex]; + const url = soundtrackUrl(); + const head = `ON · scale=${s ? s.id : "?"} · ring=${serverRing ? "server" : "SYNTH"} · url=${url || "NONE"}`; + if (!url) return "audio: " + head + " ← no soundtrack URL for this scale"; + if (aud.error) return `audio: ${head} · MEDIA ERROR ${aud.error.code} (${AUD_ERR[aud.error.code] || "?"})`; + if (audLastErr) return `audio: ${head} · ${audLastErr}`; + if (aud.paused) return `audio: ${head} · PAUSED rs=${aud.readyState}`; + return `audio: ${head} · ▶ ${aud.currentTime.toFixed(1)}s vol=${Math.round(aud.volume * 100)}% rs=${aud.readyState}`; } function updateAudioStatus() { const el = $("audio-status"); if (!el) return; el.textContent = audioStatusText(); - const playing = $("audio").checked && !aud.paused && !aud.error && !audLastErr; + const playing = $("audio").checked && !!soundtrackUrl() && !aud.paused && !aud.error && !audLastErr; el.classList.toggle("playing", playing); - el.classList.toggle("blocked", !!aud.error || !!audLastErr); + el.classList.toggle("blocked", $("audio").checked && (!soundtrackUrl() || !!aud.error || !!audLastErr)); } -aud.addEventListener("error", () => { audLastErr = ""; updateAudioStatus(); }); +aud.addEventListener("error", updateAudioStatus); setInterval(updateAudioStatus, 400); function fadeVolume(el, to, ms, done) {