Skip to content

Releases: naomiaro/waveform-playlist

v10.2.0

14 Mar 19:20

Choose a tag to compare

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

12 Mar 06:50

Choose a tag to compare

What's Changed

Improvements

  • Migrate browser package from Vite to tsup — Consistent build tooling across all 13 packages. tsup auto-externalizes dependencies and peerDependencies, preventing the class of bundle drift that caused #317.
  • Remove manual external lists 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...v10.1.2

v10.1.1

12 Mar 06:32

Choose a tag to compare

What's Changed

Bug Fixes

  • Fix clip drag not constrained horizontally — The Vite external list 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 broke RestrictToHorizontalAxis. (#317)

Improvements

  • Derive Vite externals from peerDependencies in package.json automatically, preventing this class of drift in the future.

Full Changelog

v10.1.0...v10.1.1

v10.1.0

12 Mar 06:09

Choose a tag to compare

What's Changed

Features

  • Web Audio routing for MediaElementTrackMediaElementPlaylistProvider now accepts an optional audioContext prop 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

Improvements

  • Replace hand-rolled AudioWorklet types with @types/audioworklet
  • Consolidate FadeConfig type 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.1.0

v10.0.0

10 Mar 23:05

Choose a tag to compare

v10.0.0

Breaking Changes

@waveform-playlist/recording:

  • Removed UI component exports: RecordButton, MicrophoneSelector, RecordingIndicator, VUMeter (and their prop types). Use SegmentedVUMeter from @waveform-playlist/ui-components and build your own recording controls.
  • useMicrophoneLevel options changed: removed fftSize and smoothingTimeConstant, added channelCount. Now uses AudioWorklet-based metering instead of Tone.js Meter.
  • Recording worklet files moved from @waveform-playlist/recording to @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 additionengine.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 error state
  • 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

08 Mar 20:11

Choose a tag to compare

Bug Fixes

  • Fix duplicate audio on play/pause/play — Add event.repeat guard in keyboard shortcuts to prevent held-key repeats from firing multiple concurrent play() 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 deferEngineRebuild requirement for multi-track examples in website CLAUDE.md

v9.5.1

08 Mar 07:37

Choose a tag to compare

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 workerPoolSize prop. 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 via instanceof instead of string matching

Cleanup

  • Fix canvasIds[i] undefined variable in DPR scaling error path
  • Remove dead spectrogramDataMap from SpectrogramIntegration interface
  • Use string interpolation for all console.error calls

Documentation

  • Update llm-reference.md with current SpectrogramWorkerApi interface
  • Add workerPoolSize, SpectrogramAbortError, createSpectrogramWorkerPool to docs
  • Add spectrogram architecture decisions to packages/spectrogram/CLAUDE.md

v9.5.0

08 Mar 04:20

Choose a tag to compare

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 depthRecordingOptions accepts bits?: 8 | 16, flowing through recordingState.bits to 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 rateuseAudioTracks now passes the actual audioContext.sampleRate to track building instead of always falling back to a hardcoded 48000.
  • Canvas flickerChannel, PianoRollChannel, and SpectrogramChannel switched from useEffect to useLayoutEffect for canvas drawing, preventing clearRect from being visible for one frame.
  • Recording preview width syncdurationSamples uses duration * sampleRate (zoom-independent) instead of peaks-derived calculations that depend on samplesPerPixel.
  • Mono consistency — Live preview and post-recording paths both respect the mono flag consistently.

Full Changelog: v9.4.1...v9.5.0

v9.4.1

08 Mar 00:13

Choose a tag to compare

Bug Fix

  • Fix audio bleeding between pagesTonePlayout.dispose() now stops the Tone.js Transport and all active AudioBufferSourceNodes before cleanup. Previously, audio continued playing through the global AudioContext after provider unmount (e.g., during SPA client-side navigation). (#312)
  • Resilient cleanupstop() and dispose() now guard per-track operations with individual try-catch blocks, ensuring one track failure doesn't skip cleanup of remaining tracks.

v9.4.0

07 Mar 23:12

Choose a tag to compare

What's New

  • renderPlayhead prop for MediaElementMediaElementWaveform and MediaElementPlaylist now accept a renderPlayhead prop, matching the existing API on Waveform. Pass PlayheadWithMarker or a custom component for a triangle-marker playhead.

  • Hook isolation for custom playheads — Both PlaylistVisualization (WebAudio) and MediaElementPlaylist now wrap renderPlayhead calls 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 currentTimeRef with a requestAnimationFrame loop for smooth 60fps time updates during playback.

  • Stem tracks custom playhead — Stem tracks example now uses PlayheadWithMarker to 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...v9.4.0