Files
AV-Live/web_realart/public/control/js/transport.js
T
L'électron rare 8cfa0694a7
CI build oscope-of / build-check (push) Has been cancelled
feat(web): tempo + master steppers on matrix tab
Same -/+ stepper controls duplicated on the MATRICE tab; the wiring is
factorized into bindStepGroup so both tabs' sliders and readouts stay
in sync while driving the same OSC addresses.
2026-07-02 22:43:02 +02:00

71 lines
2.8 KiB
JavaScript

// js/transport.js — beat/rms feedback + tempo, filter, quantise controls.
import { send, on } from "./osc.js";
let beatFlashTimer = null;
export function init() {
// /sync/beat — flash beat dot for 80 ms
on("/sync/beat", () => {
const beatDot = document.getElementById("beat-dot");
if (!beatDot) return;
if (beatFlashTimer !== null) { clearTimeout(beatFlashTimer); beatFlashTimer = null; }
beatDot.classList.add("flash");
beatFlashTimer = setTimeout(() => {
beatDot.classList.remove("flash");
beatFlashTimer = null;
}, 80);
});
// /sync/rms — drive master VU meter width
on("/sync/rms", (args) => {
const raw = Number(args[0]);
const rms = Number.isFinite(raw) ? Math.max(0, Math.min(1, raw)) : 0;
const bar = document.getElementById("vu-bar");
if (bar) bar.style.width = `${rms * 100}%`;
});
// Tempo / Master: sliders + -/+ steppers, duplicated on the LIVE and
// MATRICE tabs — every group member drives the same OSC address and all
// members stay visually in sync.
const bindStepGroup = (groups, step, fmt, addr) => {
const push = (v) => {
groups.forEach((g) => {
const s = document.getElementById(g.slider);
const l = document.getElementById(g.val);
if (s) s.value = v;
if (l) l.textContent = fmt(v);
});
send(addr, +v);
};
groups.forEach((g) => {
const s = document.getElementById(g.slider);
const clamp = (v) => Math.max(+s.min, Math.min(+s.max, v));
const m = document.getElementById(g.minus);
const p = document.getElementById(g.plus);
s && s.addEventListener("input", () => push(+s.value));
s && m && m.addEventListener("click", () => push(clamp(+s.value - step)));
s && p && p.addEventListener("click", () => push(clamp(+s.value + step)));
});
};
bindStepGroup([
{ slider: "tempo", minus: "tempo-minus", plus: "tempo-plus", val: "tempo-val" },
{ slider: "matrix-tempo", minus: "matrix-tempo-minus", plus: "matrix-tempo-plus", val: "matrix-tempo-val" },
], 1, (v) => String(Math.round(v)), "/launch/tempo");
bindStepGroup([
{ slider: "master", minus: "master-minus", plus: "master-plus", val: "master-val" },
{ slider: "matrix-master", minus: "matrix-master-minus", plus: "matrix-master-plus", val: "matrix-master-val" },
], 0.05, (v) => (+v).toFixed(2), "/control/doMaster");
// Filter
const filt = document.getElementById("filter");
filt && filt.addEventListener("input", () => send("/control/fx/filter", +filt.value));
// Quantize selector
document.querySelectorAll(".quant-btn").forEach(btn =>
btn.addEventListener("click", () => {
document.querySelectorAll(".quant-btn").forEach(b => b.classList.remove("active"));
btn.classList.add("active");
send("/launch/quant", +btn.dataset.quant);
}));
}