| Age | Commit message (Collapse) | Author |
|
- 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>
|
|
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
|
|
- 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
|
|
audio
- Fix incoherent per-sample jitter/spread: seed by partial index only
- Fix || fallback for zero-valued params (use != null checks)
- Phase integration: accumulator (2π*f/SR per sample) replaces 2π*f*t
- Add 'Integrate phase' checkbox to toggle between modes
- Revert Catmull-Rom back to simple bezier (1/3, 2/3 sample points)
- Remove all debug logging, clean up trackPartials, fitBezier
handoff(Gemini): dual-sine test validates full MQ pipeline (extract→track→synth).
Next: real audio loading and partial detection improvements.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- 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
|
|
Generates 2s of 440+660Hz (A4+E5) at 32kHz without needing a file.
Refactors WAV load path into shared loadAudioBuffer() used by both
file input and the test button.
handoff(Gemini): test button wired, full UI pipeline testable without assets.
|
|
- 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>
|
|
- 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
|
|
- 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
|
|
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>
|
|
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>
|
|
- 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>
|
|
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.
|