Commit Graph

39 Commits

Author SHA1 Message Date
03a7e2e485 feat: implement Phase 9.1 - Automation lanes UI
Added comprehensive automation lane UI with Ableton-style design:

**Automation Components:**
- AutomationLane: Canvas-based rendering with grid lines, curves, and points
- AutomationHeader: Parameter name, mode selector, value display
- AutomationPoint: Interactive draggable points with hover states

**Automation Utilities:**
- createAutomationLane/Point: Factory functions
- evaluateAutomationLinear: Interpolation between points
- formatAutomationValue: Display formatting with unit support
- addAutomationPoint/updateAutomationPoint/removeAutomationPoint

**Track Integration:**
- Added "A" toggle button in track control panel
- Automation lanes render below waveform
- Default lanes for Volume (orange) and Pan (green)
- Support for add/edit/delete automation points
- Click to add, drag to move, double-click to delete

**Visual Design:**
- Dark background with horizontal grid lines
- Colored curves with semi-transparent fill (20% opacity)
- 4-6px automation points, 8px on hover
- Mode indicators (Read/Write/Touch/Latch) with colors
- Value labels and current value display

Ready for playback integration in next step.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 18:34:35 +01:00
17381221d8 feat: refine UI with effects panel improvements and visual polish
Major improvements:
- Fixed multi-file import (FileList to Array conversion)
- Auto-select first track when adding to empty project
- Global effects panel folding state (independent of track selection)
- Effects panel collapsed/disabled when no track selected
- Effect device expansion state persisted per-device
- Effect browser with searchable descriptions

Visual refinements:
- Removed center dot from pan knob for cleaner look
- Simplified fader: removed volume fill overlay, dynamic level meter visible through semi-transparent handle
- Level meter capped at fader position (realistic mixer behavior)
- Solid background instead of gradient for fader track
- Subtle volume overlay up to fader handle
- Fixed track control width flickering (consistent 4px border)
- Effect devices: removed shadows/rounded corners for flatter DAW-style look, added consistent border-radius
- Added border between track control and waveform area

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 18:13:38 +01:00
9b1eedc379 feat: Ableton Live-style effects and complete automation system
Enhanced visual design:
- Improved device rack container with darker background and inner shadow
- Device cards now have rounded corners, shadows, and colored indicators
- Better visual separation between enabled/disabled effects
- Active devices highlighted with accent border

Complete automation infrastructure (Phase 9):
- Created comprehensive type system for automation lanes and points
- Implemented AutomationPoint component with drag-and-drop editing
- Implemented AutomationHeader with mode controls (Read/Write/Touch/Latch)
- Implemented AutomationLane with canvas-based curve rendering
- Integrated automation lanes into Track component below effects
- Created automation playback engine with real-time interpolation
- Added automation data persistence to localStorage

Automation features:
- Add/remove automation points by clicking/double-clicking
- Drag points to change time and value
- Multiple automation modes (Read, Write, Touch, Latch)
- Linear and step curve types (bezier planned)
- Adjustable lane height (60-180px)
- Show/hide automation per lane
- Real-time value display at playhead
- Color-coded lanes by parameter type
- Keyboard delete support (Delete/Backspace)

Track type updates:
- Added automation field to Track interface
- Updated track creation to initialize empty automation
- Updated localStorage save/load to include automation data

Files created:
- components/automation/AutomationPoint.tsx
- components/automation/AutomationHeader.tsx
- components/automation/AutomationLane.tsx
- lib/audio/automation/utils.ts (helper functions)
- lib/audio/automation/playback.ts (playback engine)
- types/automation.ts (complete type system)

Files modified:
- components/effects/EffectDevice.tsx (Ableton-style visual improvements)
- components/tracks/Track.tsx (automation lanes integration)
- types/track.ts (automation field added)
- lib/audio/track-utils.ts (automation initialization)
- lib/hooks/useMultiTrack.ts (automation persistence)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:30:01 +01:00
49dd0c2d38 feat: complete Phase 8.3 - recording settings (input gain, mono/stereo, sample rate)
Recording Settings (Phase 8.3):
- Added input gain control (0.0-2.0 with dB display)
- Real-time gain adjustment via GainNode during recording
- Mono/Stereo recording mode selection
- Sample rate matching (44.1kHz, 48kHz, 96kHz)
- Mono conversion averages all channels when enabled
- Recording settings panel shown when track is armed

