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.
- 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
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 -versionUsing Homebrew:
brew install ffmpegsudo apt update
sudo apt install ffmpegFFmpeg can be installed using Windows Package Manager:
winget install Gyan.FFmpegRestart your terminal after installation and confirm that this works:
ffmpeg -versionOnce FastPeaks is available from PyPI:
pip install fastpeaksFor 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\activateGenerate 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.
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.
Generate peaks and print JSON to the terminal:
fastpeaks "audio.mp3"Generate 2,000 peaks:
fastpeaks "audio.mp3" --num-peaks 2000Enable caching:
fastpeaks "audio.mp3" --cacheForce cache regeneration:
fastpeaks "audio.mp3" --refresh-cacheWrite the peaks to a file:
fastpeaks "audio.mp3" --output peaks.jsonGenerate formatted JSON:
fastpeaks "audio.mp3" --pretty --output peaks.jsonUse a custom cache directory:
fastpeaks "audio.mp3" \
--cache-dir "./peak_cache" \
--output peaks.jsonDisplay timings:
fastpeaks "audio.mp3" \
--cache \
--timings \
--output peaks.jsonSee all available options:
fastpeaks --helpGenerate the peak file:
fastpeaks "audio.mp3" \
--num-peaks 2000 \
--output peaks.jsonLoad 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 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.
FastPeaks asks FFmpeg to:
- Decode the source audio
- Select the first audio stream
- Downmix it to mono
- Resample it to a low analysis sample rate
- Return signed 16-bit PCM to Python
NumPy then:
- Converts the PCM data to normalized floating-point samples
- Divides the samples into equally sized sections
- Calculates the RMS amplitude of every section
- Normalizes the largest result to
1.0 - 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.
Install the development dependencies:
python -m pip install -e ".[dev]"Run the tests:
pytestBuild the package:
python -m buildCheck the generated distributions:
python -m twine check dist/*FastPeaks is released under the MIT License.