ProduceHits · Research · 2026-10-18

Song Structure & Hierarchical Harmony

Can section detection plus the SANCT bar grid make our key and chord output better? What to build, what to buy, what to avoid — for SongTranscribe, BPMandKey and friends.

Standalone report · no product code was changed

Legend — how every number and claim is labelled

  • MEASURED a number published by someone else on a named dataset with a named metric (we re-read the paper/README on 2026-10-18). It is their measurement, not ours, and does not transfer 1:1 to our uploads.
  • ESTIMATE our own projection or judgement. No experiment behind it yet. Never read it as a measurement.
  • verified a licence, feature or fact read on the primary page/repo today  ·  unverified from memory, secondary, or not fetchable.
  • Untagged numbers inside a table that has a “Reported” or “Reported accuracy” column are MEASURED by the cited source. A number without a source and without a tag should be treated as ESTIMATE.

00Summary

The hierarchy idea is well supported by how published chord and key systems work (transition-penalised decoding, whole-piece context for local key) but is not yet proven on our data (ESTIMATE); most of it can be built on CPU from pieces we already run. The biggest wins are not a higher whole-song key score. They are cleaner chord charts (bar-level decoding, no flicker), real section boundaries instead of four equal slices, and per-section keys and modulation flags that we can trust.

~0.70MEASURED strict boundary hit-rate F (±0.5 s, HR.5F .703) on SongFormBench-Harmonix — SongFormer (HX), their paper/README
~0.78MEASURED HR3F (±3 s) .784, same benchmark and model
~0.81MEASURED frame-level label ACC .807 on SongFormBench-Harmonix (7 label classes; a different SongFormer training variant, HX+E+H+G)
84%MEASURED ChordFormer MajMinor WCSR 84.09, Sevenths 72.28 — 1,217-song Isophonics+Billboard+MARL set, 5-fold CV

Recommendations

  1. Start with CPU-only wins (phases 0–2): a benchmark harness, a bar-level chord Viterbi on the chroma we already compute, and self-similarity sections snapped to SANCT bar lines. No new licences, no GPU.
  2. Treat deep section models as a second opinion, behind a licence gate (phase 3). allin1 is MIT code; SongFormer is stronger on paper but depends on MuQ, whose published weights are CC-BY-NC. That is a commercial-use blocker until cleared.
  3. SANCT stays sacred. Everything here reads beat_times/downbeat_times and never rewrites them. Section edges are snapped to the grid, not the other way round.
  4. Hierarchy is not “shorter windows”. The plan adds priors and pooling over bar-level states; it does not shrink the analysis window, which would make chroma noisier. See 4b.
  5. Measure first. The repo has no key or downbeat ground-truth benchmark today (section 1). Phase 0 fixes that; without it every gain below is an estimate.

How to read the numbers

Accuracy figures are from papers that report them on specific datasets. They do not transfer 1:1 to our users’ uploads (stems from Demucs, loop-based beats, mixed genres). Treat them as ceilings, not promises. All projected gains (roadmap, compute adders, “expected” anything) are ESTIMATE. Anything I could not fetch today is tagged unverified and listed at the bottom. A claim-by-claim ledger with the sources re-checked is in Claim ledger.

01How our key detection works today

Read from the repo (read-only). Code lives in afcut_engine/harmonic.py; webapp/app.py:_detect_key is now a thin wrapper that delegates to it. verified in repo

StageWhat it doesWhere
InputFull mix (the pack’s mixed audio). No stems are used for key. Mono downmix, resampled to 22.05 kHz, capped at the first 120 s.harmonic.py ANALYSIS_SR, MAX_ANALYSIS_SECONDS; app.py:7543, :28930
Harmonic isolationHPSS (STFT n_fft 1024, kernel 17, margin 1/3) keeps the harmonic part, so drums do not smear the chroma._harmonic_component
ChromaCQT chroma on the harmonic part. Frames are RMS-weighted and gated at 5% of the 95th-percentile energy, then averaged to one 12-bin vector._harmonic_chroma, _weighted_chroma
ProfilesKrumhansl-Kessler major/minor only. No Temperley, edma/edmm or learned profiles.KRUMHANSL_MAJOR / MINOR
ScoringRank (Spearman-style) correlation against all 24 rotated profiles. Rank transform makes it robust to the overall loudness/shape of the chroma vector._rank_keys
ConfidenceMargin between best and second-best, margin / 0.125, deliberately no floor. Returns the top 3 alternatives. Code comments say it was tuned on a small calibration set and that a wrong answer still reached 0.39 — i.e. confidence is a hint, not a probability._calibrate_confidence, _alternatives
Cross-checksCENS chroma on an 11 kHz / 45 s excerpt gives an key_agreement flag; a triad-pair “rival tonality” test (threshold 0.16) flags relative/neighbour confusions; a guard returns “indeterminate” for silence/DC/degenerate scores.detect_key_advanced, _rival_tonality_gain, _degenerate_key_reason
Per-section keyNot structural. detect_per_section_keys splits the audio into 4 equal-length slices and runs the same scorer on each.harmonic.py:734
Chordschord_timeline: for each beat window (from the SANCT grid, read-only) take triad-template cosine argmax over 12 roots × a few qualities. Merge identical neighbours, cap at 200. No HMM, no transition cost, no bar awareness, no 7ths. Confidence from template margin.harmonic.py:1099
Where it runs_harmonic_layer on the worker cache-miss path only (never on the API origin). Measured ~13.6 s per ~4 min song, ~0.9–1.1 GB peak on the cx33 worker box.app.py:~32335; docs/reports/2026-10-09-song-intelligence-strategy.md
Section prototypeOffline-only tools/song_intel_demo.py: per-bar energy (RMS + onset density + brightness), novelty peaks with a 4-bar minimum, labels from energy rank (Intro/Verse/Build/Drop…). Not wired into the product.tools/song_intel_demo.py

