Skip to main content

MediaElementPlaylistProvider

A simplified playlist provider for single-track playback using HTMLAudioElement. Ideal for language learning apps, podcast players, and single-track audio viewers.

Key Differences from WaveformPlaylistProvider

FeatureMediaElementPlaylistProviderWaveformPlaylistProvider
InstancesMultiple per pageSingle instance only (shared Tone.js Transport)
TracksSingle track (track prop)Multiple tracks (tracks prop)
Audio engineHTMLAudioElementTone.js / Web Audio API
Waveform dataPre-computed (WaveformDataObject)Decoded from AudioBuffer
Playback ratePitch-preserving (0.5x - 2.0x)Not built-in
EditingView onlyDrag, trim, split
EffectsVia Tone.js bridge (see guide)20 built-in Tone.js effects

Import

import { MediaElementPlaylistProvider } from '@waveform-playlist/browser';

Basic Usage

import { MediaElementPlaylistProvider, MediaElementWaveform } from '@waveform-playlist/browser';

<MediaElementPlaylistProvider
track={{
source: '/audio/episode.mp3',
waveformData: waveformDataJson,
name: 'Episode 1',
}}
samplesPerPixel={1024}
waveHeight={100}
timescale
>
<MediaElementWaveform />
</MediaElementPlaylistProvider>

Props

Required Props

track

Type: MediaElementTrackConfig

Single track configuration object.

interface MediaElementTrackConfig {
/** Audio source URL or Blob URL */
source: string;
/** Pre-computed waveform data (required for visualization) */
waveformData: WaveformDataObject;
/** Track name for display */
name?: string;
/** Fade in configuration (requires audioContext on provider) */
fadeIn?: FadeConfig;
/** Fade out configuration (requires audioContext on provider) */
fadeOut?: FadeConfig;
}

interface FadeConfig {
/** Duration of the fade in seconds */
duration: number;
/** Type of fade curve (default: 'linear') */
type?: 'linear' | 'logarithmic' | 'exponential' | 'sCurve';
}

Display Props

samplesPerPixel

Type: number Default: 1024

Zoom level for waveform rendering.

waveHeight

Type: number Default: 100

Height of the waveform track in pixels.

timescale

Type: boolean Default: false

Show the time ruler at the top of the playlist.

controls

Type: { show: boolean; width: number } Default: { show: false, width: 0 }

Track controls panel configuration.

Web Audio

audioContext

Type: AudioContext

When provided, audio routes through a Web Audio graph enabling fades and effects. Required for fadeIn/fadeOut on the track config and for bridging into Tone.js effects. Each provider instance should use its own AudioContextcreateMediaElementSource() is called once per audio element.

Playback

playbackRate

Type: number Default: 1

Initial playback rate. Range: 0.5 to 2.0.

preservesPitch

Type: boolean Default: true

Whether to preserve pitch when changing playback rate. When true, the browser's built-in time-stretching keeps pitch constant while speed changes. Set to false when using an external pitch processor (e.g., SoundTouch AudioWorklet) that handles pitch compensation itself.

automaticScroll

Type: boolean Default: false

Auto-scroll to keep the playhead centered during playback.

Theming

theme

Type: Partial<WaveformPlaylistTheme> Default: defaultTheme

Custom theme object. See Theming Guide.

Annotations

annotationList

Type: { annotations?: any[]; isContinuousPlay?: boolean }

Annotation configuration. When using editable annotations, pair with onAnnotationsChange.

onAnnotationsChange

Type: (annotations: AnnotationData[]) => void

Callback when annotations change. Required for edits to persist.

Waveform Rendering

barWidth

Type: number Default: 1

Width in pixels of waveform bars.

barGap

Type: number Default: 0

Spacing in pixels between waveform bars.

progressBarWidth

Type: number Default: barWidth + barGap

Width in pixels of progress bars.

Callbacks

onReady

Type: () => void

Called when the audio track is ready for playback.

Context Hooks

useMediaElementAnimation

High-frequency animation state for smooth playhead updates.

interface MediaElementAnimationContextValue {
isPlaying: boolean;
currentTime: number;
currentTimeRef: React.RefObject<number>;
}

useMediaElementState

Playlist state values.

interface MediaElementStateContextValue {
continuousPlay: boolean;
annotations: AnnotationData[];
activeAnnotationId: string | null;
playbackRate: number;
isAutomaticScroll: boolean;
}

useMediaElementControls

Playback and annotation controls.

interface MediaElementControlsContextValue {
play: (startTime?: number) => void;
pause: () => void;
stop: () => void;
seekTo: (time: number) => void;
setPlaybackRate: (rate: number) => void;
setContinuousPlay: (enabled: boolean) => void;
setAnnotations: React.Dispatch<React.SetStateAction<AnnotationData[]>>;
setActiveAnnotationId: (id: string | null) => void;
setAutomaticScroll: (enabled: boolean) => void;
setScrollContainer: (element: HTMLDivElement | null) => void;
scrollContainerRef: React.RefObject<HTMLDivElement | null>;
}

useMediaElementData

Playlist data for rendering.

interface MediaElementDataContextValue {
duration: number;
peaksDataArray: TrackClipPeaks[];
sampleRate: number;
waveHeight: number;
timeScaleHeight: number;
samplesPerPixel: number;
playoutRef: React.RefObject<MediaElementPlayout | null>;
controls: { show: boolean; width: number };
barWidth: number;
barGap: number;
progressBarWidth: number;
fadeIn?: FadeConfig;
fadeOut?: FadeConfig;
}

playoutRef.current.outputNode returns the native GainNode output — use it to bridge into Tone.js effect chains (see guide).

TypeScript

Full type definition:

interface MediaElementPlaylistProviderProps {
// Required
track: MediaElementTrackConfig;
children: React.ReactNode;

// Display
samplesPerPixel?: number;
waveHeight?: number;
timescale?: boolean;
controls?: { show: boolean; width: number };

// Web Audio
audioContext?: AudioContext;

// Playback
playbackRate?: number;
preservesPitch?: boolean;
automaticScroll?: boolean;

// Theming
theme?: Partial<WaveformPlaylistTheme>;

// Annotations
annotationList?: {
annotations?: any[];
isContinuousPlay?: boolean;
};

// Callbacks
onReady?: () => void;
onAnnotationsChange?: (annotations: AnnotationData[]) => void;

// Waveform rendering
barWidth?: number;
barGap?: number;
progressBarWidth?: number;
}

See Also