CLI
waveform-gen ./audio/*.mp3 --output ./waveforms/ — batch-generate one JSON per file.
WaveformGen is a Node CLI and ESM library that decodes audio files and writes normalized waveform peak data as JSON. Pre-generating peaks at build time means the player renders instantly — no client-side audio decode, no fetch-and-analyze on page load.
The JSON it produces drops straight into the player’s waveform option (or data-waveform / data-wb-waveform attributes), so the bars look identical to a live in-browser decode.
CLI
waveform-gen ./audio/*.mp3 --output ./waveforms/ — batch-generate one JSON per file.
Library
generatePeaks(filePath, options) — the single public export, returns a Promise.
Run it on demand with npx, install globally for a reusable waveform-gen command, or add it as a dev dependency to call the library from a build script.
# One-off, no install npx @arraypress/waveform-gen ./audio/*.mp3 --output ./waveforms/
# Global CLI npm install -g @arraypress/waveform-gen
# As a build dependency (library + CLI) npm install -D @arraypress/waveform-gen pnpm dlx @arraypress/waveform-gen ./audio/*.mp3 --output ./waveforms/ pnpm add -g @arraypress/waveform-gen pnpm add -D @arraypress/waveform-gen yarn dlx @arraypress/waveform-gen ./audio/*.mp3 --output ./waveforms/ yarn global add @arraypress/waveform-gen yarn add -D @arraypress/waveform-gen bunx @arraypress/waveform-gen ./audio/*.mp3 --output ./waveforms/ bun add -g @arraypress/waveform-gen bun add -d @arraypress/waveform-genRequirements: Node.js 18+, ESM only ("type": "module"). The only runtime dependency is audio-decode.
waveform-gen <files|directories...> [options]Positional arguments are audio files and/or directories. Anything starting with - must be a known flag — an unknown one stops the run with exit code 2. Value flags take --flag value or --flag=value. Use -- to end flag parsing, so later arguments are paths even if they start with - (a lone - is always a path).
# Generate one JSON per file into ./waveforms/waveform-gen ./audio/*.mp3 --output ./waveforms/
# Scan a directory treewaveform-gen ./audio/ --recursive --output ./waveforms/
# Lower resolution + tempo detectionwaveform-gen song.mp3 --samples 400 --bpm
# Print the peaks array to stdout for pipingwaveform-gen song.mp3 --format inline| Flag | Default | Type | Description |
|---|---|---|---|
--samples <n> |
1800 |
integer | Number of peaks (array length) generated per file. Higher = finer detail, larger JSON. Must be an integer of 1 or more, or the run exits 1. |
--precision <n> |
2 |
integer | Decimal places each peak is rounded to. Must be an integer (negative = unrounded), or the run exits 1. |
--output <dir> |
same dir as each input | path | Output directory. A file found inside a directory input keeps its path relative to that directory (out/a/intro.json), with folders created as needed; file arguments write straight into <dir> (2.0.0+). |
--format <type> |
json |
json | inline |
json writes a <name>.json file; inline prints peaks to stdout — a bare array for a single file argument, or one object keyed by path for several files or any directory (2.0.0+). Any other value exits 1. |
--bpm |
false |
flag | Run BPM detection and write an integer "bpm" into the JSON (only when a tempo is found). |
--recursive |
false |
flag | Scan passed directories recursively. Default scans the top level only. |
--quiet |
false |
flag | Suppress progress and the summary line. Errors always go to stderr (2.0.0+). |
--help, -h |
— | flag | Print help and exit(0). Also shown when run with zero arguments. |
-- |
— | — | End of flags: every later argument is an input path. |
Boolean flags (--bpm, --recursive, --quiet) take no value — --bpm=true is a usage error (exit 2).
Both the CLI (--samples) and the library generatePeaks() default to 1800 peaks — the SoundCloud-scale resolution that keeps wide / high-DPI waveforms crisp.
| Situation | Behavior |
|---|---|
--help / -h / no args |
Prints help, exit(0). |
| Every file generated | exit(0). |
| Unknown flag, flag missing its value, value on a boolean flag | [WaveformGen] … (see --help), exit(2) before anything runs. |
Invalid flag value (--samples 0, --samples abc, --format xml) |
Error message, exit(1) before anything runs. |
| No audio files resolved | [WaveformGen] No audio files found., exit(1). |
| Fatal / uncaught error | [WaveformGen] Fatal error: …, exit(1). |
| A single file fails to decode, or its output path is already taken | Reported on stderr (❌ name: message), run continues, then exit(1) (2.0.0+). |
| Input path doesn’t exist or can’t be read | [WaveformGen] Skipping … on stderr, run continues, then exit(1) (2.0.0+). |
| File argument with a non-audio extension | Ignored silently. |
Per-file failures never abort a batch — a run over 100 files where 3 fail still writes the other 97 — but the run then exits 1, so a prebuild step fails instead of shipping with missing JSON (2.0.0+; earlier versions exited 0). Errors go to stderr even with --quiet. Without --quiet, a closing Done: N generated, M failed line summarises the run. Every log and error is prefixed [WaveformGen].