Waveform Data
The waveform data example demonstrates using pre-computed BBC peaks files for instant waveform rendering, eliminating the need to load full audio files before displaying waveforms.
View Live Demo →
What It Demonstrates
- Instant waveform display - Load 50KB peaks instead of 3MB audio
- BBC peaks format - Industry-standard waveform data format
- Progressive loading - Tracks appear as peaks load (sub-second)
- Background audio loading - Audio loads in background after peaks
- Massive performance gain - 97% smaller initial download
- Real-time progress - Track loading count indicators
Complete Example
import React, { useState, useEffect, useMemo } from 'react';
import {
WaveformPlaylistProvider,
Waveform,
PlayButton,
PauseButton,
useAudioTracks,
loadWaveformData,
waveformDataToPeaks,
} from '@waveform-playlist/browser';
// Track configuration with both audio and peaks files
const trackConfigs = [
{
name: 'Kick',
audioSrc: '/audio/kick.opus',
peaksSrc: '/audio/kick.dat', // BBC peaks (8-bit, 30 samples/pixel)
peaksSize: 55, // KB
audioSize: 280, // KB
},
{
name: 'Bass',
audioSrc: '/audio/bass.opus',
peaksSrc: '/audio/bass.dat',
peaksSize: 53,
audioSize: 620,
},
// ... more tracks
];
export function WaveformDataExample() {
const [bbcPeaks, setBbcPeaks] = useState(new Map());
// Load BBC peaks PROGRESSIVELY - each track appears as its peaks load!
useEffect(() => {
trackConfigs.forEach(async (config) => {
try {
// Load peaks file (50KB)
const waveformData = await loadWaveformData(config.peaksSrc);
const peaks = waveformDataToPeaks(waveformData, 0);
// Update state for THIS track immediately - triggers re-render
setBbcPeaks(prev => {
const newMap = new Map(prev);
newMap.set(config.name, {
data: peaks.data,
bits: peaks.bits,
length: peaks.length,
sampleRate: peaks.sampleRate,
waveformData,
});
return newMap;
});
} catch (error) {
console.error(`Error loading peaks for ${config.name}:`, error);
}
});
}, []);
// Build audio configs - only for tracks with peaks loaded
const audioConfigs = useMemo(
() =>
trackConfigs
.filter(config => bbcPeaks.has(config.name))
.map(config => ({
src: config.audioSrc,
name: config.name,
waveformData: bbcPeaks.get(config.name)?.waveformData,
})),
[bbcPeaks]
);
// Load audio PROGRESSIVELY - tracks become playable as audio loads
const { tracks, loading, loadedCount, totalCount } = useAudioTracks(
audioConfigs,
{ progressive: true }
);
return (
<>
{loading && <div>Loading audio: {loadedCount}/{totalCount}</div>}
<WaveformPlaylistProvider tracks={tracks} samplesPerPixel={1024}>
<PlayButton />
<PauseButton />
<Waveform />
</WaveformPlaylistProvider>
</>
);
}
Key Features
Loading BBC Peaks
Load pre-computed waveform data:
import { loadWaveformData, waveformDataToPeaks } from '@waveform-playlist/browser';
const waveformData = await loadWaveformData('/audio/kick.dat');
const peaks = waveformDataToPeaks(waveformData, 0); // Channel 0
// Returns:
// {
// data: Int8Array | Int16Array, // Peak values
// bits: 8 | 16, // Bit depth
// length: number, // Number of peaks
// sampleRate: number, // Audio sample rate
// }
BBC peaks files (.dat) are generated using the audiowaveform CLI tool. They contain pre-computed min/max peak values at a fixed samples-per-pixel resolution.
Progressive Loading Pattern
Load peaks first, then audio in background:
// 1. Load peaks immediately (50KB, <100ms)
const waveformData = await loadWaveformData('/peaks.dat');
setBbcPeaks(new Map([['track', waveformData]]));
// ✅ Waveform visible!
// 2. Load audio in background (3MB, ~2s)
const audioConfigs = [
{
src: '/audio.mp3',
waveformData, // Pass peaks for instant display
},
];
const { tracks } = useAudioTracks(audioConfigs, { progressive: true });
// ✅ Audio loads while waveform is visible
Two-Stage Loading
Stage 1: Peaks
- Load: 50KB per track
- Time: <100ms per track
- Result: Waveforms visible
Stage 2: Audio
- Load: 3MB per track (in background)
- Time: ~2s per track
- Result: Tracks become playable
File Size Comparison
For a 4-track project:
| Approach | Initial Load | Playable After |
|---|
| Full Audio | 12 MB | 12 MB loaded (~8s) |
| With Peaks | 200 KB | 200 KB loaded (<1s) |
| Savings | 98% smaller | Instant waveforms |
Generating Peaks Files
Use the BBC audiowaveform tool:
# Install audiowaveform
sudo apt-get install audiowaveform # Linux
brew install audiowaveform # macOS
# Generate 8-bit peaks at 30 samples/pixel
audiowaveform -i audio.mp3 -o audio.dat -b 8 -z 30
# Options:
# -b 8 : 8-bit peaks (smaller files)
# -b 16 : 16-bit peaks (higher precision)
# -z 30 : 30 samples per pixel (good for overview)
# -z 256 : 256 samples per pixel (more detail)
Use 8-bit peaks for overview waveforms and 16-bit for detailed zoomed views. The library automatically scales peaks to match the current zoom level.
Get audio metadata from peaks file:
import { getWaveformDataMetadata } from '@waveform-playlist/browser';
const metadata = await getWaveformDataMetadata('/audio.dat');
// Returns:
// {
// channels: 1, // Mono or stereo
// duration: 53.24, // Duration in seconds
// samplesPerPixel: 30, // Resolution
// }
This is useful for calculating track lengths before loading audio.
Multi-Channel Support
Extract peaks for stereo files:
const waveformData = await loadWaveformData('/stereo.dat');
// Left channel
const leftPeaks = waveformDataToPeaks(waveformData, 0);
// Right channel
const rightPeaks = waveformDataToPeaks(waveformData, 1);
Real-Time Progress
Show loading progress:
const { tracks, loading, loadedCount, totalCount } = useAudioTracks(
audioConfigs,
{ progressive: true }
);
{loading && (
<div>
Loading audio: {loadedCount}/{totalCount} tracks
({Math.round((loadedCount / totalCount) * 100)}%)
</div>
)}
Initial Page Load
Without peaks:
1. Load 12 MB audio
2. Decode audio (CPU intensive)
3. Generate waveforms
4. Render UI
⏱️ Total: 8-10 seconds
With peaks:
1. Load 200 KB peaks ← 98% smaller!
2. Render waveforms
3. Show UI ← User can see/interact
4. Load audio in background
⏱️ Visible: <1 second
⏱️ Playable: 2-3 seconds
Network Usage
Audio: 280 KB × 4 tracks = 1,120 KB
Peaks: 55 KB × 4 tracks = 220 KB
Savings: 900 KB (80% reduction)
Plus peaks load in parallel for sub-second total time.
Use Cases
Perfect for:
- Multi-track projects with many files
- Mobile users on slow connections
- Podcast/audiobook players
- Music production DAWs
- Audio annotation tools
Skip if:
- Single short audio file (<30s)
- Audio already loaded/cached
- Real-time recording (no pre-computed peaks)
Source Code
View the complete source code:
- Example component:
website/src/components/examples/WaveformDataExample.tsx
- Waveform data utils:
packages/browser/src/waveform-data.ts
- E2E tests:
e2e/waveform-data.spec.ts