Skip to content
staymlPublic

About

Fast waveform peak generation for WaveSurfer.js using FFmpeg and NumPy.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

FastPeaks

FastPeaks is a small Python library and command-line tool that generates normalized waveform peaks from audio files.

It is designed for supplying precomputed waveform data to browser waveform libraries such as WaveSurfer.js.

FastPeaks uses FFmpeg to decode audio directly to low-sample-rate mono PCM and NumPy to calculate waveform peaks efficiently. A 77-minute MP3 can be processed in approximately four seconds on typical desktop hardware, while cached results can be loaded in milliseconds.

FastPeaks was originally built for SayRec, a free online voice recorder that uses precomputed peaks to render audio waveforms efficiently.

Features

  • Generate normalized RMS waveform peaks
  • Process MP3 and other FFmpeg-supported audio formats
  • Decode directly to low-sample-rate mono audio
  • Choose the number of returned peaks
  • Optional JSON caching
  • Automatic cache invalidation when the source file changes
  • Force cache regeneration when required
  • Python API
  • Command-line interface
  • JSON output suitable for WaveSurfer.js

Requirements

FastPeaks requires:

  • Python 3.10 or newer
  • FFmpeg
  • NumPy

NumPy is installed automatically with FastPeaks. FFmpeg must be installed separately and available through your system's PATH.

Check whether FFmpeg is installed:

ffmpeg -version

Installing FFmpeg on macOS

Using Homebrew:

brew install ffmpeg

Installing FFmpeg on Ubuntu or Debian

sudo apt update
sudo apt install ffmpeg

Installing FFmpeg on Windows

FFmpeg can be installed using Windows Package Manager:

winget install Gyan.FFmpeg

Restart your terminal after installation and confirm that this works:

ffmpeg -version

Installation

Once FastPeaks is available from PyPI:

pip install fastpeaks

For local development, clone the repository and install it in editable mode:

git clone https://github.com/stayml/fastpeaks.git
cd fastpeaks

python -m venv .venv
source .venv/bin/activate

python -m pip install --upgrade pip
python -m pip install -e ".[dev]"

On Windows, activate the virtual environment with:

.venv\Scripts\activate

Python usage

Generate 1,000 waveform peaks:

import fastpeaks

peaks = fastpeaks.generate_peaks("audio.mp3")

Generate 2,000 peaks:

import fastpeaks

peaks = fastpeaks.generate_peaks(
    "audio.mp3",
    num_peaks=2000,
)

Enable caching:

import fastpeaks

peaks = fastpeaks.generate_peaks(
    "audio.mp3",
    num_peaks=2000,
    cache=True,
)

Force cache regeneration:

import fastpeaks

peaks = fastpeaks.generate_peaks(
    "audio.mp3",
    num_peaks=2000,
    cache=True,
    refresh_cache=True,
)

Use a custom cache directory:

import fastpeaks

peaks = fastpeaks.generate_peaks(
    "audio.mp3",
    cache=True,
    cache_dir="./peak_cache",
)

Display performance timings:

import fastpeaks

peaks = fastpeaks.generate_peaks(
    "audio.mp3",
    num_peaks=2000,
    cache=True,
    show_timings=True,
)

Timing information is written to stderr.

Function parameters

fastpeaks.generate_peaks(
    audio_path,
    num_peaks=1000,
    decode_sample_rate=2000,
    decimals=4,
    cache=False,
    cache_dir=None,
    refresh_cache=False,
    show_timings=False,
)
Parameter Description
audio_path Path to the input audio file.
num_peaks Number of peaks to return. Defaults to 1000.
decode_sample_rate FFmpeg output sample rate used for analysis. Defaults to 2000.
decimals Decimal places in returned values. Defaults to 4.
cache Load and save JSON cache data when True.
cache_dir Optional cache directory. Defaults to .fastpeaks_cache.
refresh_cache Ignore existing cache data and regenerate it.
show_timings Print performance information to stderr.

refresh_cache=True automatically enables caching.

The returned value is a normal Python list:

[0.4835, 0.6149, 0.2875, 0.7414, 1.0]

Values are normalized between 0.0 and 1.0.

Command-line usage

Generate peaks and print JSON to the terminal:

fastpeaks "audio.mp3"

Generate 2,000 peaks:

fastpeaks "audio.mp3" --num-peaks 2000

Enable caching:

fastpeaks "audio.mp3" --cache

Force cache regeneration:

fastpeaks "audio.mp3" --refresh-cache

Write the peaks to a file:

fastpeaks "audio.mp3" --output peaks.json

Generate formatted JSON:

fastpeaks "audio.mp3" --pretty --output peaks.json

Use a custom cache directory:

fastpeaks "audio.mp3" \
    --cache-dir "./peak_cache" \
    --output peaks.json

Display timings:

fastpeaks "audio.mp3" \
    --cache \
    --timings \
    --output peaks.json

See all available options:

fastpeaks --help

Using peaks with WaveSurfer.js

Generate the peak file:

fastpeaks "audio.mp3" \
    --num-peaks 2000 \
    --output peaks.json

Load both the peaks and audio in JavaScript:

async function createWaveform() {
    const response = await fetch("/peaks.json");

    if (!response.ok) {
        throw new Error(
            `Could not load waveform peaks: ${response.status}`
        );
    }

    const peaks = await response.json();

    const wavesurfer = WaveSurfer.create({
        container: "#waveform",
        url: "/audio.mp3",
        peaks: [peaks],
        duration: 300,
    });

    return wavesurfer;
}

createWaveform().catch((error) => {
    console.error(error);
});

Replace duration: 300 with the duration of your audio in seconds.

Caching

Caching is disabled by default.

When enabled, FastPeaks stores JSON cache files under:

.fastpeaks_cache/

A custom directory can be supplied using cache_dir or --cache-dir.

Cache entries account for:

  • Resolved audio path
  • Audio file size
  • Audio modification time
  • Number of requested peaks
  • Decode sample rate
  • Decimal precision
  • FastPeaks algorithm version

If the source file changes, its existing cache entry is treated as stale and regenerated.

Cache files are written atomically to reduce the risk of incomplete files.

How it works

FastPeaks asks FFmpeg to:

  1. Decode the source audio
  2. Select the first audio stream
  3. Downmix it to mono
  4. Resample it to a low analysis sample rate
  5. Return signed 16-bit PCM to Python

NumPy then:

  1. Converts the PCM data to normalized floating-point samples
  2. Divides the samples into equally sized sections
  3. Calculates the RMS amplitude of every section
  4. Normalizes the largest result to 1.0
  5. Returns the requested number of peaks

The low decode sample rate dramatically reduces memory usage and Python processing time. FFmpeg decoding remains the largest part of first-time processing.

Development

Install the development dependencies:

python -m pip install -e ".[dev]"

Run the tests:

pytest

Build the package:

python -m build

Check the generated distributions:

python -m twine check dist/*

Licence

FastPeaks is released under the MIT License.

About

Fast waveform peak generation for WaveSurfer.js using FFmpeg and NumPy.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages