A Minimal BPM/beat tracker using CoreML. Lightweight, permissive.
- macOS-first, optimized for Apple's DSP stack and CoreML.
- Small, readable core suitable for embedding as a library.
- Fast beat and downbeat estimation with minimal dependencies.
cmake -S . -B build -G Ninja
cmake --build buildHomebrew (HEAD):
brew install --build-from-source ./Formula/beatit.rb./build/beatit --input /path/to/audio.mp3Options:
-i, --input <path>audio file (MP3/MP4/WAV/AIFF/CAF)--sample-rate <hz>resample before analysis--model <path>CoreML model path (.mlmodelc)--ml-input <name>CoreML input feature name--ml-beat <name>CoreML beat output name--ml-downbeat <name>CoreML downbeat output name--ml-sr <hz>CoreML feature sample rate--ml-frame <frames>CoreML feature frame size--ml-hop <frames>CoreML feature hop size--ml-mels <bins>CoreML mel bin count--ml-threshold <value>CoreML activation threshold--ml-beattrackuse BeatTrack CoreML defaults--ml-tempo-window <pct>percent window around classic BPM--ml-prefer-doubleprefer double-time BPM if stronger--ml-refine-constantpost-process beats into a constant grid--ml-refine-csvprint CSV for constant beat events--ml-refine-downbeatuse model downbeats to anchor bar phase--ml-refine-halfbeatenable half-beat phase correction--ml-cpu-onlyforce CoreML CPU-only execution--ml-infoprint CoreML model metadata--infoprint decoded audio stats-h, --helpshow help
Run ./build/beatit --help for the full list.
CLI is for development/testing only. The reusable API lives in include/beatit/analysis.h.
For long files, use beatit::BeatitStream to feed audio in chunks without loading
everything into memory. It produces the same AnalysisResult after finalize().
#include "beatit/stream.h"
beatit::CoreMLConfig ml_cfg;
beatit::BeatitStream stream(sample_rate, ml_cfg, true);
stream.push(chunk.data(), chunk.size());
beatit::AnalysisResult result = stream.finalize();CBR (Constant Beat Refiner) turns beat/downbeat activations into a stable beat grid of
BeatEvents with bar/marker annotations. Optional switches: downbeat anchoring and
half-beat correction.
./build/beatit --input training/moderat.wav --ml-refine-constant --ml-refine-csv --ml-cpu-onlyDefault CoreML settings match BeatTrack (torchaudio MelSpectrogram; no log scaling):
- sample rate: 44.1 kHz
- frame size: 2048
- hop size: 441
- mel bins: 81
- input layout:
[1, 1, frames, bins] - fixed frames: 3000 (30s at 100 fps, truncated/padded)
The loader checks models/beatit.mlmodelc, Homebrew share/beatit/beatit.mlmodelc, then
the app bundle resource beatit.mlmodelc. The CoreML model is expected to expose:
- input:
input(shape[1, 1, frames, 81], float32) - outputs:
beatanddownbeat(frame-wise activations)
You can override names/paths by editing beatit::CoreMLConfig or using the CLI --model flag.
If you are exporting a model from another repository (e.g. BeatTrack), use the --ml-* flags
to match its input/output names and feature settings. For BeatTrack exports, use .mlpackage
and compile to .mlmodelc with xcrun coremlc compile.
- ML model: BeatTrack — Matthew Rice — https://github.com/mhrice/BeatTrack — MIT.
- Training data: Ballroom dataset (ISMIR 2004 tempo contest, MTG UPF) — https://mtg.upf.edu/ismir2004/contest/tempoContest/ — license per dataset provider (not redistributed here).