summaryrefslogtreecommitdiff
path: root/tools/mq_editor/viewer.js
AgeCommit message (Collapse)Author
24 hoursfix(mq_editor): destroy old viewer listeners on WAV reloadskal
Each loadAudioBuffer() was creating a new SpectrogramViewer without removing the previous one's canvas event listeners. Old viewers would fire on every mouse event, rendering stale spectrogram data and calling editor.onPartialSelect() with out-of-range indices (hiding the amp panel). Fix: store handlers as named instance properties, add destroy() to remove them, and call destroy() before creating a new viewer. handoff(Claude): bug fix only, no behaviour change Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
24 hoursfeat(mq_editor): movable inner bezier control points + clamp() refactorskal
- P1/P2 in amp editor now draggable horizontally; t0<t1<t2<t3 enforced - Add clamp() to utils.js; replace all Math.max/min clamping patterns - Cursor hints: move for P1/P2, ns-resize for P0/P3 - Remove test_fft.html - Docs: Delete key, style.css/utils.js in architecture, bezier editor section handoff(Claude): inner control points done, clamp() adopted everywhere Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
27 hoursfeat(mq_editor): switch curve interpolation to Lagrange through all control ↵skal
points Replace cubic Bezier with Lagrange interpolation so P1/P2 are actual points on the curve. Eval uses stored t1/t2 as arbitrary knot positions. fitBezier keeps least-squares but with Lagrange basis at u=1/3,2/3. Remove endpoint companion drag (no longer tangent handles). TODO: support arbitrary number of inner control points. handoff(Claude): Lagrange interpolation replaces Bezier in mq_editor curve eval/fit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
28 hoursfeat(mq_editor): add iso-contour tracking mode for bass/diffuse regionsskal
trackIsoContour() follows constant energy level through STFT frames instead of peaks. Useful for broad bass areas where peak detector finds nothing. Preview in cyan, auto-detects spread on commit (naturally large). Toggle: ≋ Contour button or C key. Mutually exclusive with ⊕ Explore. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
28 hoursfeat(mq_editor): add explore mode for interactive partial trackingskal
Hover to preview a tracked partial from mouse position (peak-snapped, forward+backward MQ tracking). Click to commit. Toggle with ⊕ Explore button or X key. Escape exits explore mode. handoff(Gemini): explore mode added in mq_extract.trackFromSeed + viewer.js/app.js Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
28 hoursperf(mq_editor): move playhead to overlay canvas, avoid full render on tickskal
setPlayheadTime() now updates only the playhead overlay and spectrum panel instead of triggering a full renderSpectrogram() every rAF tick. handoff(Gemini): playhead is now an overlay canvas (like cursorCanvas), no more O(n_frames) redraw during playback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
29 hoursfeat(mq_editor): add new partial, undo/redoskal
- '+ Partial' button (N key): insert 440Hz/max-amp partial at front - Undo/Redo buttons (Ctrl+Z/Y): JSON snapshot stack, 50 levels - Hooks in delete, mute, curve edits, amp drag, freq drag handoff(Gemini): undo/redo + new-partial added to mq_editor Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
29 hoursfix(mq_editor): exclude below-keep partials from hit-test selectionskal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
30 hoursfix(mq_editor): apply coupled anchor drag to freqCurve in viewer canvasskal
Same P0↔P1 / P3↔P2 coupling as the amp editor, now for the frequency bezier dragged in the main spectrogram viewer. handoff(Claude): freq curve coupled drag fixed
30 hoursrefactor(mq_editor): consolidate duplicates, extract utils.js and app.jsskal
- utils.js (new): evalBezier (robust), getCanvasCoords, buildBandPoints - app.js (new): extract ~450-line inline script from index.html - editor.js: generalize _makeJogSlider(inp, options) with onUpdate cb, eliminate 50-line inline resonator jog duplication, use getCanvasCoords - mq_extract.js: extract findBestPeak(), replace two identical loop bodies - viewer.js: remove duplicate evalBezier, use getCanvasCoords/buildBandPoints - mq_synth.js: remove duplicate evalBezier - index.html: inline script removed, load order: utils→fft→extract→synth→viewer→editor→app handoff(Claude): mq_editor refactor complete — no logic changes, browser-ready. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
35 hoursfeat(mq_editor): jog sliders for synth params, reset partials on WAV load, ↵skal
panel refresh after extract - Clear extractedPartials and editor state when loading a new WAV - After extract, refresh right panels (re-select if index still valid) - Synth fields (decay, jitter, spread) get jog sliders: drag to nudge, spring-back on release - Spread extension limit dashed line: alpha 0.4→0.75, lineWidth 1→1.5, dash [3,4]→[4,3] handoff(Gemini): mq_editor UX polish — jog sliders, WAV reset, panel refresh, spread line visibility Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
35 hoursfeat(mq_editor): spread autodetection, 50% drop-off line, mini-spectrum peak fixskal
- autodetectSpread(): measures half-power (-3dB) peak width in spectrogram to infer spread_above/below (replaces near-zero bezier residual approach) - 'Auto' button per partial + 'Auto Spread All' toolbar button - Spread panel inputs now trigger viewer refresh on change - 50% drop-off dotted reference lines on spread band (selected partial only) - Mini-spectrum: use max() instead of mean() over bins per pixel column, fixing high-frequency amplitude mismatch between original and synthesis handoff(Gemini): spread autodetection and mini-spectrum fixes done
36 hoursfeat(mq_editor): tabbed freq/amp/synth panel, spread band viz, UI polishskal
- 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
38 hoursfeat(mq_editor): partial selection, amp bezier editor, and editor.js refactorskal
- Click-to-select partials on canvas (proximity hit test on bezier) - Right panel: peak freq/amp, time range, freq/amp bezier text inputs, mute/delete - Selected partial renders on top with glow + larger control points - Draggable freq curve control points on main canvas (grab/grabbing cursor) - Amplitude bezier editor: 120px canvas below spectrogram, time-synced with main view zoom/scroll via viewer.onRender callback - Amp edits live-affect synthesis (mq_synth.js already uses ampCurve) - PartialEditor class in editor.js owns all editing logic; index.html wires it with 5 calls (setViewer, setPartials, onPartialSelect, onRender, onPartialDeleted) handoff(Gemini): partial editing MVP complete. Next: freq curve drag polish or export (.spec generation). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
39 hoursrefactor(mq_editor): clean coordinate API and remove UI duplicationskal
viewer.js: - Add timeToX(), freqLogNorm(), normToFreq() coordinate primitives - freqToY/canvasToFreq now delegate to freqLogNorm/normToFreq - normalizeDB() replaces duplicated (magDB-(maxDB-80))/80 formula - partialColor(p) replaces repeated color array - All inline time/freq→pixel math replaced with API calls index.html: - getKeepCount() replaces 3 copies of the same calculation - playAudioBuffer() replaces duplicated playback setup + RAF loop handoff(Claude): refactor complete
39 hoursfeat(mq_editor): UI improvements and partial detection enhancementsskal
- Right panel with synthesis checkboxes (integrate phase, disable jitter, disable spread) - Style file chooser as button; show filename next to page title - Second backward pass in extractPartials to recover partial onsets - Cursor line drawn on overlay canvas (no full redraw on mousemove) handoff(Claude): UI + algo improvements complete
40 hoursfix(mq_editor): mini-spectrum and spectrogram display improvementsskal
- Fix mini-spectrum: log-scale frequency axis, per-pixel bin averaging, red peak bars after extraction - Fix key handlers swallowing digits in input fields - Clamp hop size to min 64 to prevent hang - Store maxDB in STFTCache, use it to normalize both mini-spectrum and main spectrogram (fixes clipping at 0dB for pure tones) - Add Test WAV console validation for 440/660Hz peaks - Grayscale colormap for main spectrogram handoff(Gemini): mq_editor display fixes complete, tests not affected
41 hoursfeat(mq_editor): log-scale frequency axis with clean freqToY/canvasToFreq APIskal
Replace all inline linear freq→Y math with freqToY()/canvasToFreq() pair. freqStart set to 20Hz (log-safe). Freq axis ticks now log-spaced. handoff(Gemini): log scale done, all render paths use freqToY/canvasToFreq
41 hoursrefactor(mq_editor): store only squared amplitude after FFT, drop re/imskal
handoff(Claude): removed full spectrum storage from STFTCache frames; getFFT() deleted; viewers use squaredAmplitude + 10*log10 directly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
41 hoursfix(mq_editor): Catmull-Rom bezier fit, NaN guard, synth FFT toggleskal
- evalBezier: guard dt<=0 to avoid NaN on degenerate curves - fitBezier: replace nearest-neighbor control points with Catmull-Rom tangents (Hermite->Bezier), curve now passes through endpoints - key 'a': toggle mini-spectrum between original and synth FFT handoff(Claude): bezier fix + synth FFT comparison Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
48 hoursfeat(mq_editor): sort partials by amplitude, keep% slider for reconstructionskal
- Sort extracted partials by decreasing peak amplitude - Add Keep% range slider (1-100%) to toolbar - Viewer draws omitted partials at 50% opacity (live on slider input) - synthesizeMQ uses only the top-N% partials handoff(Claude): partial amplitude filtering complete
2 daysfeat(mq_editor): peaks display, STFT cache refactor, threshold reactivityskal
- STFTCache: cache squaredAmplitude (re²+im²) per frame, add getSquaredAmplitude(t) - getMagnitudeDB uses cached sq amp (10*log10, no sqrt) - detectPeaks uses squaredAmp from cache instead of recomputing FFT - extractPartials: use cache frames, return {partials, frames} - Press 'p' to toggle raw peak overlay in viewer - threshold input: step=any, change event triggers re-extraction - runExtraction() shared by button and threshold change handoff(Claude): mq_partial peaks/cache refactor complete
2 daysclean-up pass mq-partialsskal
2 daysfeat(mq_editor): Complete Phase 2 - JS synthesizer with STFT cacheskal
Phase 2 - JS Synthesizer: - Created mq_synth.js with replica oscillator bank - Bezier curve evaluation (cubic De Casteljau algorithm) - Replica synthesis: frequency spread, amplitude decay, phase jitter - PCM buffer generation from extracted MQ partials - Normalization to prevent clipping - Key '1' plays synthesized audio, key '2' plays original - Playback comparison with animated playhead STFT Cache Optimization: - Created STFTCache class in fft.js for pre-computed windowed FFT frames - Clean interface: getFFT(t), getMagnitudeDB(t, freq), setHopSize() - Pre-computes all frames on WAV load (eliminates redundant FFT calls) - Dynamic cache update when hop size changes - Shared across spectrogram, tooltip, and mini-spectrum viewer - Significant performance improvement Mini-Spectrum Viewer: - Bottom-right overlay (200x100) matching spectral_editor style - Real-time FFT display at playhead or mouse position - 100-bar visualization with cyan-to-yellow gradient - Updates during playback or mouse hover Files: - tools/mq_editor/mq_synth.js (new) - tools/mq_editor/fft.js (STFTCache class added) - tools/mq_editor/index.html (synthesis playback, cache integration) - tools/mq_editor/viewer.js (cache-based rendering, spectrum viewer) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2 daysfeat(mq_editor): Improve partial tracking and add audio playbackskal
Tracking improvements: - Frequency-dependent threshold (5% of freq, min 20 Hz) - Candidate system requiring 3-frame persistence before birth - Extended death tolerance (5 frames) for robust trajectories - Minimum 10-frame length filter for valid partials - Result: cleaner, less scattered partial trajectories Audio playback: - Web Audio API integration for original WAV playback - Play/Stop buttons with proper state management - Animated red playhead bar during playback - Keyboard shortcuts: '2' plays original, '1' reserved for synthesis Visualization: - Power law (gamma=0.3) for improved spectrogram contrast Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2 daysfix(mq_editor): Improve spectrogram visualization and navigationskal
- Fixed FFT to 1024 bins for 31.25 Hz resolution (better bass analysis) - Refactored view state to zoom_factor + t_center for cleaner pan/zoom - Mousewheel scrolls horizontally, shift+mousewheel zooms (respects deltaX/Y) - Spectrogram bins now fill complete time/freq buckets at all zoom levels - Extended dB range to -80→0 dB (80 dB) for better high-amplitude granularity - Added real-time intensity tooltip in dB - 50% alpha on spectrogram to reduce clutter over partial trajectories Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2 daysfeat(mq_editor): Phase 1 - MQ extraction and visualization (SPECTRAL_BRUSH_2)skal
Implement McAulay-Quatieri sinusoidal analysis tool for audio compression. New files: - doc/SPECTRAL_BRUSH_2.md: Complete design doc (MQ algorithm, data format, synthesis, roadmap) - tools/mq_editor/index.html: Web UI (file loader, params, canvas) - tools/mq_editor/fft.js: Radix-2 Cooley-Tukey FFT (from spectral_editor) - tools/mq_editor/mq_extract.js: MQ algorithm (peak detection, tracking, bezier fitting) - tools/mq_editor/viewer.js: Visualization (spectrogram, partials, zoom, axes) - tools/mq_editor/README.md: Usage and implementation status Features: - Load WAV → extract sinusoidal partials → fit cubic bezier curves - Time-frequency spectrogram with hot colormap (0-16 kHz) - Horizontal zoom (mousewheel) around mouse position - Axis ticks with labels (time: seconds, freq: Hz/kHz) - Mouse tooltip showing time/frequency coordinates - Real-time adjustable MQ parameters (FFT size, hop, threshold) Algorithm: - STFT with Hann windows (2048 FFT, 512 hop) - Peak detection with parabolic interpolation - Birth/death/continuation tracking (50 Hz tolerance) - Cubic bezier fitting (4 control points per trajectory) Next: Phase 2 (JS synthesizer for audio preview) handoff(Claude): MQ editor Phase 1 complete. Ready for synthesis implementation.