--- license: mit tags: - coreml - apple-silicon - ios - beat-this - beat-tracking - downbeat-tracking - music-information-retrieval - schism-coreml --- # Beat This! — Core ML [CPJKU/beat_this](https://github.com/CPJKU/beat_this) (`final0` checkpoint; "Beat This! Accurate Beat Tracking Without DBN Postprocessing", [Foscarin, Schlüter & Widmer, ISMIR 2024](https://arxiv.org/abs/2407.21658), **MIT licensed**) for Core ML on Apple devices. Frame-wise beat and downbeat tracking at 50 fps with minimal peak-picking postprocessing — no DBN. Converted from the same verified reference used by the [schism-mlx](https://github.com/schism-audio/schism-mlx) MLX ports. Two variants per model: | File | Precision | Compute units | max logit diff | |---|---|---|---| | `BeatThis_fp16.mlpackage` | FLOAT16 | ALL (ANE) | 6.7e-2, peak-picked beat/downbeat times identical on tested real drum audio | | `BeatThis_fp32.mlpackage` | FLOAT32 | CPU+GPU | 5.2e-5, peak-picked beat/downbeat times identical on all tested clips | Verified on-device-equivalently via coremltools on an M5 Max, against the reference implementation on real audio. fp16 is ANE-eligible and recommended for iPhone / iPad; fp32 is the tight-parity fallback. ## Download `.mlpackage` bundles must be materialized as real files — the Core ML compiler rejects the symlinks that a default `snapshot_download` creates in the Hugging Face cache: ```python from huggingface_hub import snapshot_download path = snapshot_download("schism-audio/beat-this-coreml", local_dir="./beat-this-coreml") ``` (or `hf download schism-audio/beat-this-coreml --local-dir ./beat-this-coreml`). Swift hosts downloading files directly are unaffected. ## I/O contract - input `spect`: `(1, 1500, 128)` float32 — one 30 s chunk of the log-mel frontend (22.05 kHz mono, n_fft 1024, hop 441, 128 slaney mels 30–11000 Hz **without** area norm, magnitude STFT normalized `1/sqrt(n_fft)`, `log1p(1000 x)`), 50 fps - outputs `beat_logits` / `downbeat_logits`: `(1, 1500)` float32 — frame-wise logits at 50 fps; sigmoid for probabilities, peak-pick for times (local maxima within ±3 frames with logit > 0, adjacent peaks merged by averaging, downbeats snapped to the nearest beat — the reference "minimal" postprocessor) - longer audio: 1500-frame chunks starting at `-6 + k*1488`, last start shifted left to `n - 1494` so the last chunk ends at the piece end; chunk borders that fall outside the piece are zero-padded on the **spectrogram**; discard the 6 border frames of every chunk, earlier chunks winning on overlap ("keep_first"); frames no chunk covers keep the filler -1000 (see `test_vectors_beatmel.npz` params) - pieces shorter than 1488 frames (~29.8 s): the reference runs one shorter window that this fixed-shape graph cannot reproduce — attention is global, so zero-padding to 1500 frames changes all logits slightly (beat times on tested real audio were still identical; pad with zeros and drop the padded frames, or prefer the MLX port for exactness) ## DSP frontend (host-side) The Core ML graph contains the network only. The host implements the log-mel frontend and must match `schism_mlx.analyze.beat_this.model.logmel_beat_this` numerically — `test_vectors_beatmel.npz` in this repo holds deterministic input/output pairs plus the exact slaney filterbank matrix (float32; match within ~1e-4 relative). Its params json documents the full 30 s chunk/stitching contract and the peak-picking recipe. A validated Swift implementation (Accelerate) is available at [schism-audio/schism-dsp](https://github.com/schism-audio/schism-dsp), tested against these exact vectors. ## License MIT, inherited from the source repository (code and released weights). Model by the [Institute of Computational Perception, JKU Linz](https://github.com/CPJKU); Core ML conversion by [schism-audio](https://huggingface.co/schism-audio).