From 082959062671e0e1a1482fac8dc5f77e05060bee Mon Sep 17 00:00:00 2001 From: skal Date: Wed, 18 Feb 2026 11:11:21 +0100 Subject: feat(mq_editor): E key for extract, style cleanup, doc update - Map 'E' key to Extract Partials - Move extractBtn inline style to CSS rule #extractBtn - Hoist autoSpreadAllBtn DOM ref to top with other refs - Drop unused PADY local var in _renderAmpEditor - Remove redundant comment before extractBtn listener - README: add E/Esc keys, add editor.js to architecture, mark Phase 3 done handoff(Gemini): mq_editor UX polish + doc consolidated Co-Authored-By: Claude Sonnet 4.6 --- tools/mq_editor/README.md | 12 ++++++++++-- tools/mq_editor/editor.js | 1 - tools/mq_editor/index.html | 8 +++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/mq_editor/README.md b/tools/mq_editor/README.md index 4250d33..141963a 100644 --- a/tools/mq_editor/README.md +++ b/tools/mq_editor/README.md @@ -35,14 +35,17 @@ open tools/mq_editor/index.html |-----|--------| | `1` | Play synthesized audio | | `2` | Play original audio | +| `E` | Extract Partials | | `P` | Toggle raw peak overlay | | `A` | Toggle mini-spectrum: original ↔ synthesized | +| `Esc` | Deselect partial | | Shift+scroll | Zoom time axis | | Scroll | Pan time axis | ## Architecture -- `index.html` — UI, playback, extraction orchestration +- `index.html` — UI, playback, extraction orchestration, keyboard shortcuts +- `editor.js` — Property panel and amplitude bezier editor for selected partials - `fft.js` — Cooley-Tukey radix-2 FFT + STFT cache - `mq_extract.js` — MQ algorithm: peak detection, forward tracking, backward expansion, bezier fitting - `mq_synth.js` — Oscillator bank synthesis from extracted partials @@ -83,7 +86,12 @@ open tools/mq_editor/index.html - [x] Replica oscillator bank (spread, jitter, phase integration) - [x] Synthesis debug checkboxes (disable jitter/spread) - [x] Synthesized STFT cache for FFT comparison -- [ ] Phase 3: Editing UI (drag control points, replicas) +- [x] Phase 3: Editing UI + - [x] Partial selection with property panel (freq/amp/synth tabs) + - [x] Amplitude bezier drag editor + - [x] Synth params with jog sliders (decay, jitter, spread) + - [x] Auto-spread detection per partial and global + - [x] Mute / delete partials - [ ] Phase 4: Export (.spec + C++ code generation) ## See Also diff --git a/tools/mq_editor/editor.js b/tools/mq_editor/editor.js index b767534..157186a 100644 --- a/tools/mq_editor/editor.js +++ b/tools/mq_editor/editor.js @@ -275,7 +275,6 @@ class PartialEditor { const canvas = this._ampCanvas; const ctx = this._ampCtx; const W = canvas.width, H = canvas.height; - const PADY = 10; // Sync time range with viewer const amp = this._amp; diff --git a/tools/mq_editor/index.html b/tools/mq_editor/index.html index fa7543c..f6d052b 100644 --- a/tools/mq_editor/index.html +++ b/tools/mq_editor/index.html @@ -40,6 +40,7 @@ } button:hover { background: #4a4a4a; } button:disabled { opacity: 0.5; cursor: not-allowed; } + #extractBtn { background: #666; color: #fff; font-weight: bold; border-color: #888; } input[type="file"] { display: none; } .params { display: inline-block; @@ -356,6 +357,7 @@ const wavFile = document.getElementById('wavFile'); const chooseFileBtn = document.getElementById('chooseFileBtn'); const extractBtn = document.getElementById('extractBtn'); + const autoSpreadAllBtn = document.getElementById('autoSpreadAllBtn'); const playBtn = document.getElementById('playBtn'); const stopBtn = document.getElementById('stopBtn'); const canvas = document.getElementById('canvas'); @@ -512,14 +514,11 @@ }, 50); } - // Extract partials extractBtn.addEventListener('click', () => { if (!audioBuffer) return; runExtraction(); }); - // Auto-spread all partials - const autoSpreadAllBtn = document.getElementById('autoSpreadAllBtn'); autoSpreadAllBtn.addEventListener('click', () => { if (!extractedPartials || !stftCache) return; const fs = stftCache.fftSize; @@ -642,6 +641,9 @@ viewer.showSynthFFT = !viewer.showSynthFFT; viewer.renderSpectrum(); } + } else if (e.code === 'KeyE') { + e.preventDefault(); + if (!extractBtn.disabled) extractBtn.click(); } else if (e.code === 'Escape') { if (viewer) viewer.selectPartial(-1); } -- cgit v1.2.3