diff --git a/web_realart/public/control/control.css b/web_realart/public/control/control.css index dead6fd..aab8471 100644 --- a/web_realart/public/control/control.css +++ b/web_realart/public/control/control.css @@ -237,3 +237,11 @@ button.queued { animation: queued-blink 600ms ease-in-out infinite alternate; } gap: 6px; font-size: 13px; color: #ccc; } .morceau-slot select { flex: 0 0 auto; background: #222; color: #eee; border: 1px solid #444; border-radius: 4px; padding: 2px 4px; } + +/* --- Réglages group --- */ +.morceau-settings { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; } +.morceau-set-row { display: grid; grid-template-columns: 1fr 2fr auto; align-items: center; gap: 6px; font-size: 12px; color: #ccc; } +.morceau-set-row output { min-width: 2.5em; text-align: right; color: #8c8; } +.morceau-keep { display: flex; flex-wrap: wrap; gap: 2px 8px; margin-top: 4px; font-size: 11px; color: #aaa; } +.morceau-keep > span { flex-basis: 100%; color: #888; } +.morceau-keep-box { display: inline-flex; align-items: center; gap: 2px; } diff --git a/web_realart/public/control/index.html b/web_realart/public/control/index.html index 38df3e6..585aff0 100644 --- a/web_realart/public/control/index.html +++ b/web_realart/public/control/index.html @@ -181,6 +181,8 @@
Actions globales (morceau)
+
Réglages
+
diff --git a/web_realart/public/control/js/morceau-panel.js b/web_realart/public/control/js/morceau-panel.js index 15b56f5..6d07c4a 100644 --- a/web_realart/public/control/js/morceau-panel.js +++ b/web_realart/public/control/js/morceau-panel.js @@ -3,9 +3,10 @@ // matrix-state.js, transport over osc.js. Later phases add settings + global controls. import { send, on, onOpen } from "./osc.js"; import { - GLOBAL_ACTION_CHOICES, GLOBAL_SLOTS, matGlobalActions, - setGlobalAction, saveMatState, + GLOBAL_ACTION_CHOICES, GLOBAL_SLOTS, matGlobalActions, setGlobalAction, saveMatState, + matGlobalSettings, setGlobalSetting, parseGlobalSettings, } from "./matrix-state.js"; +import { MATRIX_VOICES } from "./matrix-state.js"; export function init() { const host = document.getElementById("morceau-slots"); @@ -31,6 +32,72 @@ export function init() { wrap.appendChild(sel); host.appendChild(wrap); }); + // --- Réglages: thresholds, transient duration, breakdown kept-voices --- + const sHost = document.getElementById("morceau-settings"); + if (sHost) { + const sendSettings = () => { + const s = matGlobalSettings; + send("/matrix/globalsettings", s.openThresh, s.closeThresh, s.transientBars, + s.breakdownKeep.length, ...s.breakdownKeep); + saveMatState(); + }; + const slider = (key, label, min, max, step) => { + const row = document.createElement("label"); + row.className = "morceau-set-row"; + const span = document.createElement("span"); span.textContent = label; + const inp = document.createElement("input"); + inp.type = "range"; inp.min = min; inp.max = max; inp.step = step; + inp.value = matGlobalSettings[key]; + const out = document.createElement("output"); out.textContent = matGlobalSettings[key]; + inp.addEventListener("input", () => { out.textContent = inp.value; }); + inp.addEventListener("change", () => { + setGlobalSetting(key, key === "transientBars" ? Math.round(+inp.value) : +inp.value); + sendSettings(); + }); + row.append(span, inp, out); + sHost.appendChild(row); + return { inp, out }; + }; + const ctl = { + openThresh: slider("openThresh", "Seuil ouvert", 0.5, 0.95, 0.01), + closeThresh: slider("closeThresh", "Seuil fermé (sensibilité)", 0.05, 0.6, 0.01), + transientBars: slider("transientBars", "Durée (mesures)", 1, 8, 1), + }; + const keepWrap = document.createElement("div"); + keepWrap.className = "morceau-keep"; + const keepTitle = document.createElement("span"); + keepTitle.textContent = "Voix gardées (breakdown)"; + keepWrap.appendChild(keepTitle); + const keepBoxes = {}; + MATRIX_VOICES.forEach((v) => { + const lab = document.createElement("label"); lab.className = "morceau-keep-box"; + const cb = document.createElement("input"); cb.type = "checkbox"; cb.value = v; + cb.checked = matGlobalSettings.breakdownKeep.includes(v); + cb.addEventListener("change", () => { + const keep = MATRIX_VOICES.filter((x) => keepBoxes[x].checked); + setGlobalSetting("breakdownKeep", keep); + sendSettings(); + }); + keepBoxes[v] = cb; + lab.append(cb, document.createTextNode(v)); + keepWrap.appendChild(lab); + }); + sHost.appendChild(keepWrap); + on("/matrix/globalsettings", (args) => { + const s = parseGlobalSettings(args); + setGlobalSetting("openThresh", s.openThresh); + setGlobalSetting("closeThresh", s.closeThresh); + setGlobalSetting("transientBars", s.transientBars); + setGlobalSetting("breakdownKeep", s.breakdownKeep); + ctl.openThresh.inp.value = s.openThresh; ctl.openThresh.out.textContent = s.openThresh; + ctl.closeThresh.inp.value = s.closeThresh; ctl.closeThresh.out.textContent = s.closeThresh; + ctl.transientBars.inp.value = s.transientBars; ctl.transientBars.out.textContent = s.transientBars; + MATRIX_VOICES.forEach((v) => { keepBoxes[v].checked = s.breakdownKeep.includes(v); }); + saveMatState(); + }); + onOpen(() => send("/matrix/globalsettings/get")); + send("/matrix/globalsettings/get"); + } on("/matrix/globalaction", (args) => { const slot = Math.round(Number(args[0])); const id = String(args[1] || "none");