Added comprehensive playback level monitoring system that shows
real-time audio levels during playback for each track.
useMultiTrackPlayer Hook:
- Added AnalyserNode for each track in audio graph
- Implemented RMS-based level calculation with requestAnimationFrame
- Added trackLevels state (Record<string, number>) tracking levels by track ID
- Insert analysers after effects chain, before master gain
- Monitor levels continuously during playback
- Clean up level monitoring on pause/stop
Audio Graph Chain:
source -> gain -> pan -> effects -> analyser -> master gain -> destination
AudioEditor Integration:
- Extract trackLevels from useMultiTrackPlayer hook
- Pass trackLevels down to TrackList component
TrackList & Track Components:
- Accept and forward trackLevels prop
- Pass playbackLevel to individual Track components
- Track component displays appropriate level:
* Recording level (with "Input" label) when armed/recording
* Playback level (with "Level" label) during normal playback
Visual Feedback:
- Color-coded meters: green -> yellow (70%) -> red (90%)
- Real-time percentage display
- Seamless switching between input and output modes
This completes Phase 8 (Recording) with full bidirectional level monitoring!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed the input level meter staying at 0% during recording by:
Closure Issue Resolution:
- Added isMonitoringRef to track monitoring state independent of React state
- Removed state dependencies from monitorInputLevel callback
- Animation loop now checks ref instead of stale closure state
Changes:
- Set isMonitoringRef.current = true when starting recording
- Set isMonitoringRef.current = false when stopping/pausing recording
- Animation frame continues while ref is true, stops when false
- Proper cleanup in stopRecording, pauseRecording, and unmount effect
This ensures the requestAnimationFrame loop continues properly and
updates the RMS level calculation in real-time during recording.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added migration logic to useMultiTrack hook:
- When loading tracks from localStorage, check if height < DEFAULT_TRACK_HEIGHT
- Automatically upgrade old heights (120px, 150px) to new default (180px)
- Preserves custom heights that are already >= 180px
This fixes the inline style issue where existing tracks had
style="height: 120px" that was cutting off the level meter.
After this update, refreshing the page will automatically upgrade
all existing tracks to the new height without losing any data.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added recording capabilities to the multi-track editor:
- useRecording hook with MediaRecorder API integration
- Audio input device enumeration and selection
- Microphone permission handling
- Input level monitoring with RMS calculation
- InputLevelMeter component with visual feedback
- Record-enable button per track with pulsing indicator
- Real-time input level display when recording
Recording infrastructure is complete. Next: integrate into AudioEditor
for global recording control and buffer storage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive selection and editing capabilities to multi-track editor:
- Visual selection overlay with Shift+drag interaction on waveforms
- Multi-track edit commands (cut, copy, paste, delete, duplicate)
- Full keyboard shortcut support (Ctrl+X/C/V/D, Delete, Ctrl+Z/Y)
- Complete undo/redo integration via command pattern
- Per-track selection state with localStorage persistence
- Audio buffer manipulation utilities (extract, insert, delete, duplicate segments)
- Toast notifications for all edit operations
- Red playhead to distinguish from blue selection overlay
All edit operations are fully undoable and integrated with the existing
history manager system.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Architecture:
- Each track now has its own effect chain stored in track.effectChain
- Separate master effect chain for the final mix output
- SidePanel has 3 tabs: Tracks, Track FX, Master FX
Changes:
- types/track.ts: Add effectChain field to Track interface
- lib/audio/track-utils.ts: Initialize effect chain when creating tracks
- lib/hooks/useMultiTrack.ts: Exclude effectChain from localStorage, recreate on load
- components/editor/AudioEditor.tsx:
- Add master effect chain state using useEffectChain hook
- Add handlers for per-track effect chain manipulation
- Pass both track and master effect chains to SidePanel
- components/layout/SidePanel.tsx:
- Update to 3-tab interface (Tracks | Track FX | Master FX)
- Track FX tab shows effects for currently selected track
- Master FX tab shows master bus effects with preset management
- Different icons for track vs master effects tabs
Note: Effect processing in Web Audio API not yet implemented.
This commit sets up the data structures and UI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add masterVolume state to AudioEditor (default 0.8)
- Pass masterVolume to useMultiTrackPlayer hook
- Create master gain node in audio graph
- Connect all tracks through master gain before destination
- Update master gain in real-time when volume changes
- Wire up PlaybackControls volume slider and mute button
- Clean up master gain node on unmount
Fixes global volume and mute controls not working in transport controls.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed issue where currentTime wasn't updating during playback:
- Removed 'isPlaying' from updatePlaybackPosition dependencies
- This was causing the RAF loop to stop when state changed
- Now animation frame continues running throughout playback
- Playhead now updates smoothly in waveform and timeline slider
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed [object Object] display in Effect Chain section of SidePanel
by adding String() conversion to selectedTrack.name.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Explicitly whitelist track fields when saving to localStorage to prevent
DOM element references (HTMLButtonElement with React fiber) from being
serialized. This fixes the circular structure JSON error.
Changes:
- Changed from spread operator exclusion to explicit field whitelisting
- Ensured track.name is always converted to string
- Only serialize Track interface fields that should be persisted
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added string conversion and error handling when loading tracks from localStorage to prevent corrupted data from causing React rendering errors. If localStorage data is corrupted, it will be cleared automatically.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed the "Converting circular structure to JSON" error in useMultiTrack by properly destructuring audioBuffer from track objects before serializing to localStorage.
Changed from spreading the entire track object (which could have circular refs) to explicitly excluding audioBuffer using destructuring.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added real-time multi-track audio mixing and playback:
**useMultiTrackPlayer Hook:**
- Real-time multi-track audio mixing with Web Audio API
- Synchronized playback across all tracks
- Dynamic gain control respecting solo/mute states
- Per-track panning with constant power panning
- Seek functionality with automatic resume
- Playback position tracking with requestAnimationFrame
- Automatic duration calculation from longest track
- Clean resource management and cleanup
**Features:**
- ✅ Play/Pause/Stop controls for multi-track
- ✅ Solo/Mute handling (if any track is soloed, only soloed tracks play)
- ✅ Per-track volume control (0-1 range)
- ✅ Per-track pan control (-1 left to +1 right)
- ✅ Real-time parameter updates during playback
- ✅ Seamless seek with playback state preservation
- ✅ Automatic stop when reaching end of longest track
**Audio Graph Architecture:**
For each track: BufferSource → GainNode → StereoPannerNode → Destination
The mixer applies:
- Volume attenuation based on track volume setting
- Solo/Mute logic (getTrackGain utility)
- Constant power panning for smooth stereo positioning
Next: Integrate multi-track UI into AudioEditor
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Effect Chain System:
- Create comprehensive effect chain types and state management
- Implement EffectRack component with drag-and-drop reordering
- Add enable/disable toggle for individual effects
- Build PresetManager for save/load/import/export functionality
- Create useEffectChain hook with localStorage persistence
UI Integration:
- Add Chain tab to SidePanel with effect rack
- Integrate preset manager dialog
- Add chain management controls (clear, presets)
- Update SidePanel with chain props and handlers
Features:
- Drag-and-drop effect reordering with visual feedback
- Effect bypass/enable toggle with power icons
- Save effect chains as presets with descriptions
- Import/export presets as JSON files
- localStorage persistence for chains and presets
- Visual status indicators for enabled/disabled effects
- Preset timestamp and effect count display
Components Created:
- /lib/audio/effects/chain.ts - Effect chain types and utilities
- /components/effects/EffectRack.tsx - Visual effect chain component
- /components/effects/PresetManager.tsx - Preset management dialog
- /lib/hooks/useEffectChain.ts - Effect chain state hook
Updated PLAN.md:
- Mark Phase 6.6 as complete
- Update current status to Phase 6.6 Complete
- Add effect chain features to working features list
- Update Next Steps to show Phase 6 complete
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Complete rewrite of seeking logic to support both scrubbing and
click-to-play functionality with proper state management.
Changes:
1. Added autoPlay parameter to seek() methods across the stack
2. Waveform behavior:
- Click and drag → scrubs WITHOUT auto-play during drag
- Mouse up after drag → auto-plays from release position
- This allows smooth scrubbing while dragging
3. Timeline slider behavior:
- onChange → seeks WITHOUT auto-play (smooth dragging)
- onMouseUp/onTouchEnd → auto-plays from final position
4. Transport button state now correctly syncs with playback state
Technical implementation:
- player.seek(time, autoPlay) - autoPlay defaults to false
- If autoPlay=true OR was already playing → continues playback
- If autoPlay=false AND wasn't playing → just seeks (isPaused=true)
- useAudioPlayer.seek() now reads actual player state after seeking
User experience:
✓ Click on waveform → music plays from that position
✓ Drag on waveform → scrubs smoothly, plays on release
✓ Drag timeline slider → scrubs smoothly, plays on release
✓ Transport buttons show correct state (Play/Pause)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed issue where Play/Pause buttons didn't update after clicking on
waveform or timeline slider.
Problem:
- seek() in useAudioPlayer hook only updated currentTime
- But player.seek() now auto-starts playback
- React state (isPlaying, isPaused) wasn't updated
- Transport buttons showed wrong state (Play instead of Pause)
Solution:
- Update isPlaying = true and isPaused = false in seek callback
- Now transport buttons correctly show Pause icon when seeking
- UI state matches actual playback state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive undo/redo functionality:
- Command pattern interface and base classes
- HistoryManager with 50-operation stack
- EditCommand for all edit operations (cut, delete, paste, trim)
- Full keyboard shortcuts (Ctrl+Z undo, Ctrl+Y/Ctrl+Shift+Z redo)
- HistoryControls UI component with visual feedback
- Integrated history system with all edit operations
- Toast notifications for undo/redo actions
- History state tracking and display
New files:
- lib/history/command.ts - Command interface and BaseCommand
- lib/history/history-manager.ts - HistoryManager class
- lib/history/commands/edit-command.ts - EditCommand and factory functions
- lib/hooks/useHistory.ts - React hook for history management
- components/editor/HistoryControls.tsx - History UI component
Modified files:
- components/editor/AudioEditor.tsx - Integrated history system
- components/editor/EditControls.tsx - Updated keyboard shortcuts display
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 2 Complete Features:
- Web Audio API context management with browser compatibility
- Audio file upload with drag-and-drop support
- Audio decoding for multiple formats (WAV, MP3, OGG, FLAC, AAC, M4A)
- AudioPlayer class with full playback control
- Waveform visualization using Canvas API
- Real-time waveform rendering with progress indicator
- Playback controls (play, pause, stop, seek)
- Volume control with mute/unmute
- Timeline scrubbing
- Audio file information display
Components:
- AudioEditor: Main editor container
- FileUpload: Drag-and-drop file upload component
- AudioInfo: Display audio file metadata
- Waveform: Canvas-based waveform visualization
- PlaybackControls: Transport controls with volume slider
Audio Engine:
- lib/audio/context.ts: AudioContext management
- lib/audio/decoder.ts: Audio file decoding utilities
- lib/audio/player.ts: AudioPlayer class for playback
- lib/waveform/peaks.ts: Waveform peak generation
Hooks:
- useAudioPlayer: Complete audio player state management
Types:
- types/audio.ts: TypeScript definitions for audio types
Features Working:
✓ Load audio files via drag-and-drop or file picker
✓ Display waveform with real-time progress
✓ Play/pause/stop controls
✓ Seek by clicking on waveform or using timeline slider
✓ Volume control with visual feedback
✓ Audio file metadata display (duration, sample rate, channels)
✓ Toast notifications for user feedback
✓ SSR-safe audio context initialization
✓ Dark/light theme support
Tech Stack:
- Web Audio API for playback
- Canvas API for waveform rendering
- React 19 hooks for state management
- TypeScript for type safety
Build verified and working ✓
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>