From 78faa77b208d20c01c242a942a1ddf9278f4ef17 Mon Sep 17 00:00:00 2001 From: skal Date: Wed, 18 Feb 2026 10:17:07 +0100 Subject: feat(mq_editor): tabbed freq/amp/synth panel, spread band viz, UI polish - Freq/Amp curve params now in tabs to save vertical space - Add Synth tab: per-partial decay, jitter, spread_above/below controls - Visualize spread band on selected partial (filled band + dashed bounds) - Larger fonts and right panel (14px body, 260px panel width) - Non-kept partials at 0.12 alpha (was 0.5) - Default threshold -20dB (was -60dB) handoff(Claude): mq_editor UI/UX improvements --- tools/mq_editor/editor.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'tools/mq_editor/editor.js') diff --git a/tools/mq_editor/editor.js b/tools/mq_editor/editor.js index e1e70c6..441f787 100644 --- a/tools/mq_editor/editor.js +++ b/tools/mq_editor/editor.js @@ -11,6 +11,7 @@ class PartialEditor { this._ampTitle = document.getElementById('ampEditTitle'); this._freqGrid = document.getElementById('freqCurveGrid'); this._ampGrid = document.getElementById('ampCurveGrid'); + this._synthGrid = document.getElementById('synthGrid'); this._ampCtx = this._ampCanvas ? this._ampCanvas.getContext('2d') : null; // References set by host @@ -82,6 +83,7 @@ class PartialEditor { this._buildCurveGrid(this._freqGrid, partial, 'freqCurve', 'f', index); this._buildCurveGrid(this._ampGrid, partial, 'ampCurve', 'a', index); + this._buildSynthGrid(partial, index); } _buildCurveGrid(grid, partial, curveKey, valueLabel, partialIndex) { @@ -113,6 +115,39 @@ class PartialEditor { } } + _buildSynthGrid(partial, index) { + const grid = this._synthGrid; + grid.innerHTML = ''; + const defaults = { decay_alpha: 0.1, jitter: 0.05, spread_above: 0.02, spread_below: 0.02 }; + const rep = partial.replicas || {}; + const params = [ + { key: 'decay_alpha', label: 'decay', step: '0.001' }, + { key: 'jitter', label: 'jitter', step: '0.001' }, + { key: 'spread_above', label: 'spread ↑', step: '0.001' }, + { key: 'spread_below', label: 'spread ↓', step: '0.001' }, + ]; + for (const p of params) { + const val = rep[p.key] != null ? rep[p.key] : defaults[p.key]; + const lbl = document.createElement('span'); + lbl.textContent = p.label; + const inp = document.createElement('input'); + inp.type = 'number'; + inp.value = val.toFixed(3); + inp.step = p.step; + inp.min = '0'; + inp.addEventListener('change', (e) => { + if (!this.partials) return; + const v = parseFloat(e.target.value); + if (isNaN(v)) return; + if (!this.partials[index].replicas) + this.partials[index].replicas = { ...defaults }; + this.partials[index].replicas[p.key] = v; + }); + grid.appendChild(lbl); + grid.appendChild(inp); + } + } + _makeCurveUpdater(partialIndex, curveKey, field, pointIndex) { return (e) => { if (!this.partials) return; -- cgit v1.2.3