Why it is accurate (and where that is a claim, not a measurement)

  • It reads harmonic content only (HPSS), uses CQT chroma and a rank-based comparison — all robust choices that avoid the classic failure of full-mix chroma polluted by drums.
  • It reports alternatives and a margin, so relative-key confusion (e.g. “D# minor, could also be F# major” in the 2026-10-09 demo) is surfaced instead of hidden.
  • It is an honest baseline, not state of the art: one profile family and a single global vector. Literature suggests profile choice alone matters by genre (section 4).

Data we have to benchmark it

Essentially none. No tests/ directory, no ground-truth key file, no evidence folder with labelled keys. The code comments mention two published-key demo tracks used for calibration (one still came out wrong: a C♯ minor piece detected as D minor, per scout notes unverified: not re-checked). mir_eval==0.8.2 is already pinned in requirements.txt, so scoring tools are free. The founder’s “very accurate” is a plausible but unmeasured claim — phase 0 of the roadmap turns it into a number.

Also noted: the Track 12 plan (docs/plans/2026-09-14-track12-bpmandkey-harmonic-analysis.md) still lists chord_timeline as to-be-built and cites _detect_key at app.py:4772; both are stale (it now lives at app.py:5741, and chords exist). Not edited here.

02Section / structure segmentation

Libraries and models

SystemWhatReported accuracyLicenceNotes
allin1 (All-In-One)Joint beats, downbeats, section boundaries and labels (intro/verse/chorus/bridge/outro…). Takes demixed stems. WASPAA 2023.MEASURED Harmonix, 8-fold CV (their paper): beat F1 .958, downbeat F1 .915, boundary HR.5F .660, label pairwise-F .738
(on SongFormBench-Harmonix, measured by the SongFormer authors: HR.5F .596, HR3F .730, ACC .740)
Code MIT verified (GitHub licence API). Weights licence not stated in the README unverified. Needs NATTEN and madmom (from git).Speed per README: 33 min of audio in 73 s on RTX 4090 + 14-core CPU. Trained on Harmonix only (pop/electronic skew).
SongFormer (Oct 2025)Fuses MuQ + MusicFM representations; trained on 14k+ songs (SongFormDB) with mixed label schemas. arXiv 2510.02797.MEASURED SongFormBench-Harmonix (200 Harmonix + 100 Chinese-pop songs for the full bench): HR.5F .703, HR3F .784 (HX-trained variant); ACC .807 (HX+E+H+G variant) — best figures across the paper’s variants, not one model.
RWC-Pop (HX+E+H+G variant): HR.5F .650, HR3F .800, ACC .812
Code CC-BY-4.0 (README “License” section) verified. The README tells users to fetch MuQ-related weights; MuQ’s README states its published weights (MuQ-large-msd-iter, MuQ-MuLan-large) are CC-BY-NC 4.0 verified. We did not establish which exact checkpoint SongFormer loads or its own weights licence, so the NC conflict is likely, not confirmed commercial blocker until clearedREADME: 2–4 s per song on an L40 GPU (excl. model load). Beats Gemini 2.5 Pro on strict boundaries (HR.5F .423) but Gemini is slightly better at ±3 s (.813).
MSAFClassical framework: many boundary/label algorithms (novelty, spectral clustering, etc.).Older algorithms; no 2024–26 numbers fetched unverifiedMITUseful as a reference/ablation, not as the main engine.
librosaRecurrence matrix, self-similarity, agglomerative clustering (librosa.segment). We already ship it.Boundary quality depends on features; no benchmark of our ownISC unverifiedCheap CPU baseline. Our building block for SSM-on-bar-grid.
MusicFM / MuQ / MERTSelf-supervised music encoders; the strongest structure models fine-tune on top of them (SongFormer, and the “MusicFM-Zhang” and “MuQiter” baselines in its table).MusicFM-Zhang: ACC .725, HR.5F .640; MuQiter ACC .772 (cited in SongFormer, Harmonix subset)MuQ code MIT, weights CC-BY-NC 4.0; MusicFM: repo LICENSE file says dual MIT / Apache-2.0 (GitHub shows NOASSERTION) verified; weights licence not checked unverifiedEncoders are heavy; need a GPU in practice.
LinkSegRecent supervised structure model (baseline in SongFormer paper).ACC .780, HR.5F .630, HR3F .762 (Harmonix subset)unverifiedNot evaluated by us.

Realistic accuracy and the honest ceiling

What the numbers mean

  • On the best public benchmark, a strict ±0.5 s boundary F-measure tops out near 0.70; relaxed ±3 s is near 0.78–0.80. An F of ~0.70 means a substantial share of strict boundaries are still missed or spurious even for the 2025 state of the art (F mixes precision and recall, so “one in three” is only a rough reading). MEASURED SongFormBench-Harmonix, HR.5F/HR3F.
  • Frame-level label accuracy ~0.80 MEASURED (ACC, SongFormBench-Harmonix) is with a seven-class label set. It drops as labels get finer.
  • Snapping predicted boundaries to the nearest bar line helps strict F, because annotators mark bar starts (estimate — to be proven in phase 0).

By genre — what we can and cannot say

  • The benchmarks are Harmonix (mostly pop/rock/electronic, unverified composition), RWC-Pop (J-pop) and 100 Chinese pop songs. No fetched number covers hip-hop, loop-based electronic, jazz or classical.
  • Our own 2026-10-09 prototype note: sections were “believable” on a beat-driven track and wrong (“Verse”) on orchestral music.
  • estimate Loop-based music (hip-hop, house) has structure carried by layers entering and leaving, not by harmony or melody changing. Chroma self-similarity is weak there; energy/stem-activity features matter more. Expect lower label accuracy and boundaries that are real but ambiguous (drop vs. build).
  • estimate Pop/rock with verse-chorus form and vocals is the best case.

The human ceiling is also below 1.0: annotators disagree on where sections start and what to call them (see risks). I could not fetch a sourced inter-annotator figure today unverified.

Commercial and competitor approaches

ProductWhat they doEvidence
rekordbox“Phrase analysis” marks track phrases; auto hot-cue/memory-cue placement uses it and is skipped when phrases cannot be analysed or the track is too short.verified rekordbox 7 FAQ
Moises“Chord Finder”: chords synced to playback, Easy/Medium/Advanced voicings, capo mode, editable, exportable chart. No accuracy figure published on the page.verified moises.ai
Spotify audio analysisSpotify’s 2024-11-27 notice lists Audio Analysis among endpoints removed for new apps (registered on/after that date) and for development-mode apps without a pending extension request; apps that already had access are unaffected. Not an option for us.verified Spotify blog
Mixed In Key, Serato, Ableton, Logic, Cubase, Chordify, Songsterr, Cyanite, Musiio, AudioShake, LANDR, BeatportNot fetched. Our own earlier note (2026-10-09) describes MIK/rekordbox/Splice features “based on established product knowledge”. Chordify’s site returned 403 to automated fetch.unverified see unverified list

Take-away: phrase/section bands on the waveform are now table stakes in DJ software, but nobody publishes accuracy. Our differentiator is honest confidence + bar-exact edges on our own grid.

03Chord recognition & harmonic rhythm

SystemApproachReported accuracyLicenceNotes
Chordino / NNLS-Chroma (Mauch)NNLS-chroma + HMM/Viterbi over a chord dictionary; Vamp plugin.No fresh number fetched unverifiedGPL-2.0 (repo) verifiedClassic, interpretable, CPU. GPL means keep it a separate process or skip it.
madmom chords (deep chroma + CRF)CNN chroma + CRF decoding.unverifiedCode BSD-style; model files CC BY-NC-SA 4.0 verified LICENSENon-commercial weights ⇒ off-limits for the paid product.
BTC (Park et al., ISMIR 2019)Bi-directional Transformer; maj/min or large vocabulary.MEASURED as a baseline in the ChordFormer table: “BTC+CNN” MajMinor 49.00 (the paper’s own re-run on its 1,217-song split; not BTC’s own published result). Training sets listed from memory unverifiedCode MIT verified repo; weights/training audio status unverifiedOld but usable; librosa-based features.
ChordFormer (Feb 2025)Conformer on CQT, structured chord representation, re-weighted loss, CRF decoding to cut spurious transitions.MEASURED 1,217-song Isophonics+Billboard+MARL set, 5-fold CV, WCSR: Root 84.7, MajMin 84.1, Sevenths 72.3, MIREX 83.6 (CNN+BLSTM baseline 83.4 / 82.6 / 69.8 / 81.5)Weights/code release unverifiedGains over the CNN+BLSTM baseline in the same table are +1.3 (root), +1.5 (MajMin), +2.5 (7ths) points MEASURED. our reading progress is incremental.
Chord Recognition with Deep Learning (Dec 2025)Thesis revisiting methods.Findings: poor on rare chords; pitch augmentation helps; generative-model features do notn/aConfirms the plateau.
Essentia chord detection, autochord, CREMATemplate / deep options.unverifiedEssentia is AGPL-3.0 verifiedAGPL is a network-copyleft risk for a hosted service.

How to stop beat-by-beat flicker

  • Decode on bars, not beats. Aggregate beat-synchronous chroma into per-bar vectors using the SANCT downbeats, then run Viterbi over bars. A bar is the natural unit of harmony in most pop/electronic music.
  • Hierarchical resolution choice. Per bar, allow three hypotheses — one chord, two half-bars, or four beats — and charge a penalty for each extra change. The finer split only wins when the evidence margin is large.
  • Phrase-aware prior. Changes are cheaper at bar 1 of a 4/8-bar phrase than mid-phrase; repeated phrases should decode to the same chords (use the section SSM to tie them).
  • Transition and self-loop costs (the HMM/CRF trick used by Chordino/madmom/ChordFormer). ChordFormer’s paper explicitly credits CRF decoding with reducing excessive transitions.

Harmonic-rhythm priors — what is and is not sourced

“Most pop is one chord per bar or per two bars” matches practice and our own demo (about 115 chords for a ~4-minute song, which is too dense), but I did not fetch a corpus study (e.g. McGill Billboard statistics, de Clercq & Temperley) unverified. Plan: measure chords-per-bar on the Billboard annotations in phase 0 and set the penalty from data, per genre bucket.

Annotation ambiguity caps all scores: even expert annotators disagree on chord labels, which ChordFormer cites as a cause of overlapping class boundaries. A sourced agreement percentage was not retrieved unverified, so the often-quoted “80–85% ceiling” is not used here.

04Local / segmental key detection

TopicWhat we knowTag
Key CNN (Korzeniowski & Widmer)Genre-agnostic “AllConv” model, MIREX weighted score w = r_c + 0.5 r_fifth + 0.3 r_relative + 0.2 r_parallel. GiantSteps (electronic, Beatport previews): w 74.6 (correct 67.9, fifth 7.0, relative 8.1, parallel 4.1, other 12.9). Billboard: 85.1 (correct 79.9). Classical: 96.6. arXiv 1808.05340.verified
Genre sensitivityAn earlier paper by the same authors finds systems tuned on pop perform subpar on electronic music, and that errors concentrate on relative and parallel keys. arXiv 1706.02921.verified
Profile familiesEssentia’s KeyExtractor exposes diatonic, krumhansl, temperley, weichai, tonictriad, temperley2005, thpcp, shaath, gomez, noland, faraldo, pentatonic, edmm, edma, bgate, braw; default bgate. Profile names such as edma/edmm suggest electronic-music-specific profiles; the docs page itself gives no accuracy comparison, and the claim that KK fits electronic worse rests on the Key-CNN authors’ cross-genre finding below, not on Essentia our inference. Essentia docs.verified (names); accuracy by profile unverified
Local key / modulationThe Key-CNN paper itself notes that local-key performance on short excerpts depends on the harmonic coherence of the whole piece (1808.05340 abstract) — i.e. local windows need global context. Dedicated modulation-detection papers were not found in my search unverified. Truck-driver modulations (final chorus +1 or +2 semitones) are well known in pop unverified frequency.mixed
Stem-aware chromaNo source fetched. Reasoning: bass stem gives a strong root estimate; “other”/harmonic stems remove drums and vocal melody-only passages. HPSS already approximates the drum removal. A test is in the ablation list.estimate
TuningOur CQT chroma path uses librosa defaults; whether tuning is estimated per track was not confirmed in code unverified. Cheap to add: estimate tuning offset and re-centre before chroma.unverified
MIREX audio key resultsmusic-ir.org wiki pages were not reachable from this environment (connection failed). The key-CNN paper cites MIREX 2017 results.unverified

What section structure adds to key (the core idea)

  1. Pool across repeats. If chorus 1, 2 and 3 are the same section, sum their (energy-weighted) bar chroma before scoring. Noise from vocals/fills averages out; this is a bigger effective sample for the same key.
  2. Per-section key from real sections, not four equal slices. A verse in the relative minor no longer drags a quarter-slice vote.
  3. Modulation by transposed repetition. If the last chorus matches earlier choruses after rotating its chroma by k semitones (k=1,2) with high similarity, that is strong evidence of a key change, much stronger than a lone key-vote flip.
  4. Bidirectional reconciliation. Whole-song key is the prior for each section (high self-transition in a 24-state key HMM over bars); a section overrides it only after ≥8 bars of consistent evidence.

4b · Hierarchical inference is not the same as shorter windows

These are two different ways to get “finer” harmonic output, and they pull in opposite directions. The report proposes the first and rejects the second.

Hierarchical harmonic inference (what we propose)

  • Keep the evidence window at a musical unit (a bar, from the SANCT grid) and decode a sequence of bar-level states with Viterbi.
  • Priors flow down the hierarchy: song key → section key → phrase position → bar. A change is cheap on bar 1 of a phrase and dear mid-phrase; diatonic chords are cheaper than chromatic ones; a harmonic-rhythm prior defaults to one chord per bar.
  • Evidence is pooled across repeats: choruses 1–3 share chroma/posteriors, so noise averages out as the effective sample grows.
  • A finer split (half-bar, beat) is accepted only when its likelihood gain beats a penalty. Resolution is earned, not assumed.

Just shrinking the window (what we avoid)

  • Cutting the analysis window (say from a bar to a beat, or a 4-slice key vote to 16 slices) gives each estimate less audio, so chroma is noisier, passing tones and vocal melody dominate, and the argmax flips.
  • With no transition cost or prior, each window is decided independently ⇒ flicker (this is exactly today’s chord_timeline: beat windows, argmax, no HMM, ~115 chords in a ~4-minute song).
  • For key, shorter slices make the vote less reliable, not more local: the Key-CNN authors note local-key classification of short segments has to consider the harmonic coherence of the whole piece.
ClaimEvidenceLabel
Per-frame/window argmax over-produces chord changes; adding transition-penalised decoding fixes itChordFormer (arXiv 2502.11840): taking the top class per frame “often results in excessive transitions between adjacent chords, as it lacks a mechanism to impose penalties for immediate changes”; they add a linear-chain CRF for “more coherent chord transitions”. Chordino/NNLS also decodes with an HMM/Viterbi. We did not extract an isolated CRF-on/off score.MEASURED (mechanism stated by authors) / no isolated number unverified
Local key needs whole-piece contextKorzeniowski & Widmer (arXiv 1808.05340), abstract: one must “consider the harmonic coherence of the whole piece when classifying the local key of short segments of audio”.verified (statement), not a head-to-head
Shorter windows = noisier chromaSignal-processing reasoning: fewer frames per estimate means higher variance, and a beat holds fewer harmonic cycles than a bar. No window-length sweep was fetched or run.ESTIMATE (reasoned, not measured)
Pooling repeated sections improves key/chord posteriorsStandard averaging argument; no paper fetched that measures it for key. Depends on repeat clustering being right.ESTIMATE
Harmonic-rhythm prior (about one chord per bar in pop/electronic)Plausible and consistent with our own dense demo, but no corpus statistic was fetched.unverified → ESTIMATE
Bar-level Viterbi beats beat-level argmax on our audioNot measured. Falsifying test, to run in phase 0/1 (ablation 7): same chroma, same beat grid; compare (a) beat argmax, (b) shorter windows (half-beat), (c) bar Viterbi with priors. Report MajMin WCSR and chord changes per bar. The hierarchy claim fails if (c) does not beat (a) on flicker at equal or better WCSR.ESTIMATE — hypothesis with a stated test

One caution cuts the other way: hierarchical priors can over-smooth real fast changes (jazz, passing chords) and wrong section clusters can tie unrelated bars together. That is why the sketch lets half-bar/beat hypotheses win on strong evidence and why low-confidence songs fall back to beat-level output.

05Beat / downbeat tracking as the grid

TrackerReportedLicenceNotes
SANCT beat_engine (ours)No benchmark in repo. Downbeats come from a beat-phase vote over bars of 4 beats.OursSacred. librosa-based (HPSS tempo probes); no madmom/Beat This! dependency seen in beat_engine.py. Exposes beat_times and downbeat_times.
Beat This! (ISMIR 2024)MEASURED GTZAN test-only set (models trained with 8-fold CV on other data): beat F1 89.1, downbeat F1 78.3 without DBN (77.4 with DBN, but better downbeat continuity: CMLt 73.3 vs 67.3). ~20 M params; the paper’s smaller model scores 88.8 / 77.2. Their ablation table on a validation split reports higher numbers (92.6 / 85.4) — do not mix the two.MIT code and weights verified; note training data partly copyrightedAuthors admit failures on underrepresented genres and non-periodic beats; weaker continuity metrics. arXiv 2407.21658.
allin1 joint modelHarmonix: beat F1 .958, downbeat F1 .915 (different data from the row above — not comparable)MIT codeJoint training helps all four tasks (ablation in paper).
madmom DBNOur internal notes quote ~0.83–0.88 beat accuracy unverified sourceCode BSD-style; models CC BY-NC-SA 4.0 verifiedPyPI release only supports Python<3.10 and numpy<1.20, per Beat This! README verified; install from git.
Beat Transformer, SpecTNT-TCN, BEASTMEASURED Beat Transformer: “up to 4% point improvement in downbeat tracking accuracy over the TCN architectures” (abstract; separate finding: demixed input beats non-demixed); BEAST: online, <50 ms latency, beat F1 80.04, downbeat F1 46.78Abstracts only checked unverified beyond thatResearch baselines; 2209.07140, 2312.17156.

Why downbeats matter so much here

Everything in the hierarchy — sections on bar lines, bar-level chords, 4-bar phrases — assumes the bar phase is right. If the downbeat is one beat off, every bar chroma straddles two real bars and chords smear. Public downbeat F-measures (MEASURED ~0.78 on GTZAN for Beat This!, ~0.92 on Harmonix for allin1; different datasets) say a meaningful fraction of songs will have an off-phase or wrong-meter grid. Phase 0 must measure SANCT downbeat accuracy against annotated data (read-only), and the pipeline should expose a bar-phase confidence so low-confidence songs fall back to beat-level or whole-song output.

SANCT rule for this project

New code consumes the SANCT grid; it never re-derives, snaps or reorders it. Other trackers (Beat This!, allin1) may run as diagnostics to flag grids that look wrong; they must not feed back into cut points. Section/chord boundaries are expressed as indices into the SANCT bar list, so they cannot drift from the grid by construction.

06Proposed architecture for ProduceHits

Hierarchy: song → sections → phrases (4/8 bars) → bars → half-bars → beats. Each level constrains the one below it with a prior and passes a confidence up.

Uploadmix + Demucs stems SANCT beat grid (read-only)beats, downbeats, bar list Beat-sync chroma + timbreHPSS/CQT, bass-stem chroma, tuning Bar tensorper-bar chroma(12) + MFCC + energy Section segmentation (CPU)bar-level SSM + novelty, min 4 barscluster repeats (agglomerative)edges = bar indices (never off-grid)optional: SSM with key-rotation k Deep second opinion (Modal T4)allin1 and/or SongFormerlabels + boundary voteslicence gate before prod Fusion + don't-over-segment rulessnap to bars, merge < 4 barsboundary kept if 2 of 3 votes or high noveltylabel = deep label if agree, else A/B/Csection confidence 0-1 Key reconciliationwhole-song key (today's HPSS+KK, + edma/Temperley ensemble)pooled chroma per repeated-section cluster24-state key HMM over bars, high self-loop, global-key priormodulation = transposed-repeat match or ≥8 bars of evidenceoutput: global key, per-section keys, modulations, confidences Bar-level chord Viterbistates: 24 maj/min + N (7ths later), per barresolution per bar: 1 chord | 2 half-bars | 4 beatscost = -loglik + change penalty + phrase-position priorrepeated phrases tied via section clusterskey-aware transition bias (diatonic chords cheaper) Output (versioned JSON, additive)sections[]: bar_start, bar_end, label, cluster_id, conf · keys: global + per_section[] + modulations[] · chords[]: bar, resolution, symbol, confflags: bar_phase_conf, low_conf_fallback ("whole-song only") · UI fades low-confidence items; CSV export keeps allRuns on auto-scaled Hetzner workers (CPU) and Modal T4 (optional deep step). Never on the API origin.