Components Created:
- RecordingSettings.tsx: Settings panel with gain slider, mono/stereo toggle, sample rate buttons

Components Modified:
- useRecording hook: Added settings state and GainNode integration
- AudioEditor: Pass recording settings to TrackList
- TrackList: Forward settings to Track components
- Track: Show RecordingSettings when armed for recording

Technical Details:
- GainNode inserted between source and analyser in recording chain
- Real-time gain updates via gainNode.gain.value
- AudioContext created with target sample rate
- Mono conversion done post-recording by averaging channels
- Settings persist during recording session

Phase 8 Complete:
-  Phase 8.1: Audio Input
-  Phase 8.2: Recording Controls (punch/overdub)
-  Phase 8.3: Recording Settings
- 📋 Phase 9: Automation (NEXT)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:51:38 +01:00
db01209f77 feat: implement professional logarithmic dB scale for level meters
Converted level meters from linear to logarithmic (dB) scale to
match professional audio software behavior and human hearing.

The Problem:
- Linear scale (0-100%) doesn't match perceived loudness
- Doesn't match professional DAW meter behavior
- Half-volume audio appears at 50% but sounds much quieter
- No industry-standard dB reference

The Solution:
- Convert linear amplitude to dB: 20 * log10(linear)
- Normalize -60dB to 0dB range to 0-100% display
- Matches professional audio metering standards

dB Scale Mapping:
  0 dB (linear 1.0)    = 100% (full scale, clipping)
 -6 dB (linear ~0.5)   = 90%  (loud)
-12 dB (linear ~0.25)  = 80%  (normal)
-20 dB (linear ~0.1)   = 67%  (moderate)
-40 dB (linear ~0.01)  = 33%  (quiet)
-60 dB (linear ~0.001) = 0%   (silence threshold)

Implementation:
- Added linearToDbScale() function to both hooks
- useMultiTrackPlayer: playback level monitoring
- useRecording: input level monitoring
- Formula: (dB - minDb) / (maxDb - minDb)
- Range: -60dB (min) to 0dB (max)

Benefits:
 Professional audio metering standards
 Matches human perception of loudness
 Consistent with DAWs (Pro Tools, Logic, Ableton)
 Better visual feedback for mixing/mastering
 More responsive in useful range (-20dB to 0dB)

Now properly mastered tracks will show levels in the
90-100% range, matching what you'd see in professional software.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:23:33 +01:00
a0ce83a654 fix: use Float32Array for accurate full-range level measurement
Switched from Uint8Array to Float32Array for level monitoring
to get accurate, full-precision audio measurements.

The Problem:
- getByteTimeDomainData() uses Uint8Array (0-255)
- Byte conversion: (value - 128) / 128 has asymmetric range
- Positive peaks: (255-128)/128 = 0.992 (not full 1.0)
- Precision loss from byte quantization
- Mastered tracks with peaks at 0dBFS only showed ~50%

The Solution:
- Switched to getFloatTimeDomainData() with Float32Array
- Returns actual sample values directly in -1.0 to +1.0 range
- No conversion needed, no precision loss
- Accurate representation of audio peaks

Changes Applied:
- useMultiTrackPlayer: Float32Array with analyser.fftSize samples
- useRecording: Float32Array with analyser.fftSize samples
- Peak detection: Math.abs() on float values directly

Benefits:
 Full 0-100% range for properly mastered audio
 Higher precision (32-bit float vs 8-bit byte)
 Symmetric range (-1.0 to +1.0, not -1.0 to ~0.992)
 Accurate metering for professional audio files

Now mastered tracks with peaks at 0dBFS will correctly show
~100% on the meters instead of being capped at 50%.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:21:31 +01:00
3e6fbda755 fix: move analyser before gain node to show true audio levels
Repositioned analyser nodes in audio graph to measure raw audio
levels before volume/gain adjustments.

The Problem:
- Analyser was after gain node in signal chain
- Track volume defaults to 0.8 (80%)
- Audio was scaled down before measurement
- Meters only showed ~50% of actual audio peaks

The Solution:
- Moved analyser to immediately after source
- Now measures raw audio before any processing
- Shows true audio content independent of fader position

Audio Graph Changes:
Before: source -> gain -> pan -> effects -> analyser -> master
After:  source -> analyser -> gain -> pan -> effects -> master

