drone-v1
A 109,128-parameter key classifier: 24 classes (12 tonics x major/minor) from a constant-Q spectrogram. K10 (MIREX 2026) architecture, retrained on 1,363 Beatport EDM tracks. The smallest model to beat the native libkeyfinder reference (69.35% MIREX) on the held-out GiantSteps 604.
Results
Held-out GiantSteps 604, single evaluation per seed:
| seed | exact | MIREX |
|---|---|---|
| 13 | 68.5% | 74.8% |
| 37 | 66.1% | 73.0% |
| 73 | 65.7% | 72.9% |
| mean | 66.8% | 73.58% |
The shipped drone-v1.pt is the seed-13 checkpoint. drone-v1.onnx is its
export (opset 18, dynamic batch, CPU parity verified).
Input contract
- Audio: mono, 22,050 Hz PCM (decode with any standard decoder, e.g. ffmpeg).
- Features:
librosa.cqt, 24 bins per octave, 208 bins from two semitones below C1 (fmin ~ 25.957 Hz), hop 4096,log1pamplitude, shape(208, frames). The 192 core bins are rows 8..199; the 16 outer rows are the +/-(4) semitone shift pad. - Model input:
(batch, 192, frames)β the core window of the CQT, any length= 1 frame (the head pools over time).
- Output: 24 logits. Class
i= tonici // 12semitones from C, modei % 2(0 = major, 1 = minor).
Usage
Python (PyTorch):
from drone import Predictor
predictor = Predictor() # resolves drone-v1.pt by default
print(predictor.predict("track.mp3")) # (tonic, mode, softmax probability)
Or raw, with the ONNX file:
import numpy as np
import onnxruntime as ort
import librosa
y, _ = librosa.load("track.mp3", sr=22050, mono=True)
cqt = np.log1p(np.abs(librosa.cqt(
y, sr=22050, hop_length=4096, fmin=25.95661061576629,
n_bins=208, bins_per_octave=24)))
x = cqt[8:200].astype(np.float32)[None]
logits = ort.InferenceSession("drone-v1.onnx").run(["logits"], {"features": x})[0]
Training
Beatport EDM Key Dataset previews (1,363 of 1,486 usable; 933 minor / 430
major), K10 protocol: 320-frame crops, +/-(4) semitone shift as an exact
re-slice with a transposed label, AdamW 1e-3, cosine 120 epochs, batch 32,
plain cross-entropy. Audio is (c) Beatport; annotations are CC BY-SA 4.0.
Full story in docs/training.md
in the source repository.
Caveats
Trained on 2-minute EDM previews; expect lower accuracy on long, genre-diverse recordings. Softmax values are uncalibrated.
Evaluation results
- MIREX (weighted) on GiantSteps (held-out, 604 tracks)self-reported73.580
- exact on GiantSteps (held-out, 604 tracks)self-reported66.800