Green = sacred input, blue = new CPU code, orange dashed = optional GPU step.

Bar-level chord decoding (sketch)

for each bar b:   x_b      = mean(beat chroma in bar b)          # 12-d, RMS weighted
                  x_b,h    = [mean(first half), mean(second half)]
                  x_b,beat = beat chroma (4)
score(chord c, span s)     = cosine(x_span, template_c)           # triads now, 7ths later
cost(bar b, hypothesis h)  =  - sum_span score  +  lambda_change * (#changes in bar)
                             + lambda_phrase * [change not on phrase bar 1 or bar 3]
Viterbi over bars with transition cost  T(c_prev, c) = 0 if same, mu if diatonic to key, mu + nu otherwise
choose finer split (2 or 4) only if cost drops by more than a margin  =>  default is 1 chord per bar
tie repeated phrases: bars in the same section-cluster share chord posteriors (soft sum)

Parameters (lambda_change, lambda_phrase, mu, nu) are fitted by grid search on Billboard/Isophonics-style annotations, per genre bucket. design proposal

“Don’t over-segment” rules

  • Minimum section length 4 bars; boundaries only on SANCT bar lines.
  • Cap sections to roughly one per ~8 bars on average; merge neighbours whose bar-SSM similarity exceeds a threshold.
  • Keep a boundary only if supported by novelty above a threshold or by two independent voters (SSM, allin1, SongFormer).
  • Chords: minimum duration of one beat, default one per bar; show chords faded by confidence (already the product guidance from 2026-10-09).
  • Low-confidence songs (odd meter, no stable bar phase, very short) return whole-song key + beat-level chords only, labelled as such.
  • Don’t force Verse/Chorus words. If the label model and the SSM disagree, show neutral labels (A, B, C… or Low/Rising/High energy for beatless material).

6a · Recommendation table

LibraryTaskAccuracy (reported)LicenceSpeedVerdict
librosa (ours)chroma, SSM, clusteringn/a (feature tool)ISC unv.CPU, secondsUSE backbone of phases 1–2
mir_eval (pinned)scoring: segment, chord, key, beatn/aMIT unv.trivialUSE benchmark harness
allin1sections + labels + downbeatsHR.5F .60–.66, ACC .74 (Harmonix)MIT code; weights unstated~27 s of audio/s on 4090; ~9–12 s/song L40 (SongFormer README)PILOT on Modal T4 after weights-licence check
SongFormersections + labelsHR.5F .70, HR3F .78, ACC .81Code CC-BY-4.0; MuQ weights CC-BY-NC2–4 s/song on L40 (README)GATE evaluate offline; no prod until licence cleared
MSAFclassical segmentationolder, unmeasured hereMITCPUREFERENCE ablation baseline only
Beat This!beats/downbeatsbeat F1 89.1, downbeat F1 78.3MIT code+weights~20 M params; CPU speed unv.DIAGNOSTIC cross-check of SANCT bar phase only
madmombeats, chords, keyvariousmodels CC BY-NC-SACPUAVOID in prod (NC models; install friction)
Chordino / NNLSchordsunverifiedGPL-2.0CPUAVOID linking; could be an offline reference only
Essentiakey profiles, chordsunverifiedAGPL-3.0CPUAVOID as a dependency; borrow the idea of edma/edmm/bgate profiles (re-derive from papers)
BTCchords (maj/min, large vocab)baseline in ChordFormer tableMIT code; weights unv.small modelPILOT as a learned alternative to templates
ChordFormerchords (large vocab)MajMin 84.1, 7ths 72.3release unv.unv.WATCH check for released weights
Key CNN (Korzeniowski)global keyGiantSteps w 74.6; Billboard 85.1unv.small CNNWATCH use paper as the benchmark to beat
Spotify audio analysissectionsn/aclosed to new appsn/aNO

6b · Ablations and benchmark plan

Ablations

  1. Key: full-mix HPSS (today) vs harmonic stem vs bass+other stems vs no HPSS.
  2. Key: KK vs Temperley vs edma/edmm-style profiles vs an ensemble vote.
  3. Key: flat global vs pooled-by-repeat-cluster vs bar-level key HMM.
  4. Key: with and without per-track tuning estimation.
  5. Sections: equal slices (today) vs energy novelty (demo) vs bar-SSM vs allin1 vs SongFormer vs 2-of-3 fusion.
  6. Sections: effect of snapping to SANCT bars on HR.5F.
  7. Chords: beat argmax (today) vs bar Viterbi vs bar+half-bar+beat hypotheses vs + phrase prior vs + key prior.
  8. Bar phase: SANCT downbeats vs Beat This! downbeats vs allin1 downbeats (agreement and chord accuracy impact).

Datasets and metrics

  • Keys: GiantSteps Key (Beatport previews, electronic) and Billboard-type sets as used in the key-CNN paper; metric mir_eval.key.weighted_score plus the raw correct/fifth/relative/parallel split.
  • Chords: Isophonics/Beatles, McGill Billboard, RWC-Pop; mir_eval.chord root, majmin, sevenths WCSR; plus our own chords-per-bar and flicker rate.
  • Sections: Harmonix Set / SongFormBench (200 Harmonix + 100 Chinese songs), SALAMI, RWC-Pop; mir_eval.segment detection P/R/F at 0.5 s and 3 s, pairwise F, V-measure.
  • Beats: Harmonix beats/downbeats; mir_eval.beat F, CMLt, AMLt, downbeat F.
  • Internal set (new): 100–150 tracks from the founder’s own catalog and licensed/public-domain audio, hand-labelled for key, modulations and sections, balanced across pop/rock, hip-hop, house/techno, orchestral/other.

Most public sets distribute annotations only; audio must be sourced separately. Keep any benchmark audio private and out of the repo and out of demos.

6c · Compute and licence notes

  • Where it runs: everything is worker-side. Phases 1–2 are CPU on the auto-scaled Hetzner workers, adding an estimated <1–2 s per song on top of the measured ~13.6 s / ~1 GB baseline (estimate: SSM on ~100–200 bars and a 24-state Viterbi are tiny). The optional deep step is GPU-only on Modal T4. The API origin never touches audio.
  • Demucs reuse: allin1 runs Demucs internally. We already produce stems for paid users, so a pilot should check whether stems can be passed in to avoid a second separation unverified. Free-tier songs have no stems; the CPU path must work from the mix.
  • Pinned versions: requirements.txt has torch 2.6.0 while modal_gpu.py pins torch 2.4.1; SongFormer’s requirements pin torch 2.4.0. allin1 needs NATTEN builds matched to torch/CUDA. Budget integration time for a dedicated Modal image.
  • Licence flags: (1) MuQ weights CC-BY-NC → SongFormer commercial use unresolved. (2) madmom models CC BY-NC-SA. (3) Essentia AGPL-3.0 and NNLS-Chroma GPL-2.0 are copyleft. (4) Weights of allin1/BTC/ChordFormer are not stated in what I fetched. (5) Beat This! is MIT but notes some training data is copyrighted or under limited CC licences. None of this is legal advice; get a one-hour review before any model ships.
  • Credits / storage laws: new analysis is part of the existing bpmandkey_analyze job; results go into the existing analysis JSONB on processed_songs (additive fields). No new job type is needed (Track 12 plan). Credit pricing for any extra GPU step must go through cost-guard measurement first.

6d · Phased roadmap

PhaseDeliverableEffortExpected gain ESTIMATE (not measured)Gate
0 · Measuremir_eval harness; baseline for current key, chord flicker, SANCT downbeat vs Harmonix; internal labelled set3–5 days est.A real accuracy number for key (replaces “very accurate”); bar-phase reliabilityDatasets sourced
1 · Bar-level chordsViterbi with 1/2/4-resolution, phrase prior, key prior; behind a flag, same JSON shape plus bar1 weekLarge drop in chord changes per bar (target ≤1.2 on pop); MajMin gain of a few points likely est.Phase 0 metrics
2 · CPU sections + pooled keyBar-SSM sections snapped to bars, repeat clusters, pooled per-section key, key HMM, modulation flag1–2 weeksPer-section keys meaningful; whole-song key +1–3 pts on mixed material est., unproven; detect final-chorus modulationsPhase 0 + 1
3 · Deep second opinionallin1 and SongFormer offline eval on Modal T4; fusion rules; licence decision1–2 weeksBoundary F at 0.5 s from ~0.5–0.6 (CPU, est.) toward 0.65–0.70; real labelsLicence cleared
4 · Better chordsLearned model (BTC / ChordFormer if weights are usable) vs templates; 7ths; bass-stem root prior2–3 weeksSevenths and inversions; at most low single-digit WCSR over a tuned template Viterbi est.Phase 1 baseline
5 · Product surfaceSection bands, per-section key chips, modulation badge, confidence fading, CSV with bars1 weekTrust & usabilityux-polish gate

07Honest risks

Label ambiguity

Functional labels (verse/pre-chorus/chorus/bridge) are subjective and schema-dependent. SongFormer’s whole premise is training with “schema-mismatched labels”. Expect disagreement even among experts; ship neutral labels when models disagree.

Electronic and loop-based music

Sections are defined by layers and energy, not by harmony. Chroma-SSM finds a loop repeated for 64 bars and calls it one section. Key profiles tuned on pop fit electronic worse (key-CNN papers). A single-chord or drone track makes chord Viterbi and key pooling nearly meaningless.

Tempo changes and time signatures

SANCT assumes stable bar groups of 4 beats. 3/4, 6/8, 5/4, meter changes and rubato break the bar tensor. Beat This! authors themselves note failures on non-periodic pieces. Detect and fall back.

Lyrics-driven structure

Verses often share a melody and chords but differ in lyrics; choruses can be defined by hook text. Audio-only models partially capture this. Gemini-style lyric-aware models score higher at ±3 s but worse strict boundaries (SongFormer table).

Over-segmentation and false modulations

Every extra boundary or key flip that a user sees and finds wrong costs more trust than a missed one. Hence the 4-bar floor, the 8-bar evidence rule and the whole-song fallback.

Benchmark and licence risk

No existing key ground truth; models trained on Harmonix may overfit pop/EDM; some weights are non-commercial. Estimated gains in this report are not measurements until phase 0 runs.

—Claim ledger (decision-driving claims, re-checked 2026-10-18)

Each source was re-opened (paper PDF/abstract, repo README or LICENSE, product page) and the number or licence compared with the claim. “Fixed” = the report text was corrected or softened in this validation pass.

Claim in reportLabelSource checkStatus
SongFormer HR.5F .703, HR3F .784, ACC .807 on SongFormBench-HarmonixMEASUREDSongFormer README table (also arXiv 2510.02797): HX variant .703/.784; ACC .807 belongs to the HX+E+H+G variantConfirmed; variant caveat added
allin1 Harmonix 8-fold: beat F1 .958, downbeat .915, HR.5F .660, label PWF .738MEASUREDarXiv 2307.16425 Table 1 (All-In-One 300K: .958 / .915 / .660 / .738)Confirmed
allin1 on SongFormBench-Harmonix: HR.5F .596, HR3F .730, ACC .740MEASURED (by SongFormer authors)SongFormer READMEConfirmed
allin1 speed 33 min audio in 73 s on RTX 4090MEASURED (README)allin1 READMEConfirmed
SongFormer 2–4 s/song on L40; allin1 9–12 sMEASURED (SongFormer authors, README)README speed table (excl. model load)Confirmed; GPU is L40, not our Modal T4 unverified on T4
ChordFormer MajMin 84.09, Sevenths 72.28, Root 84.69, MIREX 83.62; baseline CNN+BLSTM 82.62/69.78MEASUREDarXiv 2502.11840 Table II; dataset 1,217 songs (Isophonics, Billboard, MARL), 5-fold CV, WCSRConfirmed; dataset/CV wording added. Earlier note that the baseline row was “83.4/82.6/69.8/81.5” matches
Beat This! beat F1 89.1, downbeat F1 78.3 (77.4 with DBN)MEASUREDarXiv 2407.21658 Table 2 (GTZAN test set)Fixed: dataset was mislabelled as “broad 8-fold set”; removed unverified “78 MB”
Key-CNN GiantSteps w 74.6 / Billboard 85.1 / Classical 96.6MEASUREDarXiv 1808.05340 results tableConfirmed
Local key needs whole-piece harmonic coherenceverified1808.05340 abstractConfirmed; now cited in 4b
Pop-tuned key systems underperform on electronic; errors are relative/parallelverifiedarXiv 1706.02921 abstractConfirmed
MuQ weights CC-BY-NC 4.0, code MITverifiedMuQ README “License”Confirmed. Gap: SongFormer’s exact checkpoint not traced, so “commercial blocker” softened to “likely”
madmom models CC BY-NC-SA 4.0; code BSDverifiedmadmom LICENSE fileConfirmed
NNLS-Chroma GPL-2.0; Essentia AGPL-3.0verifiedCOPYING files in each repoConfirmed. The “AVOID” verdicts are our legal-risk judgement, not legal advice
allin1 / BTC / Beat This! / MSAF code MITverifiedGitHub licence API / LICENSE / Beat This! README (MIT code and weights; notes some training data copyrighted)Confirmed
Spotify Audio Analysis closed to new appsverifiedSpotify 2024-11-27 blogReworded to match the post exactly
rekordbox auto cues use Phrase analysis; skipped if phrases cannot be analysed / track too shortverifiedrekordbox 7 FAQConfirmed
Moises Chord Finder, no published accuracy numberverifiedmoises.ai page: only “most users find… quite accurate”Confirmed
Our pipeline: ~13.6 s and ~0.9–1.1 GB per songMEASURED (internal)docs/reports/2026-10-09-song-intelligence-strategy.md table (13.6 s; 888 MB / 1,065 MB peak)Confirmed
Phase 1–4 expected gains; +<1–2 s CPU; CPU boundary F 0.5–0.6; whole-song key +1–3 pts; chords/bar ≤1.2ESTIMATENo source. Projections only; the phase-0 harness exists to test themLabelled
Bar snapping raises strict boundary FESTIMATENo sourceLabelled
Hierarchical decoding beats shorter windows (4b)ESTIMATE with partial supportMechanism stated by ChordFormer and Key-CNN authors; no head-to-headStated as hypothesis + falsifying test

Not checked: MIREX results, weights licences for allin1/SongFormer/BTC/ChordFormer, any competitor beyond the three listed (see Unverified list).

—Sources

All fetched on 2026-10-18 unless noted.

  1. Kim & Nam, All-In-One Metrical and Functional Structure Analysis (WASPAA 2023): arxiv.org/abs/2307.16425; code github.com/mir-aidj/all-in-one (MIT).
  2. SongFormer: arxiv.org/abs/2510.02797; code github.com/ASLP-lab/SongFormer (CC-BY-4.0 code).
  3. MuQ: github.com/tencent-ailab/MuQ (code MIT, weights CC-BY-NC 4.0). MusicFM: github.com/minzwon/musicfm.
  4. MSAF: github.com/urinieto/msaf (MIT).
  5. Beat This!: arxiv.org/abs/2407.21658; github.com/CPJKU/beat_this (MIT).
  6. Beat Transformer 2209.07140; SpecTNT 2205.14701; BEAST 2312.17156 (abstract-level only).
  7. madmom: github.com/CPJKU/madmom, LICENSE (code BSD-style; models CC BY-NC-SA 4.0).
  8. ChordFormer: arxiv.org/abs/2502.11840. Chord Recognition with Deep Learning: arxiv.org/abs/2512.22621. BTC: arxiv.org/abs/1907.02698, code (MIT).
  9. NNLS-Chroma/Chordino: github.com/c4dm/nnls-chroma (GPL-2.0).
  10. Essentia: github.com/MTG/essentia (AGPL-3.0); KeyExtractor.
  11. Korzeniowski & Widmer, Genre-Agnostic Key Classification with CNNs: arxiv.org/abs/1808.05340; End-to-End Musical Key Estimation: arxiv.org/abs/1706.02921.
  12. Spotify Web API changes, 2024-11-27: developer.spotify.com.
  13. rekordbox 7 FAQ (phrase analysis): rekordbox.com. Moises Chord Finder: moises.ai.
  14. Repo (internal): afcut_engine/harmonic.py, webapp/app.py (_detect_key, _harmonic_layer), webapp/beat_engine.py (read-only), tools/song_intel_demo.py, docs/plans/2026-09-14-track12-bpmandkey-harmonic-analysis.md, docs/reports/2026-10-09-song-intelligence-strategy.md, requirements.txt, modal_gpu.py.

—Unverified list

  • MIREX structure, chord and key results (music-ir.org not reachable from the research environment).
  • Weights licences for allin1, SongFormer, BTC, ChordFormer; whether allin1 loads madmom model files at runtime.
  • Accuracy of Chordino, madmom chords, Essentia, autochord, CREMA; any 2024–26 chord or key model other than ChordFormer and the 2025 thesis.
  • Commercial tools beyond rekordbox, Moises and Spotify: Mixed In Key, Serato, Ableton, Logic, Cubase, Chordify, Songsterr, Cyanite, Musiio, AudioShake, LANDR, Beatport.
  • Inter-annotator agreement for sections and chords; harmonic-rhythm statistics by genre; frequency of pop modulations; any dedicated modulation-detection literature.
  • Harmonix Set genre composition; librosa, mir_eval, Demucs licences (from memory); Beat This! CPU speed; allin1 stems pass-through; T4 vs L40 speed for SongFormer.
  • Whether our CQT path estimates tuning; accuracy of SANCT downbeats; the two calibration tracks’ details.
  • All “expected gain” figures in the roadmap are estimates, not measurements.