Audio analysis CLI: SuperFlux onsets + RNN/DBN beats and downbeats, with streaming NDJSON logs.
Project description
zigify-madmom
Audio analysis CLI: percussive onsets, beats, and downbeats for a single
audio file, packaged as a uvx-runnable tool with a streaming JSON
protocol so other processes (Node, Bun, anything) can consume progress
events live and capture the final result cleanly.
Built on madmom: SuperFlux ODF on the HPSS percussive component, adaptive peak picking, density-aware NMS, an energy-rescue pass, and madmom's RNN/DBN beat & downbeat trackers.
Install / run
# one-shot, no install
uvx zigify-madmom path/to/audio.mp3 > result.json
# project-local (in a uv project)
uv add zigify-madmom
# pip
pip install zigify-madmom
Heads up —
madmomon PyPI is stale. The last PyPI release of madmom (0.16.1, 2018) does not work with NumPy >= 2. This package declaresmadmomas a regular dependency for PyPI compliance, but in practice you'll want the currentmainbranch from CPJKU/madmom. When usinguv, the bundled[tool.uv.sources]inpyproject.tomlalready does this for you. With plainpip, install the git version yourself first:pip install "madmom @ git+https://github.com/CPJKU/madmom" pip install zigify-madmom
CLI
zigify-madmom AUDIO [--config FILE] [--write-viewer] [--viewer-dir DIR]
[--stdin-suffix .wav] [--print-defaults]
AUDIO— path to an audio file, or-to read raw bytes from stdin (buffered to a temp file because madmom's beat trackers expect a path).--config FILE— JSON config file. Keys are deep-merged over the defaults; omit to use defaults. See--print-defaultsfor the schema.--write-viewer— also write<stem>.png,<stem>.html,<stem>.jsonnext to the audio. The HTML is a self-contained player with a synced cursor over the saved plot.--viewer-dir DIR— override where viewer files go (default: alongside the audio file).--stdin-suffix— extension for the temp file when reading stdin (default.wav); set to match your input format if needed.--print-defaults— print the default config as JSON and exit. Use as a starting template:zigify-madmom --print-defaults > my-config.json
Examples
# defaults, capture payload to a file
zigify-madmom audio.mp3 > out.json
# custom config + viewer files
zigify-madmom audio.mp3 --config tuned.json --write-viewer
# pipe from ffmpeg
ffmpeg -i input.flac -f wav - | zigify-madmom - --stdin-suffix .wav > out.json
Streaming protocol
The CLI splits its output across two streams so a parent process can display progress live and still parse the final result:
| Stream | Format | Purpose |
|---|---|---|
| stderr | NDJSON, one per line | Progress / log events |
| stdout | One JSON object | Final analysis payload |
Every stderr line is a complete JSON object with at minimum level and
msg, plus optional fields like stage, counters, paths. Errors come
through the same channel with "level": "error" and a traceback field;
the process exits non-zero.
// stderr — observed live
{"level":"info","msg":"Loading audio","stage":"load","path":"audio.mp3"}
{"level":"info","msg":"Computing SuperFlux ODF","stage":"odf","hpss":true}
{"level":"info","msg":"Onset NMS complete","stage":"onset_nms","primary":560,"raw":949,"culled":389}
{"level":"info","msg":"Energy rescue complete","stage":"onset_rescue","energy":360}
{"level":"info","msg":"Tracking beats","stage":"beats"}
{"level":"info","msg":"Tracking downbeats","stage":"downbeats"}
{"level":"info","msg":"Tempo computed","stage":"tempo","bpm_med":100.0,"bpm_min":71.4,"bpm_max":107.1}
{"level":"info","msg":"Done","stage":"done"}
// stdout — single JSON object at end
{
"meta": {
"file": "audio.mp3",
"duration_s": 242.98,
"fps": 100,
"mode": "HPSS+SuperFlux",
"tempo_bpm": 100.0,
"tempo_range_bpm": [71.4, 107.1],
"beats_per_bar_candidates": [4, 4]
},
"bars": [
{ "index": 1, "start_s": 0.123, "end_s": 2.521,
"beats": [0.123, 0.722, 1.323, 1.922],
"rms_db": -18.4, "odf_energy": 0.27 }
],
"beats": [0.123, 0.722, 1.323, /* ... */],
"downbeats": [0.123, 2.521, /* ... */],
"onsets": [{ "t": 0.42, "strength": 0.61 }, /* ... */],
"onsets_energy": [{ "t": 0.45, "strength": 0.18 }, /* ... */]
}
Consuming from TypeScript
import { spawn } from "node:child_process";
import { createInterface } from "node:readline";
const proc = spawn("zigify-madmom", ["audio.mp3", "--config", "cfg.json"]);
const rl = createInterface({ input: proc.stderr });
rl.on("line", (line) => {
const evt = JSON.parse(line);
console.log(`[${evt.stage ?? evt.level}] ${evt.msg}`);
});
let stdout = "";
proc.stdout.on("data", (chunk) => (stdout += chunk));
proc.on("close", (code) => {
if (code !== 0) throw new Error(`exit ${code}`);
const payload = JSON.parse(stdout);
// payload.meta, payload.bars, payload.beats, ...
});
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Analysis error (see stderr traceback) |
| 2 | Bad arguments / missing file / config parse error |
| 130 | Interrupted (Ctrl+C) |
Config
The full default config is available via zigify-madmom --print-defaults.
Top-level keys:
fps— analysis frame rate (default 100)use_hpss— gate the ODF on the HPSS percussive component (default true)hpss.{masking_p, harmonic_filter, percussive_filter}— HPSS knobsonset.{offset, pre_avg_s, post_avg_s, combine_s, nms_quiet_s, nms_loud_s, rescue_min_density, rescue_min_strength, rescue_min_spacing_s}— peak picking, density-adaptive NMS, and the energy-rescue passbeats.beats_per_bar— candidate meters for the DBN downbeat trackerviewer.{png_px_per_minute, png_dpi, png_min_width_in}— only used with--write-viewer
Partial configs are deep-merged; only override what you want to change.
{
"use_hpss": false,
"onset": { "offset": 0.15, "nms_loud_s": 0.25 }
}
Programmatic use
from zigify_madmom import analyze, load_config
cfg = load_config(None) # defaults; pass a path to override
result = analyze("audio.mp3", cfg)
payload = result["payload"]
analyze() accepts an optional log callable for custom progress
reporting: analyze(path, cfg, log=lambda msg, **kw: ...).
Development
git clone <repo>
cd zigify-madmom
uv sync
uv run zigify-madmom audio/your-track.mp3
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zigify_madmom-1.1.0.tar.gz.
File metadata
- Download URL: zigify_madmom-1.1.0.tar.gz
- Upload date:
- Size: 30.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
237f7f3872d9a49f928883f9558d43195b793541498238ba7e4f229ee09800e5
|
|
| MD5 |
501cdd40b5873ea2e93759f7194e3713
|
|
| BLAKE2b-256 |
e084aa093dbeba09f3119d5b2ce541245684c44020d41671d0237273e65a00bb
|
File details
Details for the file zigify_madmom-1.1.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: zigify_madmom-1.1.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 30.9 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5bf03359f756c341cf31869116f3aad833c158fc60afa4e7c33485133676b74
|
|
| MD5 |
5b6a557a414ace8f1c8aaf56d7d5ae50
|
|
| BLAKE2b-256 |
f8073fc4e24f0d5279d204adbbd4c34fbbd54b8a301794091165ffc8427b9838
|