Benefits:
 Meters show full 0-100% range based on audio content
 Meter reading independent of volume fader position
 Accurate representation of track audio levels
 Increased smoothingTimeConstant to 0.8 for smoother motion

This is how professional DAWs work - level meters show the
audio content, not the output level after the fader.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:17:42 +01:00
8367cbf6e7 fix: switch from RMS to peak detection for more accurate level meters
Changed level calculation from RMS to peak detection to show
more realistic and responsive meter values.

The Problem:
- RMS calculation produced values typically in 0-30% range
- Audio signals have low average RMS (0.1-0.3 for music)
- Meters appeared broken, never reaching higher levels

The Solution:
- Switched to peak detection (max absolute value)
- Peaks now properly show 0-100% range
- More responsive to transients and dynamics
- Matches typical DAW meter behavior

Algorithm Change:
Before (RMS):
  rms = sqrt(sum(normalized²) / length)

After (Peak):
  peak = max(abs(normalized))

Applied to Both:
- Recording input level monitoring (useRecording)
- Playback output level monitoring (useMultiTrackPlayer)

Benefits:
 Full 0-100% range utilization
 More responsive visual feedback
 Accurate representation of audio peaks
 Consistent with professional audio software

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:15:16 +01:00
a157172e3d fix: resolve playback level monitoring closure issue
Fixed playback level meters staying at 0% by resolving React closure
issue in the monitoring loop - same pattern as the recording fix.

The Problem:
- monitorPlaybackLevels callback checked stale `isPlaying` state
- Animation loop would run once and never continue
- Dependency on isPlaying caused callback recreation on every state change

The Solution:
- Added isMonitoringLevelsRef to track state independent of React
- Removed isPlaying dependency from callback (now has empty deps [])
- Set ref to true when starting playback
- Set ref to false when pausing, stopping, or ending playback
- Animation loop checks ref instead of stale closure state

Monitoring State Management:
- Start: play() sets isMonitoringLevelsRef.current = true
- Stop: pause(), stop(), onended, and cleanup set it to false
- Loop: continues while ref is true, stops when false

This ensures the requestAnimationFrame loop runs continuously
during playback and calculates real-time RMS levels for all tracks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 15:12:42 +01:00
6fbb677bd2 feat: implement real-time playback level monitoring for all tracks
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>
2025-11-18 15:01:55 +01:00
cf0c37caa6 fix: resolve recording level meter monitoring closure issue
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>
2025-11-18 14:56:30 +01:00
c0ca4d7913 fix: migrate existing tracks to new 180px height from localStorage
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>
2025-11-18 14:53:31 +01:00
5e6c61d951 feat: implement Phase 8.1 - audio recording infrastructure
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>
2025-11-18 14:37:01 +01:00
74879a42cf feat: implement multi-track waveform selection and editing with undo/redo
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>
2025-11-18 13:05:05 +01:00
beb7085c89 feat: complete Phase 7.4 - real-time track effects system
Implemented comprehensive real-time effect processing for multi-track audio:

Core Features:
- Per-track effect chains with drag-and-drop reordering
- Effect bypass/enable toggle per effect
- Real-time parameter updates (filters, dynamics, time-based, distortion, bitcrusher, pitch, timestretch)
- Add/remove effects during playback without interruption
- Effect chain persistence via localStorage
- Automatic playback stop when tracks are deleted

Technical Implementation:
- Effect processor with dry/wet routing for bypass functionality
- Real-time effect parameter updates using AudioParam setValueAtTime
- Structure change detection for add/remove/reorder operations
- Stale closure fix using refs for latest track state
- ScriptProcessorNode for bitcrusher, pitch shifter, and time stretch
- Dual-tap delay line for pitch shifting
- Overlap-add synthesis for time stretching

UI Components:
- EffectBrowser dialog with categorized effects
- EffectDevice component with parameter controls
- EffectParameters for all 19 real-time effect types
- Device rack with horizontal scrolling (Ableton-style)

Removed offline-only effects (normalize, fadeIn, fadeOut, reverse) as they don't fit the real-time processing model.

