diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-06 13:36:19 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-06 13:36:19 +0100 |
| commit | a0888c1afa8bf178b7a57d4e80373ad867a3474a (patch) | |
| tree | ec7c4526d41e08c629c2e88115071b1614dbae34 /tools/spectral_editor/index.html | |
| parent | 3002553be5bf880ead27fb3e415bc97d484b43eb (diff) | |
feat(spectral_editor): Complete Phase 2 milestone - Full-featured web editor
MILESTONE: Spectral Brush Editor Phase 2 Complete (February 6, 2026)
Phase 2 delivers a production-ready web-based editor for creating procedural
audio by tracing spectrograms with parametric Bezier curves. This tool enables
replacing 5KB .spec binary assets with ~100 bytes of C++ code (50-100× compression).
Core Features Implemented:
========================
Audio I/O:
- Load .wav and .spec files as reference spectrograms
- Real-time audio preview (procedural vs original)
- Live volume control with GainNode (updates during playback)
- Export to procedural_params.txt (human-readable, re-editable format)
- Generate C++ code (copy-paste ready for demo integration)
Curve Editing:
- Multi-curve support with individual colors and volumes
- Bezier curve control points (frame, frequency, amplitude)
- Drag-and-drop control point editing
- Per-curve volume control (0-100%)
- Right-click to delete control points
- Curves only render within control point range (no spill)
Profile System (All 3 types implemented):
- Gaussian: exp(-(dist² / σ²)) - smooth harmonic falloff
- Decaying Sinusoid: exp(-decay × dist) × cos(ω × dist) - metallic resonance
- Noise: noise × exp(-(dist² / decay²)) - textured grit with decay envelope
Visualization:
- Log-scale frequency axis (20 Hz to 16 kHz) for better bass visibility
- Logarithmic dB-scale intensity mapping (-60 dB to +40 dB range)
- Reference opacity slider (0-100%) for mixing original/procedural views
- Playhead indicator (red dashed line) during playback
- Mouse crosshair with tooltip (frame number, frequency)
- Control point info panel (frame, frequency, amplitude)
Real-time Spectrum Viewer (NEW):
- Always-visible bottom-right overlay (200×100px)
- Shows frequency spectrum for frame under mouse (hover mode)
- Shows current playback frame spectrum (playback mode)
- Dual display: Reference (green) + Procedural (red) overlaid
- dB-scale bar heights for accurate visualization
- Frame number label (red during playback, gray when hovering)
Rendering Architecture:
- Destination-to-source pixel mapping (prevents gaps in log-scale)
- Offscreen canvas compositing for proper alpha blending
- Alpha channel for procedural intensity (pure colors, not dimmed)
- Steeper dB falloff for procedural curves (-40 dB floor vs -60 dB reference)
UI/UX:
- Undo/Redo system (50-action history)
- Keyboard shortcuts (1/2/Space for playback, Ctrl+Z/Ctrl+Shift+Z, Delete, Esc)
- File load confirmation (warns about unsaved curves)
- Automatic curve reset on new file load
Technical Details:
- DCT/IDCT implementation (JavaScript port matching C++ runtime)
- Overlap-add synthesis with Hanning window
- Web Audio API integration (32 kHz sample rate)
- Zero external dependencies (pure HTML/CSS/JS)
Files Modified:
- tools/spectral_editor/script.js (~1730 lines, main implementation)
- tools/spectral_editor/index.html (UI structure, spectrum viewer)
- tools/spectral_editor/style.css (VSCode dark theme styling)
- tools/spectral_editor/README.md (updated features, roadmap)
Phase 3 TODO (Next):
===================
- Effect combination system (noise + Gaussian modulation, layer compositing)
- Improved C++ code testing (validation, edge cases)
- Better frequency scale (mu-law or perceptual scale, less bass-heavy)
- Pre-defined shape library (kick, snare, hi-hat templates)
- Load procedural_params.txt back into editor (re-editing)
- FFT-based DCT optimization (O(N log N) vs O(N²))
Integration:
- Generate C++ code → Copy to src/audio/procedural_samples.cc
- Add PROC() entry to assets/final/demo_assets.txt
- Rebuild demo → Use AssetId::SOUND_PROC
handoff(Claude): Phase 2 complete. Next: FFT implementation task for performance optimization.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/spectral_editor/index.html')
| -rw-r--r-- | tools/spectral_editor/index.html | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/tools/spectral_editor/index.html b/tools/spectral_editor/index.html index 52f1d8f..a9391dd 100644 --- a/tools/spectral_editor/index.html +++ b/tools/spectral_editor/index.html @@ -27,6 +27,10 @@ <p>Load a .wav or .spec file to begin</p> <p class="hint">Click "Load .wav/.spec" button or press Ctrl+O</p> </div> + <!-- Mini spectrum viewer (bottom-right overlay) --> + <div id="spectrumViewer" class="spectrum-viewer"> + <canvas id="spectrumCanvas" width="200" height="100"></canvas> + </div> </div> <!-- Toolbar (right side, 20% width) --> @@ -39,6 +43,22 @@ <span class="icon">×</span> Delete </button> <div id="curveList" class="curve-list"></div> + + <h3>Selected Point</h3> + <div id="pointInfo" class="point-info"> + <div class="info-row"> + <span class="info-label">Frame:</span> + <span id="pointFrame" class="info-value">-</span> + </div> + <div class="info-row"> + <span class="info-label">Frequency:</span> + <span id="pointFreq" class="info-value">-</span> + </div> + <div class="info-row"> + <span class="info-label">Amplitude:</span> + <span id="pointAmp" class="info-value">-</span> + </div> + </div> </div> </div> @@ -56,9 +76,20 @@ <label for="sigmaSlider" id="sigmaLabel">Sigma:</label> <input type="range" id="sigmaSlider" class="slider" min="1" max="100" value="30" step="0.1"> <input type="number" id="sigmaValue" class="number-input" min="1" max="100" value="30" step="0.1"> + + <label for="curveVolumeSlider">Curve Vol:</label> + <input type="range" id="curveVolumeSlider" class="slider" min="0" max="100" value="100" step="1"> + <input type="number" id="curveVolumeValue" class="number-input" min="0" max="100" value="100" step="1"> + </div> + + <!-- Middle section: Display controls --> + <div class="control-section"> + <label for="refOpacitySlider">Ref Opacity:</label> + <input type="range" id="refOpacitySlider" class="slider" min="0" max="100" value="50" step="1"> + <input type="number" id="refOpacityValue" class="number-input" min="0" max="100" value="50" step="1"> </div> - <!-- Middle section: Curve selection --> + <!-- Curve selection --> <div class="control-section"> <label for="curveSelect">Active Curve:</label> <select id="curveSelect" class="select-input"> @@ -68,6 +99,12 @@ <!-- Right section: Playback controls --> <div class="control-section playback-controls"> + <label for="volumeSlider">Volume:</label> + <input type="range" id="volumeSlider" class="slider" min="0" max="100" value="100" step="1"> + <input type="number" id="volumeValue" class="number-input" min="0" max="100" value="100" step="1"> + </div> + + <div class="control-section playback-controls"> <button id="playProceduralBtn" class="btn-playback" title="Play procedural sound (Key 1)"> <span class="icon">▶</span> <kbd>1</kbd> Procedural </button> |
