Overview
The MediaElementPlaylistProvider is a simplified provider for single-track audio playback using the browser’s native HTMLAudioElement. It provides pitch-preserving playback rate control (0.5x - 2.0x speed) without requiring audio decoding or the Tone.js library.
Use this provider for:
Language learning apps (speed control for practice)
Podcast players
Single-track audio viewers
Simple annotation playback
Use cases where you need speed control without pitch shift
For multi-track editing, use WaveformPlaylistProvider instead.
Feature MediaElementPlaylistProvider WaveformPlaylistProvider Audio Engine HTMLAudioElement Tone.js (Web Audio API) Playback Speed 0.5x - 2.0x (pitch-preserving) 1.0x only Tracks Single track only Multiple tracks Audio Effects Not supported Full Tone.js effects Waveform Data Pre-computed (required) Generated from AudioBuffer Track Editing View only Full editing (move, trim, split) Recording Not supported Supported Bundle Size Smaller (no Tone.js) Larger
Import
import { MediaElementPlaylistProvider } from '@waveform-playlist/browser' ;
Props
track
MediaElementTrackConfig
required
Single track configuration with source URL and pre-computed waveform data. track = {{
source : 'https://example.com/audio.mp3' ,
waveformData : peaksData , // From BBC audiowaveform or similar
name : 'My Audio'
}}
Show MediaElementTrackConfig properties
Audio source URL or Blob URL. Must be a valid audio file accessible via HTTP or blob.
waveformData
WaveformDataObject
required
Pre-computed waveform data for visualization. This provider does not decode audio, so waveform data must be provided. Generate using BBC audiowaveform or similar tools.
Zoom level in samples per pixel. Lower values = more zoomed in. Note: Unlike WaveformPlaylistProvider, zoom is fixed (no zoom in/out controls).
Height in pixels of the waveform track.
Show timescale ruler above waveform.
Initial playback speed. Valid range: 0.5 to 2.0.
0.5 = half speed (50%)
1.0 = normal speed
2.0 = double speed (200%)
Speed changes preserve pitch (no “chipmunk effect”).
Automatically scroll to keep the playhead centered during playback.
theme
Partial<WaveformPlaylistTheme>
controls
{ show: boolean; width: number }
default: "{ show: false, width: 0 }"
Configuration for track control panel area. controls = {{ show : true , width : 100 }}
Configuration for annotations display. Show Annotation configuration properties
Array of annotation segments. Must be pre-parsed with numeric start and end values. Use parseAeneas() from @waveform-playlist/annotations to parse raw annotation data.
When enabled, playback continues across annotation boundaries. When disabled, playback stops at the end of the current annotation.
Width in pixels of waveform bars.
Spacing in pixels between waveform bars.
progressBarWidth
number
default: "barWidth + barGap"
Width in pixels of progress bars during playback.
onAnnotationsChange
(annotations: AnnotationData[]) => void
Callback fired when annotations are edited. onAnnotationsChange = {(updated) => setAnnotations ( updated )}
Callback fired when the audio element is ready for playback.
Context Hooks
The provider exposes four separate contexts optimized for performance.
Access playback state and timing.
import { useMediaElementAnimation } from '@waveform-playlist/browser' ;
function MyComponent () {
const {
isPlaying , // boolean
currentTime , // number (seconds)
currentTimeRef // RefObject<number>
} = useMediaElementAnimation ();
}
Show MediaElementAnimation values
Whether audio is currently playing.
Current playback position in seconds.
Ref to current time for animation loops.
Access playlist state (annotations, playback rate).
import { useMediaElementState } from '@waveform-playlist/browser' ;
function MyComponent () {
const {
continuousPlay ,
annotations ,
activeAnnotationId ,
playbackRate ,
isAutomaticScroll
} = useMediaElementState ();
}
Show MediaElementState values
Whether continuous play is enabled for annotations.
Current annotations array.
ID of the currently active annotation during playback.
Current playback speed (0.5 to 2.0).
Whether automatic scroll is enabled.
Access control functions for playback and settings.
import { useMediaElementControls } from '@waveform-playlist/browser' ;
function PlaybackControls () {
const {
play ,
pause ,
stop ,
seekTo ,
setPlaybackRate
} = useMediaElementControls ();
return (
< div >
< button onClick = { () => play () } > Play </ button >
< button onClick = { pause } > Pause </ button >
< button onClick = { stop } > Stop </ button >
< button onClick = { () => setPlaybackRate ( 0.75 ) } > 0.75x </ button >
< button onClick = { () => setPlaybackRate ( 1.0 ) } > 1.0x </ button >
< button onClick = { () => setPlaybackRate ( 1.5 ) } > 1.5x </ button >
</ div >
);
}
Show MediaElementControls methods
play
(startTime?: number) => void
Start playback. Optionally specify start time in seconds.
Pause playback at current position.
Stop playback and return to start.
Seek to a specific time in seconds.
Set playback speed (0.5 to 2.0). Clamped automatically.
setContinuousPlay
(enabled: boolean) => void
Enable or disable continuous play for annotations.
setAnnotations
Dispatch<SetStateAction<AnnotationData[]>>
Update annotations. Calls onAnnotationsChange callback.
setActiveAnnotationId
(id: string | null) => void
Set the active annotation ID.
setAutomaticScroll
(enabled: boolean) => void
Enable or disable automatic scrolling.
setScrollContainer
(element: HTMLDivElement | null) => void
Set the scroll container element for automatic scrolling.
scrollContainerRef
RefObject<HTMLDivElement | null>
Ref to the scroll container element.
Access playlist data (duration, waveform peaks).
import { useMediaElementData } from '@waveform-playlist/browser' ;
function MyComponent () {
const {
duration ,
peaksDataArray ,
sampleRate ,
waveHeight ,
samplesPerPixel
} = useMediaElementData ();
}
Show MediaElementData values
Audio duration in seconds.
Array of waveform peak data for rendering.
Audio sample rate from waveform data.
Height in pixels of waveform track.
Height in pixels of timescale ruler (0 if disabled).
Current zoom level in samples per pixel.
playoutRef
RefObject<MediaElementPlayout | null>
Ref to the underlying media element playout instance.
controls
{ show: boolean; width: number }
Track controls configuration.
Width in pixels of waveform bars.
Gap in pixels between waveform bars.
Width in pixels of progress bars.
Complete Example
import { useState } from 'react' ;
import {
MediaElementPlaylistProvider ,
useMediaElementControls ,
useMediaElementState ,
useMediaElementAnimation
} from '@waveform-playlist/browser' ;
import { parseAeneas } from '@waveform-playlist/annotations' ;
function SpeedControl () {
const { setPlaybackRate } = useMediaElementControls ();
const { playbackRate } = useMediaElementState ();
return (
< div >
< label > Speed: { playbackRate } x </ label >
< input
type = "range"
min = "0.5"
max = "2.0"
step = "0.1"
value = { playbackRate }
onChange = { ( e ) => setPlaybackRate ( parseFloat ( e . target . value )) }
/>
</ div >
);
}
function PlaybackControls () {
const { play , pause , stop } = useMediaElementControls ();
const { isPlaying } = useMediaElementAnimation ();
return (
< div >
< button onClick = { () => play () } >
{ isPlaying ? 'Pause' : 'Play' }
</ button >
< button onClick = { stop } > Stop </ button >
</ div >
);
}
function App () {
const [ annotations , setAnnotations ] = useState ([
parseAeneas ({ begin: "0.000" , end: "2.500" , id: "1" , lines: [ "First segment" ] }),
parseAeneas ({ begin: "2.500" , end: "5.000" , id: "2" , lines: [ "Second segment" ] })
]);
// Waveform data from BBC audiowaveform or similar tool
const waveformData = {
sample_rate: 44100 ,
samples_per_pixel: 512 ,
bits: 8 ,
length: 2000 ,
data: [ ... ], // Int8Array of peak values
duration: 45.2
};
return (
< MediaElementPlaylistProvider
track = { {
source: 'https://example.com/podcast-episode.mp3' ,
waveformData: waveformData ,
name: 'Episode 42'
} }
waveHeight = { 120 }
samplesPerPixel = { 1024 }
playbackRate = { 1.0 }
automaticScroll
timescale
annotationList = { {
annotations ,
isContinuousPlay: true
} }
onAnnotationsChange = { setAnnotations }
onReady = { () => console . log ( 'Audio ready!' ) }
>
< PlaybackControls />
< SpeedControl />
{ /* Your waveform visualization components */ }
</ MediaElementPlaylistProvider >
);
}
Since this provider doesn’t decode audio, you must provide pre-computed waveform data. Use tools like:
# Install
brew install audiowaveform
# Generate waveform data
audiowaveform -i input.mp3 -o output.json -z 512
const { exec } = require ( 'child_process' );
function generateWaveform ( inputPath , outputPath ) {
return new Promise (( resolve , reject ) => {
exec (
`audiowaveform -i ${ inputPath } -o ${ outputPath } -z 512 --pixels-per-second 50` ,
( error , stdout , stderr ) => {
if ( error ) reject ( error );
else resolve ( outputPath );
}
);
});
}
The JSON output from audiowaveform is compatible with the waveformData prop.
Use Cases
Language Learning App
< MediaElementPlaylistProvider
track = { { source: lessonAudioUrl , waveformData , name: 'Lesson 5' } }
playbackRate = { 0.75 } // Slow down for beginners
annotationList = { {
annotations: sentenceAnnotations ,
isContinuousPlay: false // Stop after each sentence
} }
>
{ /* UI for sentence-by-sentence playback */ }
</ MediaElementPlaylistProvider >
Podcast Player
< MediaElementPlaylistProvider
track = { { source: episodeUrl , waveformData , name: episode . title } }
playbackRate = { 1.5 } // Faster playback for regular listeners
automaticScroll
annotationList = { {
annotations: chapterMarkers ,
isContinuousPlay: true
} }
>
{ /* UI with chapter navigation */ }
</ MediaElementPlaylistProvider >
Interview Transcription
< MediaElementPlaylistProvider
track = { { source: interviewUrl , waveformData , name: 'Interview' } }
playbackRate = { 0.8 } // Slightly slower for transcription
annotationList = { {
annotations: transcriptSegments ,
isContinuousPlay: false
} }
>
{ /* UI for reviewing and editing transcript timing */ }
</ MediaElementPlaylistProvider >