summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-18 11:11:21 +0100
committerskal <pascal.massimino@gmail.com>2026-02-18 11:11:21 +0100
commit082959062671e0e1a1482fac8dc5f77e05060bee (patch)
tree420af2481cbdc8aa77968c05e386bfe7db99e9d7 /tools
parent890f4fdf96945832d5da078cb795266127cf122d (diff)
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 <noreply@anthropic.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/mq_editor/README.md12
-rw-r--r--tools/mq_editor/editor.js1
-rw-r--r--tools/mq_editor/index.html8
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);
}