Releases: naomiaro/waveform-playlist
v9.5.1
Spectrogram Performance & Reliability
Performance
- Worker pool — Parallel per-channel FFT computation (~1.5s instead of ~2.9s for stereo). Pool size defaults to 2; configurable via
workerPoolSizeprop. FFT fan-out capped to actual channel count (excess workers sit idle). - Three-tier rendering — Viewport-first paint, then buffer zone, then background batches
- Generation-based abort — Cancels stale FFT requests on scroll, preventing queue blocking
- LRU cache — 16-entry FFT cache prevents recomputation on scroll-back
- Lazy per-batch FFT — Bounded memory per render batch, prevents OOM on 1hr+ files
SpectrogramAbortError— Type-safe abort detection viainstanceofinstead of string matching
Cleanup
- Fix
canvasIds[i]undefined variable in DPR scaling error path - Remove dead
spectrogramDataMapfromSpectrogramIntegrationinterface - Use string interpolation for all
console.errorcalls
Documentation
- Update
llm-reference.mdwith currentSpectrogramWorkerApiinterface - Add
workerPoolSize,SpectrogramAbortError,createSpectrogramWorkerPoolto docs - Add spectrogram architecture decisions to
packages/spectrogram/CLAUDE.md
v9.5.0
What's New
- Multi-channel recording pipeline — Recording now captures all channels from the microphone stream with per-channel peaks. Channel count is auto-detected from the stream via
getSettings().channelCount. - Configurable peak bit depth —
RecordingOptionsacceptsbits?: 8 | 16, flowing throughrecordingState.bitsto the renderer.
Bug Fixes
- AudioWorklet buffer overflow — At 44100Hz, the 128-sample AudioWorklet quantum doesn't divide evenly into the ~16ms buffer (705 samples), causing ~9% of recorded samples to be silently dropped. Fixed with a loop that handles frame boundary crossings.
- Real AudioContext sample rate —
useAudioTracksnow passes the actualaudioContext.sampleRateto track building instead of always falling back to a hardcoded 48000. - Canvas flicker —
Channel,PianoRollChannel, andSpectrogramChannelswitched fromuseEffecttouseLayoutEffectfor canvas drawing, preventingclearRectfrom being visible for one frame. - Recording preview width sync —
durationSamplesusesduration * sampleRate(zoom-independent) instead of peaks-derived calculations that depend onsamplesPerPixel. - Mono consistency — Live preview and post-recording paths both respect the
monoflag consistently.
Full Changelog: v9.4.1...v9.5.0
v9.4.1
Bug Fix
- Fix audio bleeding between pages —
TonePlayout.dispose()now stops the Tone.js Transport and all activeAudioBufferSourceNodes before cleanup. Previously, audio continued playing through the global AudioContext after provider unmount (e.g., during SPA client-side navigation). (#312) - Resilient cleanup —
stop()anddispose()now guard per-track operations with individual try-catch blocks, ensuring one track failure doesn't skip cleanup of remaining tracks.
v9.4.0
What's New
-
renderPlayheadprop for MediaElement —MediaElementWaveformandMediaElementPlaylistnow accept arenderPlayheadprop, matching the existing API onWaveform. PassPlayheadWithMarkeror a custom component for a triangle-marker playhead. -
Hook isolation for custom playheads — Both
PlaylistVisualization(WebAudio) andMediaElementPlaylistnow wraprenderPlayheadcalls in dedicated components (CustomPlayhead,CustomMediaElementPlayhead), preventing React's "Rendered more hooks" error when the prop is conditionally provided. -
Time display fix — Media element example now uses
currentTimeRefwith arequestAnimationFrameloop for smooth 60fps time updates during playback. -
Stem tracks custom playhead — Stem tracks example now uses
PlayheadWithMarkerto exercise the WebAudio custom playhead path. -
Media Element Playout guide — New documentation page covering usage, custom playheads, and the 4 context hooks.
Full Changelog
v9.3.3
New
- KeyboardShortcuts — Self-closing component for declarative keyboard shortcut setup. Eliminates ~100 lines of boilerplate. Three boolean props (all default
false):playback— Space (play/pause), Escape (stop), 0 (rewind)clipSplitting— 's' key splits clip at playheadannotations— Arrow nav, boundary editing, Enter to playadditionalShortcuts— Append custom shortcuts
<KeyboardShortcuts playback clipSplitting />Install
npm install @waveform-playlist/browser@9.3.3v9.3.2
New
- KeyboardShortcuts — Self-closing component for declarative keyboard shortcut setup. Eliminates ~100 lines of boilerplate across examples. Three boolean props (all default
false):playback— Space (play/pause), Escape (stop), 0 (rewind)clipSplitting— 's' key splits clip at playheadannotations— Arrow nav, boundary editing, Enter to playadditionalShortcuts— Append custom shortcutsenabled— Disable all shortcuts
<KeyboardShortcuts playback clipSplitting />Install
npm install @waveform-playlist/browser@9.3.2v9.3.1
New
- ClearAllButton — Reusable button component that stops playback before clearing tracks. Fixes a bug where clearing all tracks during playback left orphaned audio continuing. Accepts
onClearAllcallback prop.
Install
npm install @waveform-playlist/browser@9.3.1v9.3.0
ClipInteractionProvider
New declarative wrapper that encapsulates all clip drag/move/trim/snap/collision setup, replacing ~120 lines of boilerplate per interactive example.
Before
<DragDropProvider
sensors={sensors}
onDragStart={onDragStart}
onDragMove={onDragMove}
onDragEnd={onDragEnd}
modifiers={[RestrictToHorizontalAxis, SnapToGridModifier.configure({...}), ClipCollisionModifier.configure({...})]}
plugins={noDropAnimationPlugins}
>
<Waveform showClipHeaders interactiveClips />
</DragDropProvider>After
<ClipInteractionProvider snap>
<Waveform showClipHeaders />
</ClipInteractionProvider>What's new
ClipInteractionProvider— wrapsDragDropProviderwith pre-wired sensors, handlers, modifiers, and snap logicsnapboolean prop — auto-detects beats vs timescale snapping fromBeatsAndBarsProvidercontext- Auto-enables
interactiveClipson descendantWaveformvia context useClipInteractionEnabled— hook to check if inside aClipInteractionProvideronTracksChangeexposed fromusePlaylistData()— no more prop threading for drag handlers- Custom Drag Setup guide — manual
DragDropProvidersetup for power users
v9.2.1
Features
scaleModeprop onBeatsAndBarsProvider— set to'temporal'to show minutes:seconds timescale while keeping snap-to-grid active. Defaults to'beats'. This avoids mounting/unmounting the provider when switching scale modes.
Fixes
- Resolve website type errors for
@docusaurus/Head,Link, andLayout - Remove stray
timescaleprop from<Waveform>(belongs on provider) - Replace duplicated progressive loading code block with link to guide
Docs
- New Beats & Bars guide
- Immediate Mode section in Loading Audio guide
deferEngineRebuildprop documented in WaveformPlaylistProvider API
🤖 Generated with Claude Code
v9.2.0
Beats & Bars
Musical timescale with bar and beat markers, PPQN-based snap-to-grid, and configurable time signatures. Closes #226.
Features
- BeatsAndBarsProvider — context for BPM, time signature, and snap config (
@waveform-playlist/ui-components) - SmartScale beats/bars mode — timescale renders bar and beat markers instead of minutes:seconds
- SnapToGridModifier — snaps clip absolute position to beat or bar grid boundaries (
@waveform-playlist/browser) - PPQN math utilities —
ticksPerBeat,ticksPerBar,samplesToTicks,ticksToSamples,snapToGrid(@waveform-playlist/core) - Configurable PPQN — defaults to 192 (Tone.js transport resolution), configurable for custom grids
deferEngineRebuildprop — prevents double engine rebuilds during progressive loading- Immediate mode (
useAudioTracks) — placeholder tracks render instantly, peaks fill in as audio decodes
Bug Fixes
- Null filter bug in
useAudioTracks— loose equality (!= null) to catch both null and undefined - Initial mount flash in immediate mode — reordered hooks so
useStateinitializes fromuseMemo
Docs
- New Beats & Bars guide
- Immediate Mode section in Loading Audio guide
deferEngineRebuildprop documented in WaveformPlaylistProvider API- Interactive example with BPM, time signature, and snap controls
- PPQN explainer with BPM relationship on the example page
🤖 Generated with Claude Code