Skip to main content

BBC Waveform Data Example

This example demonstrates fast waveform loading using BBC's pre-computed peaks format. Waveforms appear almost instantly while audio loads in the background.

Loading...

About BBC Waveform Data

BBC's audiowaveform tool generates pre-computed peak data from audio files. This enables:

  • Instant waveform display - peaks files are ~50KB vs ~3MB for audio
  • Reduced server load - no need to decode audio for visualization
  • Consistent rendering - same peaks regardless of browser/platform
  • Progressive loading - show waveforms while audio loads in background

Generating BBC Peaks Files

# Install audiowaveform (macOS)
brew install audiowaveform

# Generate binary .dat file at 256 samples per pixel
audiowaveform -i audio.mp3 -o peaks.dat -z 256 -b 8

# Generate with different zoom levels
audiowaveform -i audio.mp3 -o peaks-30.dat -z 30 -b 8  # ~30 SPP

# Generate 16-bit for higher precision
audiowaveform -i audio.mp3 -o peaks-16bit.dat -z 256 -b 16

Fully Progressive Loading

import React, { useState, useEffect, useMemo } from 'react';
import type WaveformData from 'waveform-data';
import {
  WaveformPlaylistProvider,
  Waveform,
  PlayButton,
  PauseButton,
  StopButton,
  useAudioTracks,
  loadWaveformData,
} from '@waveform-playlist/browser';

const trackConfigs = [
  { name: 'Kick', audioSrc: '/audio/kick.opus', peaksSrc: '/peaks/kick.dat' },
  { name: 'Bass', audioSrc: '/audio/bass.opus', peaksSrc: '/peaks/bass.dat' },
];

function WaveformDataExample() {
  const [peaksMap, setPeaksMap] = useState<Map<string, WaveformData>>(new Map());

  // 1. Load peaks PROGRESSIVELY - each track appears as its peaks load!
  useEffect(() => {
    trackConfigs.forEach(async (config) => {
      const waveformData = await loadWaveformData(config.peaksSrc);
      // Update state for THIS track immediately - triggers re-render
      setPeaksMap(prev => new Map(prev).set(config.name, waveformData));
    });
  }, []);

  // 2. Build configs - only include tracks that have peaks ready
  const audioConfigs = useMemo(() =>
    trackConfigs
      .filter(config => peaksMap.has(config.name))
      .map(config => ({
        src: config.audioSrc,
        name: config.name,
        waveformData: peaksMap.get(config.name), // Pre-computed peaks!
      })),
  [peaksMap]);

  // 3. Load audio progressively - tracks appear as they load!
  const { tracks, loading, loadedCount, totalCount } = useAudioTracks(
    audioConfigs,  // Configs added progressively as peaks arrive
    { progressive: true }
  );

  // Tracks render immediately as each one loads - no waiting!
  return (
    <WaveformPlaylistProvider tracks={tracks} samplesPerPixel={1024}>
      {loading && <div>Loading: {loadedCount} / {totalCount}</div>}
      <PlayButton /> <PauseButton /> <StopButton />
      <Waveform />
    </WaveformPlaylistProvider>
  );
}
Audio Credits: "Ubiquitous" by Albert Kader — Minimal Techno stems from the Cambridge Music Technology multitrack library. Licensed under CC BY 4.0.
Buy Me A Coffee