diff --git a/editor.html b/editor.html
index c86a2fd..cace70d 100644
--- a/editor.html
+++ b/editor.html
@@ -253,6 +253,7 @@
@@ -267,6 +268,7 @@
120
⏱ 0:00
+
⏳ 0:00
▦ 0
@@ -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@*/