Completed all items in Phase 7.4:
- [x] Per-track effect chain
- [x] Effect rack UI
- [x] Effect bypass per track
- [x] Real-time effect processing during playback
- [x] Add/remove effects during playback
- [x] Real-time parameter updates
- [x] Effect chain persistence

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 12:08:33 +01:00
f640f2f9d4 feat: implement per-track and master effect chains (Option 3)
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>
2025-11-18 07:30:46 +01:00
2f8718626c feat: implement global volume and mute controls
- 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>
2025-11-18 07:20:29 +01:00
5817598c48 fix: playback position animation frame not updating
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>
2025-11-18 07:16:07 +01:00
64902fa707 chore: remove debug console.log statements
Cleaned up debugging code now that track name rendering issue is resolved.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 22:51:42 +01:00
cf1358e051 fix: ensure track name is always a string in createTrack
Added type checking to prevent event objects from being used as track names.
When onClick handlers pass events, we now explicitly check for string type.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 22:50:43 +01:00
7c19c069bf fix: convert selectedTrack.name to string in Effect Chain header
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>
2025-11-17 22:46:28 +01:00
6b540ef8fb fix: prevent localStorage circular reference in track serialization
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>
2025-11-17 22:36:07 +01:00
a2636bb3a9 fix: ensure track names are strings when loading from localStorage
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>
2025-11-17 22:30:45 +01:00
4735b5fb00 fix: resolve circular reference error in localStorage
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>
2025-11-17 22:04:13 +01:00
d566a86c58 feat: implement multi-track playback system (Phase 7.3)
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>
2025-11-17 21:03:39 +01:00
3c950eeba7 feat: implement Phase 7.1-7.2 multi-track infrastructure
Added core multi-track support with track management and controls:

**Track Types & Utilities:**
- Track interface with audio buffer, controls (volume/pan/solo/mute)
- Track utility functions for creation, mixing, and gain calculation
- Track color system with 9 preset colors
- Configurable track heights (60-300px)

**Components:**
- TrackHeader: Collapsible track controls with inline name editing
  - Solo/Mute buttons with visual feedback
  - Volume slider (0-100%) and Pan control (L-C-R)
  - Track color indicator and remove button
- Track: Waveform display component with canvas rendering
  - Click-to-seek on waveform
  - Playhead visualization
  - Support for collapsed state
- TrackList: Container managing multiple tracks
  - Scrollable track list with custom scrollbar
  - Add track button
  - Empty state UI

**State Management:**
- useMultiTrack hook with localStorage persistence
- Add/remove/update/reorder track operations
- Track buffer management

Features implemented:
-  Track creation and removal
-  Track naming (editable)
-  Track colors
-  Solo/Mute per track
-  Volume fader per track (0-100%)
-  Pan control per track (L-C-R)
-  Track collapse/expand
-  Track height configuration
-  Waveform visualization per track
-  Multi-track audio mixing utilities

Next: Integrate into AudioEditor and implement multi-track playback

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 20:59:36 +01:00
8a0bd46593 fix: correct FilterOptions import in effect chain
Fixed TypeScript build error by importing FilterOptions instead of
non-existent FilterParameters from filters module.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 20:34:38 +01:00
0986896756 feat: add Phase 6.6 Effect Chain Management system
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>
2025-11-17 20:27:08 +01:00
ee48f9475f feat: add advanced audio effects and improve UI
Phase 6.5 Advanced Effects:
- Add Pitch Shifter with semitones and cents adjustment
- Add Time Stretch with pitch preservation using overlap-add
- Add Distortion with soft/hard/tube types and tone control
- Add Bitcrusher with bit depth and sample rate reduction
- Add AdvancedParameterDialog with real-time waveform visualization
- Add 4 professional presets per effect type

Improvements:
- Fix undefined parameter errors by adding nullish coalescing operators
- Add global custom scrollbar styling with color-mix transparency
- Add custom-scrollbar utility class for side panel
- Improve theme-aware scrollbar appearance in light/dark modes
- Fix parameter initialization when switching effect types

Integration:
- All advanced effects support undo/redo via EffectCommand
- Effects accessible via command palette and side panel
- Selection-based processing support
- Toast notifications for all effects

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 20:03:40 +01:00
f414573655 fix: seeking backwards no longer jumps to frame 0
Fixed critical bug where seeking backwards during playback would
jump to position 0 instead of the desired position.

Root cause:
- When stop() was called on a playing source node, it triggered
  the onended event callback
- The onended callback would set pauseTime = 0 (thinking playback
  naturally ended)
- This interfered with the seek operation which was trying to set
  a new position

Solution:
- Clear sourceNode.onended callback BEFORE calling stop()
- This prevents the ended event from firing when we manually stop
- Seeking now works correctly in all directions

