Skip to content

Profazia/beatlyzer

Repository files navigation

beatlyzer

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.


Example

beatlyzer demo.wav produces this four-panel analysis:

beatlyzer analysis of demo.wav

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.


What it detects

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

Install

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).

As a global CLI tool — recommended, no venv to manage

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.mp3

Note: librosa/numba may lag the newest Python release. If a build fails, pin the interpreter: pipx install --python python3.12 ....

From a clone (development)

pip install -e ".[dev,mcp]"       # editable install with test + MCP deps

This installs the beatlyzer and beatlyzer-mcp commands.


Usage

# 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 --quiet

Don't have a file handy? Generate a demo track:

python scripts/make_sample.py sample.wav
beatlyzer sample.wav --open

Options

-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.


The AI-readable JSON

<name>.beatlyzer.json follows the beatlyzer.analysis/v1 schema. Feed it straight to an LLM — it's self-describing (see the ai_notes field):

{
  "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 ..."
}

The visualization

<name>.beatlyzer.png is a four-panel figure sharing one time axis:

  1. Waveform with shaded structural sections and a faint beat grid.
  2. Loudness (dB) with beat drops (red) and volume surges (orange).
  3. Brightness (spectral centroid) with high-tone peaks (purple).
  4. Mel spectrogram with drop lines overlaid.

Use it as an MCP server

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-mcp

Claude 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."


As a library

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 dict

How the detection works (short version)

Every 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.

Development

pip install -e ".[dev]"
pytest

License

MIT — see LICENSE.

About

Analyze audio files into AI-readable summaries and annotated visualizations of beats, drops, volume surges and tonal content. CLI + MCP server.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages