Releases: naomiaro/waveform-playlist
v10.2.0
What's New
preservesPitch prop on MediaElementPlaylistProvider
The HTMLAudioElement.preservesPitch was previously hardcoded to true. It's now configurable via a new boolean prop (default: true, backwards compatible).
<MediaElementPlaylistProvider
track={trackConfig}
preservesPitch={false} // disable browser pitch correction
/>Set to false when using an external pitch processor (e.g., SoundTouch AudioWorklet) that handles pitch compensation itself.
MediaElement example update
The Media Element example now includes a Preserve Pitch toggle so you can hear the difference between pitch-preserved and non-pitch-preserved playback rate changes.
Full Changelog: v10.1.2...v10.2.0
v10.1.2
What's Changed
Improvements
- Migrate browser package from Vite to tsup — Consistent build tooling across all 13 packages. tsup auto-externalizes
dependenciesandpeerDependencies, preventing the class of bundle drift that caused #317. - Remove manual
externallists from all tsup configs — Redundant with tsup's auto-externalization. Removes 52 transitive devDependencies (Vite, Rollup, etc.). ESM bundle reduced from 398KB to 251KB.
Full Changelog
v10.1.1
What's Changed
Bug Fixes
- Fix clip drag not constrained horizontally — The Vite
externallist referenced stale @dnd-kit v4 packages (@dnd-kit/core,@dnd-kit/modifiers) instead of the v0.3.x packages actually used (@dnd-kit/abstract,@dnd-kit/dom,@dnd-kit/react). This caused @dnd-kit to be bundled into the npm output, creating duplicate instances at runtime that brokeRestrictToHorizontalAxis. (#317)
Improvements
- Derive Vite externals from
peerDependenciesinpackage.jsonautomatically, preventing this class of drift in the future.
Full Changelog
v10.1.0
What's Changed
Features
- Web Audio routing for MediaElementTrack —
MediaElementPlaylistProvidernow accepts an optionalaudioContextprop to enable Web Audio routing through a gain chain (HTMLAudioElement → MediaElementSourceNode → fadeGain → volumeGain → destination). This enables:- Fade in/out with 4 curve types:
linear,logarithmic,exponential,sCurve - Tone.js effect bridging via native→Tone.Gain connection pattern
- Partial fade curve preservation when seeking mid-fade
- Fade in/out with 4 curve types:
Improvements
- Replace hand-rolled AudioWorklet types with
@types/audioworklet - Consolidate
FadeConfigtype alias in@waveform-playlist/core(re-exported by playout and media-element-playout) - Fix stale API references across documentation for v10
Full Changelog
v10.0.0
v10.0.0
Breaking Changes
@waveform-playlist/recording:
- Removed UI component exports:
RecordButton,MicrophoneSelector,RecordingIndicator,VUMeter(and their prop types). UseSegmentedVUMeterfrom@waveform-playlist/ui-componentsand build your own recording controls. useMicrophoneLeveloptions changed: removedfftSizeandsmoothingTimeConstant, addedchannelCount. Now uses AudioWorklet-based metering instead of Tone.jsMeter.- Recording worklet files moved from
@waveform-playlist/recordingto@waveform-playlist/worklets(auto-installed as a dependency).
New Package
@waveform-playlist/worklets— Shared AudioWorklet processors for sample-accurate metering (meter-processor) and multi-channel recording (recording-processor).
New Features
- SegmentedVUMeter — LED-style meter component with horizontal/vertical orientation, configurable segments, dB range, color stops, per-channel peak hold, and dimmed inactive scale
- Worklet-based metering — Sample-accurate peak and RMS measurement replacing Tone.js Meter polling
- useOutputMeter — Master bus output metering hook with auto-reset on stop
- Multi-channel useMicrophoneLevel — Auto-detects mono/stereo from mic, mirrors mono to fill requested channel count, exposes per-channel
levels,peakLevels,rmsLevels - Overdub recording — Record over existing audio with latency compensation (
outputLatency + lookAhead). Timeline position captured at record-start. - Incremental track addition —
engine.addTrack()avoids full playout rebuild when appending tracks - DAW-style toolbar — Transport strip + meter bridge with IN/OUT meters, mic selector, master volume, export
- Recording keyboard shortcuts — R to record, Shift+R to create new track and record
- indefinitePlayback — Timeline fills visible scroll container
- Device hot-plug detection — Auto-detects plugged/unplugged microphones, falls back to first available device
Error Handling
- Meter setup failures exposed via
errorstate - Short recordings set user-facing error instead of silent discard
- Consistent
console.warn('[waveform-playlist] ...')logging - All recording hooks use
getGlobalContext()from playout (CLAUDE.md pattern 22)
Test Coverage
- 46 new unit tests: incremental track addition, latency compensation, mono-to-stereo mirroring, SegmentedVUMeter activation
v9.5.2
Bug Fixes
- Fix duplicate audio on play/pause/play — Add
event.repeatguard in keyboard shortcuts to prevent held-key repeats from firing multiple concurrentplay()calls during async engine initialization - Fix engine rebuild race condition — Add
deferEngineRebuild={loading}to Flexible API example to prevent per-track engine rebuilds during progressive loading
Tests
- Add 16 unit tests for keyboard shortcut handling including bug reproduction scenario
Documentation
- Document jsdom keyboard event testing quirks in browser package CLAUDE.md
- Document
deferEngineRebuildrequirement for multi-track examples in website CLAUDE.md
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.