Audio analysis that machines (and humans) can read.
Point beatlyzer at an .mp3 (or .wav, .flac, .ogg, .m4a, …) and it produces:
- a structured, LLM-friendly JSON description of the track,
- a rich terminal summary,
- an annotated multi-panel visualization (PNG) marking beat drops, volume surges, high tones, brightness, structure and the spectrogram,
- an optional Markdown report.
It's designed so a vision- or text-capable AI model can "understand" a song: what it sounds like, how it's structured, where the energy peaks, and exactly when the interesting moments happen.
beatlyzer demo.wav produces this four-panel analysis:
Alongside the PNG it writes a machine-readable
demo.beatlyzer.json and a
demo.beatlyzer.md report — both included here. Regenerate
the demo input yourself with python scripts/make_sample.py demo.wav.
| Signal | How | Output |
|---|---|---|
| Tempo & beats | librosa beat tracking | BPM + beat grid |
| Key | Krumhansl-Schmuckler chroma correlation | e.g. F minor |
| Beat drops | sharp rises into loud, bass-heavy passages, snapped to beats | timeline events |
| Volume surges | crescendos / hits (loudness jumps that aren't drops) | timeline events |
| High tones | spectral-centroid + treble-energy peaks | timeline events |
| Loudness & dynamics | RMS in dB relative to peak | avg / peak / dynamic range |
| Brightness | spectral centroid | dark ↔ airy |
| Structure | agglomerative clustering of timbre+harmony | intro → build → drop → outro |
Requires Python 3.9+ (3.10+ for the MCP server). For mp3/m4a/aac decoding
you need ffmpeg on your PATH (sudo dnf install ffmpeg /
brew install ffmpeg / apt install ffmpeg).
The cleanest way to get beatlyzer (and beatlyzer-mcp) available everywhere
is pipx or uv, which each
install the tool into their own isolated environment and put the commands on
your PATH — you never create or activate a virtualenv yourself:
# pipx
pipx install 'git+https://github.com/Profazia/beatlyzer.git'
pipx inject beatlyzer mcp # add the MCP server extra
# or uv
uv tool install 'beatlyzer[mcp] @ git+https://github.com/Profazia/beatlyzer.git'
# run once without installing anything permanent:
uvx --from 'git+https://github.com/Profazia/beatlyzer.git' beatlyzer song.mp3Note:
librosa/numbamay lag the newest Python release. If a build fails, pin the interpreter:pipx install --python python3.12 ....
pip install -e ".[dev,mcp]" # editable install with test + MCP depsThis installs the beatlyzer and beatlyzer-mcp commands.
# analyze a file — writes <name>.beatlyzer.{png,json,md} next to it
beatlyzer song.mp3
# choose an output directory and open the image when done
beatlyzer track.wav -o out/ --open
# only the machine-readable JSON, printed to stdout, no files, no chatter
beatlyzer mix.flac --format json --print-json --quietDon't have a file handy? Generate a demo track:
python scripts/make_sample.py sample.wav
beatlyzer sample.wav --open-o, --output-dir DIR Where to write outputs (default: next to the input)
-f, --format CHOICE all | png | json | md | none (default: all)
--stem NAME Base name for output files (default: input name)
--sr INT Analysis sample rate (default: 22050)
--dpi INT PNG resolution (default: 140)
--open Open the PNG when finished
--quiet Suppress the terminal summary
--print-json Print the JSON summary to stdout
-V, --version Show version
Run as a module too: python -m beatlyzer song.mp3.
<name>.beatlyzer.json follows the beatlyzer.analysis/v1 schema. Feed it
straight to an LLM — it's self-describing (see the ai_notes field):
<name>.beatlyzer.png is a four-panel figure sharing one time axis:
- Waveform with shaded structural sections and a faint beat grid.
- Loudness (dB) with beat drops (red) and volume surges (orange).
- Brightness (spectral centroid) with high-tone peaks (purple).
- Mel spectrogram with drop lines overlaid.
beatlyzer ships an MCP server so AI agents — Claude Code, Claude Desktop, Cursor, etc. — can analyze audio directly. It runs over stdio and exposes three tools:
| Tool | Returns |
|---|---|
analyze_audio(file_path, sample_rate=22050) |
full structured JSON summary |
describe_audio(file_path) |
a short prose description |
visualize_audio(file_path, output_path=None, dpi=140) |
the annotated PNG, as an image the model can see |
Make sure the mcp extra is installed (pipx inject beatlyzer mcp, or
pip install 'beatlyzer[mcp]'), then register the server.
Claude Code:
claude mcp add beatlyzer beatlyzer-mcpClaude Desktop / any MCP client (claude_desktop_config.json or equivalent):
{
"mcpServers": {
"beatlyzer": {
"command": "beatlyzer-mcp"
}
}
}If beatlyzer-mcp isn't on the client's PATH, use the absolute path (e.g.
~/.local/bin/beatlyzer-mcp, or the one printed by pipx list). A ready-made
snippet lives in examples/mcp-config.json.
Then just ask the model things like "analyze ~/Music/track.mp3 and tell me where the beat drops are" or "visualize this song."
from beatlyzer import analyze_file
from beatlyzer.report import build_result_dict
result = analyze_file("song.mp3")
print(result.summary_text)
print([e.time for e in result.drops])
doc = build_result_dict(result) # the JSON-ready dictEvery detector smooths a feature track, measures how it transitions (mean energy after a moment minus mean before), then keeps prominent, well-separated peaks and snaps them to the nearest beat:
- Drops blend overall RMS with sub-250 Hz bass energy and additionally require the landing passage to be genuinely loud — a build-up that fizzles isn't a drop.
- Surges track loudness jumps and are de-duplicated against drops.
- High tones combine the spectral centroid with the >4 kHz energy share.
These are transparent heuristics, not a trained model — fast, dependency-light,
and explainable. Tune thresholds in src/beatlyzer/events.py.
pip install -e ".[dev]"
pytestMIT — see LICENSE.

{ "schema": "beatlyzer.analysis/v1", "metadata": { "duration_hms": "0:24", "tempo_bpm": 128.0, "estimated_key": "A minor", ... }, "loudness": { "average_db": -18.4, "dynamic_range_db": 31.2, "description": "wide dynamics" }, "brightness":{ "average_centroid_hz": 2680.0, "description": "balanced" }, "sections": [ { "label": "intro", "start_hms": "0:00", "energy_level": "low" }, ... ], "events": [ { "time_hms": "0:09", "type": "beat_drop", "strength_0_1": 1.0, "bass_share": 0.71, "description": "Beat drop at 0:09 — energy surges into a loud, bass-heavy section." }, { "time_hms": "0:17", "type": "high_tone", "strength_0_1": 0.93, "centroid_hz": 6011.0, ... } ], "energy_profile": [ { "t": 0.0, "energy": 0.05, "loudness_db": -34.1, "brightness": 0.2 }, ... ], "summary_text": "This 0:24 track is a high-energy piece at 128 BPM in A minor. ...", "ai_notes": "Times are seconds from the start. 'loudness' is dB relative to the track's peak ..." }