The fix ensures clean state transitions during seeking operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 17:32:50 +01:00
10d2921147 fix: proper seeking behavior with optional auto-play
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>
2025-11-17 17:30:11 +01:00
9aac873b53 fix: update transport button state when seeking auto-starts playback
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>
2025-11-17 17:27:12 +01:00
19bf7dc68a fix: seek now auto-starts playback for intuitive interaction
Changed seek behavior to match user expectations:
- Clicking on waveform now immediately starts playing from that position
- Dragging timeline slider starts playback at the selected position
- No need to click Play button after seeking

Previous behavior:
- seek() only continued playback if music was already playing
- Otherwise it just set isPaused = true
- User had to seek AND THEN click play button

New behavior:
- seek() always starts playback automatically
- Click anywhere → music plays from that position
- Much more intuitive UX matching common audio editors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 17:24:31 +01:00
958c6d6680 fix: playback starts from seeked position instead of beginning
Fixed critical bug where playback always started from 0:00 regardless
of seek position or pause state.

Root cause:
- play() method called stop() which reset pauseTime to 0
- Then it checked isPaused (now false) and pauseTime (now 0)
- Result: always played from beginning

Solution:
- Calculate offset BEFORE calling stop()
- Preserve the paused position or start offset
- Then stop and recreate source node with correct offset

Now playback correctly starts from:
- Seeked position (waveform click or timeline slider)
- Paused position (when resuming after pause)
- Specified start offset (when provided)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 17:21:10 +01:00
0d43d73014 fix: cleanup round - full width layout and paste operation bug
Fixed two issues:
1. Made audio editor full width by removing max-w-6xl wrapper
2. Fixed insertBufferSegment bug where paste operation had incorrect
   target buffer indexing causing corrupted audio after paste

Changes:
- app/page.tsx: Removed max-w-6xl constraint for full-width editor
- lib/audio/buffer-utils.ts: Fixed paste buffer copying logic
  * Corrected target index calculation in "copy after insert point" loop
  * Was: targetData[insertBuffer.length + i] = sourceData[i]
  * Now: targetData[insertSample + insertBuffer.length + (i - insertSample)] = sourceData[i]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 17:13:25 +01:00
159da29082 feat: implement Phase 5 - undo/redo system with command pattern
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>
2025-11-17 17:08:31 +01:00
ed9ac0b24f feat: implement Phase 4 - selection and editing features
Added comprehensive audio editing capabilities:
- Region selection with Shift+drag on waveform
- Visual selection feedback with blue overlay and borders
- AudioBuffer manipulation utilities (cut, copy, paste, delete, trim)
- EditControls UI component with edit buttons
- Keyboard shortcuts (Ctrl+A, Ctrl+X, Ctrl+C, Ctrl+V, Delete, Escape)
- Clipboard management for cut/copy/paste operations
- Updated useAudioPlayer hook with loadBuffer method

New files:
- types/selection.ts - Selection and ClipboardData interfaces
- lib/audio/buffer-utils.ts - AudioBuffer manipulation utilities
- components/editor/EditControls.tsx - Edit controls UI

Modified files:
- components/editor/Waveform.tsx - Added selection support
- components/editor/AudioEditor.tsx - Integrated edit operations
- lib/hooks/useAudioPlayer.ts - Added loadBuffer method

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 15:50:42 +01:00
ebfb4d3fff feat: implement Phase 2 - Web Audio API engine and waveform visualization
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>
2025-11-17 15:32:00 +01:00
591f726899 feat: initialize Next.js 16 project with Tailwind CSS 4 and Docker support
Phase 1 Implementation:
- Set up Next.js 16 with React 19, TypeScript 5, and Turbopack
- Configure Tailwind CSS 4 with OKLCH color system
- Implement dark/light theme support
- Create core UI components: Button, Card, Slider, Progress, Toast
- Add ThemeToggle component for theme switching
- Set up project directory structure for audio editor
- Create storage utilities for settings management
- Add Dockerfile with multi-stage build (Node + nginx)
- Configure nginx for static file serving with caching
- Add docker-compose.yml for easy deployment
- Configure static export mode for production

Tech Stack:
- Next.js 16 with Turbopack
- React 19
- TypeScript 5
- Tailwind CSS 4
- pnpm 9.0.0
- nginx 1.27 (for Docker deployment)

Build verified and working ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 15:23:00 +01:00