← Vibeset · case note
Where's the one?
Cutting picture to music is not a beat-detection problem. It's a bar problem. Every tool will tell you where the beats are; the useful question is which of them is the one. We started with a one-line library call that guessed the bar once per song and never said whether it was right, and ended with a 20-million-parameter model we serve ourselves on CPU. The most valuable thing we found along the way was a defect that no published benchmark in this field is capable of showing you.
01 — The problem
Beats are the easy part. The downbeat is the product
An editor lands a cut on the 1. So does a camera move, a title card, a character hitting a pose. Get the beat grid right and the bar phase wrong, and every one of those lands on the 2. Steady, confident, and wrong in a way nobody can point at.
You hear it before you can name it. A lyric restarting in the wrong place. A hit that arrives a beat early for three minutes.
A noisy grid announces itself. A mis-phased grid passes every gate you have and feels off.
02 — Where it started
One line of librosa, and a guess we never checked
The first version called librosa.beat.beat_track, like most first versions do. It returns beats.
It does not return downbeats, so bar phase came from a low-band kick heuristic that picked
one global phase for the whole song. When that guess was wrong, every bar-aligned
edit in the piece was aligned to a grid offset from the music's actual bars.
One measurement ended it, and one structural fact. Both had to be gone looking for; nothing in the product was failing.
03 — The seam
Change what's behind the door, not the door
Before swapping trackers, the beat grid moved behind one interface. The existing path was copied across verbatim, with a test asserting bit-identical output to the block it replaced. No behaviour change, on purpose.
That seam paid for itself within a day. The replacement went in and made the grid worse.
The provider handed a 22,050 Hz signal to a library that assumes 44,100. Every track read as half its real length. Every downbeat landed at the wrong time and the wrong phase.
The failure the swap existed to fix, reintroduced by the fix. Every unit test passed throughout, because no fixture ever crossed a sample-rate boundary.
04 — The instrument
Build the ruler before you trust the measurement
The next step wasn't a model. It was a benchmark harness, validated against numbers somebody else had already published. It reproduced Beat This!'s reported GTZAN row to within half a point, and madmom's to within one, before we read a single result of our own.
Unglamorous, and it decides whether anything after it means much. Until the ruler was trusted, every number we produced was a number about our own code rather than about the music.
What the numbers mean
Every figure below is downbeat CMLt. Read it as the share of a song where the predicted bar line stays locked to the real one. Not just close on average, but holding, beat after beat, without slipping. 100 would mean the bar is right everywhere. Published systems land in the low 70s, and the difference between 73 and 75 is a real one in this field.
05 — The find
The benchmarks are 30 seconds long. Songs aren't
GTZAN, Ballroom, SMC, Hainsworth: the corpora beat trackers are usually scored on are 30-second excerpts. One chunk. No seams. Full-length annotated sets do exist and we train on one, but no headline benchmark number in this field is computed over a song long enough to have a seam.
Real music isn't. A cue is three and a half minutes, and the model infers in 30-second chunks carrying no state across them. On an actual song it re-decides tempo and bar phase about six times, and no published metric can see it happen.
On three quarters of full-length songs, the bar count jumped somewhere mid-track, under the exact setup that had produced our entire stored catalogue.
The part worth keeping is what didn't work. Overlapping the chunks — the obvious fix, the one we built first and expected to win — measured no better than plain tiling. The problem was never the seam. It was that each chunk was allowed its own opinion about where the bar was.
Share of songs where the bar count jumped at least once · 60 full-length commercial tracks, averaging 3m28s with about six window joins each. Lower is better.
The difference is a grid that holds for three minutes versus one that is right until 0:47 and then quietly isn't. Anything downstream that trusts bar numbers inherits it: a cut placed on the 2, a loop spliced a beat out. None of it raises an error.
06 — The lever
It was the data. It kept being the data
Every public beat corpus is overwhelmingly Western. Ballroom, rock, jazz, classical, electronic. That is what the open models are trained on, and it is what they are good at.
So we scored the backbone on 99 held-out tracks of anime, game and rhythm-game music. It read 61.0 there against 75.0 on the standard benchmark. Same model, same decoder, a different part of the world.
We added 736 tracks of that repertoire to the training mix and fine-tuned. On the same held-out 99, the result went to 77.0.
Then we built a specialist just for it. On the specialist's own repertoire, the generalist trained on all sixteen corpora beat it by 4.4 points.
The specialisation wasn't what helped. Having the music in the mix at all was. That is also why the tempo story below matters here: 63% of that repertoire sits above 160 BPM, which is the band where everything, ours included, is weakest.
One honest limit, and it is the same one the API docs carry: 99 tracks cannot resolve a difference under about 3 points. This says what the model was trained on. It does not prove a margin.
07 — The cliff
We lowered the floor and forgot the ceiling
Accuracy is not evenly distributed across tempo, and that shape is the most useful thing here.
The fast band has a story attached. The decoder searches a tempo range, and ours was 55–215 BPM. We had three configurations that lowered the floor for slow music and not one that raised the ceiling. We had simply never looked at the other end.
Above 215 BPM the tracker was scoring 8.7. Raising the ceiling took that band to 50.0: a 41-point move, from changing a constant. It helps on a checkpoint we never trained, so it's a property of the decoder rather than of our model.
Which matters for a fast catalogue: 63% of the anime and rhythm-game corpus sits above 160 BPM. On GTZAN those tracks are 3.4% of the set, diluted roughly thirtyfold in any pooled average. That is most likely why we let the axis go the first time we looked at it.
One caveat that belongs next to the chart rather than in a footnote. The served path decodes at 55–215 BPM by default and only widens when the caller supplies a tempo. Hand it a track with no catalogue BPM and the fast band is still 8.7, not 50.0. The 41 points are available; they are not automatic.
The counterweight is the more honest finding. We tried to repair the tails with data, oversampling the starved bands four times over. It moved the pooled score by 0.06 points.
Exposure was never the constraint. 190 training tracks is too few to learn a tempo regime from however often you show them, and the corpus does not contain more.
08 — The check
Then we pointed the instrument at ourselves
This programme runs on pre-registered gates. Every experiment carries its threshold, written down before it runs. That discipline exists because of one earlier result. We scored 23 variants and the best gained +0.80 — until we accounted for having taken 23 shots at the target, at which point the odds of seeing that by chance alone came out at 0.586. Better than a coin flip. The best result of the search sat below the median of its own noise.
The gates caught us again, harder. Our headline gain had been confirmed on a 646-track holdout at +1.38. Then we checked what that holdout was made of.
85% of it was the base model's own training data. Split by contamination, the same result reads +1.57 on corpora the backbone had memorised and +0.36 on clean music.
So we wrote it down, demoted our own flagship number, and adopted the rule: a gain must appear on clean data to count.
Then we ran the audit in the other direction, checking whether our training set had absorbed benchmark recordings. Two methods sharing no statistic, each with a time-reversed decoy control. 23 tracks confirmed leaked. Re-scoring without them — not retraining — the fine-tune's margin went from +1.85 to +1.89.
The gain got slightly larger with the leak taken out. That's the number we'd want to see from somebody selling us a model, so it's the one we publish.
09 — The shape
Knowing when it's wrong beats being right more often
Running three models and averaging them buys about 1.5 points. Running three models and asking whether they agree buys considerably more.
Set aside the 30% of tracks the models disagree most about, and accuracy on everything you keep goes from 73.6 to 87.3. The three-model average is worth 1.5 points. The verdict is worth 13.7.
For a pipeline generating something on top of the grid, that ratio is the interesting one. Knowing which songs to send to a human beats being slightly better on all of them.
This is measured and not yet wired into the product. Numbers when it ships, same rules as everything above.
10 — What ships
20 million parameters, one forward pass, no GPU
Cue Beat v1 is a Beat This! backbone (MIT-licensed, from Foscarin et al., ISMIR 2024), fine-tuned on our corpus. The fine-tunes were then averaged into one set of weights, so serving a track costs a single pass through the model rather than running several and voting.
Audio goes in at 22,050 Hz mono and becomes a spectrogram at 50 slices per second. The model scores every slice for how much it looks like a beat, and how much like a bar line. A decoder then reads those scores end to end and picks the one grid that best explains the whole song.
It runs on CPU: 4.4 seconds of compute per minute of audio as deployed, 97% of it the forward pass.
It's served as its own async endpoint, POST /v1/beats, for two reasons. Its cost driver is
audio minutes rather than API calls. And it's the only component in the estate that needs torch, which
would otherwise land on every other endpoint's cold start.
- audio
- log-mel · 50 fps
- Cue Beat v1 · one pass
- whole-track DBN
- beats · downbeats · tempo
+1.8
points of downbeat CMLt over the free MIT backbone
75 → 30%
of full-length tracks carrying a bar-grid discontinuity, before and after
$0.008
per audio-minute, one forward pass, CPU only, live in us-east-2
against the tracker we shipped before, the first number reads +21.7. that comparison flatters us, so it isn't the one in large type.
11 — What breaks
The rows we don't hide
The limits, in full
- Tempo extremes. Under 55 and over 215 BPM, accuracy falls off a cliff. The chart above is the honest map, and the cause is corpus content rather than model capacity. Adding exposure didn't move it.
- The anime-repertoire result is a training-composition claim, not an accuracy claim. On 99 held-out tracks it reads 77.0 against the stock backbone's 61.0, but only +0.36 points against our own generalist. The corpus matters; the weight-merge on top of it does not. And n=99 can't resolve anything under ~3 points, so neither figure proves a margin.
- We have never measured our own run-to-run variance. The backbone authors' three published runs span 1.1 points, so we treat anything under ~1.5 from a retrain as unresolved rather than settled. Several of our own closures sit in that band. Our seed repeat is queued, not done.
- The model doesn't run the video editor yet. The editor still ships madmom, because the request-path image deliberately carries no torch and there's no silent fallback to degrade to. Cue Beat v1 serves the beat-map API. That's the true state of it.
- Three times now we've found a real per-track signal and no way to route on it. Model agreement, tempo steadiness, structural confidence. Each is worth 1 to 2 points if you could already tell which tracks to apply it to, and nothing we built can tell. Declining a track works, as above; picking a better treatment for it does not. At three for three that's a statement about the task, not our methods.
12 — The arithmetic
None of this is hard to start
beat_track is one line and it will look fine in a demo.
What costs is the rest. We could not learn the bar phase was wrong on 42% of songs until we built a benchmark that measured bar phase. Our accuracy came from 30-second excerpts; the product ran on three-minute songs. Our holdout had been memorised by our own backbone. A tempo ceiling we never questioned was worth 41 points.
Each of those is a few weeks, and a benchmark you have to build before it can tell you anything.