From 6aeca94222961e0041ade935c77600d61d7cc7f9 Mon Sep 17 00:00:00 2001 From: Me Here Date: Sun, 31 May 2026 18:29:53 -0500 Subject: [PATCH] PE-1 editor display: match the device (always-elapsed, ramp, device link) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring the web editor's display in line with the PM_K-1 device screen: - Elapsed stopwatch is always visible and counts while playing (was gated behind the Timers switch); the switch now governs only the countdown. - Tempo-ramp indicator in the display (↗/↘ amount/everyBars), shown whenever a ramp is active — mirrors the device's ramp arrow. - Header "device" badge that lights green with the port name while a PM_K-1 / PM_X-1 is connected over USB-MIDI, updated live on connect/disconnect. The editor requests MIDI on load (Chrome remembers the grant) so it reflects the link automatically; the badge is also click-to-connect. editor-beta.html (separate live-sync variant) left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) --- editor.html | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/editor.html b/editor.html index c86a2fd..cace70d 100644 --- a/editor.html +++ b/editor.html @@ -253,6 +253,7 @@

PM_E‑1 PolyMeter Editor

+ ◎ connect device
@@ -267,6 +268,7 @@
120
0:00 +
@@ -1201,7 +1203,13 @@ async function _ensureMidi() { // MIDI access WITH SysEx (needed to send/ _midiAccess.onstatechange = _wireMidi; _wireMidi(); return true; } -function _wireMidi() { for (const inp of _midiInputs()) inp.onmidimessage = onDeviceMidi; updateMidiBtn(); } +function _wireMidi() { for (const inp of _midiInputs()) inp.onmidimessage = onDeviceMidi; updateMidiBtn(); updateDevBadge(); } +function updateDevBadge() { // header badge: lights green while a PM_K-1 / PM_X-1 is connected over USB-MIDI + const el = $("devBadge"); if (!el) return; + const dev = _midiAccess ? [..._midiOutputs(), ..._midiInputs()].filter(_isDevicePort) : []; + if (dev.length) { el.textContent = "● " + (dev[0].name || "device").slice(0, 18); el.style.color = "#2fe07a"; el.style.borderColor = "#2fe07a"; } + else { el.textContent = _midiAccess ? "◎ no device" : "◎ connect device"; el.style.color = "var(--muted)"; el.style.borderColor = "var(--edge)"; } +} function onDeviceMidi(e) { const d = e.data; if (!d) return; if (d[0] === 0xF0 && d[1] === 0x7D) { // our SysEx reply @@ -1403,9 +1411,9 @@ function tickTimers() { const now = Date.now(); const dt = timers.last ? Math.min(now - timers.last, 1000) : 0; // clamp so backgrounded gaps don't jump timers.last = now; - if (timersOn && state.running) { - timers.elapsedMs += dt; - if (timers.totalMs > 0) { + if (state.running) { + timers.elapsedMs += dt; // elapsed stopwatch always runs while playing (like the device) + if (timersOn && timers.totalMs > 0) { const before = timers.remainingMs; timers.remainingMs -= dt; // time countdown hit 0 → auto-advance (smooth). Bar-length segments use the @@ -1420,10 +1428,12 @@ function tickTimers() { renderTimers(); } function renderTimers() { - $("dtimers").hidden = !timersOn; - if (!timersOn) return; + $("dtimers").hidden = false; // elapsed + ramp always visible (like the device) $("elapsedVal").textContent = fmtClock(timers.elapsedMs); - const off = timers.totalMs <= 0; + const rw = $("rampWrap"); // tempo-ramp indicator (matches the device's ramp arrow) + if (ramp.on) { rw.hidden = false; rw.textContent = (ramp.amount < 0 ? "↘ " : "↗ ") + (ramp.amount >= 0 ? "+" : "") + ramp.amount + "/" + ramp.everyBars + "b"; } + else rw.hidden = true; + const off = !timersOn || timers.totalMs <= 0; $("countWrap").hidden = off; // hide time countdown when off if (!off) { const cd = $("countVal"); @@ -1576,6 +1586,7 @@ $("saveDeviceBtn").addEventListener("click", () => { $("trayMenu").hidden = true $("loadDeviceBtn").addEventListener("click", () => { $("trayMenu").hidden = true; loadFromDevice(); }); $("updateFwBtn").addEventListener("click", () => { $("trayMenu").hidden = true; updateFirmware(); }); $("midiBtn").addEventListener("click", toggleDeviceAudio); +$("devBadge").addEventListener("click", () => { _ensureMidi().then(updateDevBadge); }); $("clearLogBtn").addEventListener("click", () => { $("trayMenu").hidden = true; clearLog(); }); $("resetAllBtn").addEventListener("click", () => { $("trayMenu").hidden = true; resetAll(); }); $("shareSettingsBtn").addEventListener("click", () => { $("trayMenu").hidden = true; shareSettings(); }); @@ -1663,6 +1674,10 @@ updateCtx(); refreshFeatureBoxes(); $("continueMode").checked = continueMode; $("timersOn").checked = timersOn; +// Connect to a PM_K-1 / PM_X-1 over USB-MIDI on load so the header badge reflects the link +// (Chrome remembers the grant; first visit prompts once). updateDevBadge runs via _wireMidi. +if (navigator.requestMIDIAccess) _ensureMidi().then(updateDevBadge).catch(() => updateDevBadge()); +else updateDevBadge(); requestAnimationFrame(drawLoop); /*@BUILD:include:src/chrome.js@*/