Skip to content

feat(genre): measured classifier + mix-doctor widening for the missing families (PR-G7) - #216

Merged
slittycode merged 1 commit into
mainfrom
accuracy/genre-classifier-widening
Jul 13, 2026
Merged

feat(genre): measured classifier + mix-doctor widening for the missing families (PR-G7)#216
slittycode merged 1 commit into
mainfrom
accuracy/genre-classifier-widening

Conversation

@slittycode

Copy link
Copy Markdown
Owner

What

PR-G7, the final piece of the genre-generalization program: the classifier and mix-doctor learn the missing electronic families, with every measured number sourced from real reference audio (93 GiantSteps clips run through the full Phase 1 pipeline — method, caveats, and provenance in audits/genre-target-sourcing-2026-07-13.md, committed here).

Changes

  1. Nine new _GENRE_SIGNATURES — measured: gabber, hardstyle, electro, downtempo (GiantSteps hardcore n=17, hard-dance n=11, electro-house n=15, chill-out n=15); knowledge-based and flagged in-line: trap, footwork, two-step, speed-garage, halftime-dnb (2015 Beatport has no reference audio for these; same provenance as the original table). two-step's low sidechain window (0.1–0.35) is the audit's uk-garage fix.
  2. Three measured retunesbreaks, dubstep, psytrance: all three controls' old windows NEVER fired on real audio (real breaks read acid-techno 8/15; measured dubstep bass decay is 0.11–0.40 s vs the assumed 0.6–1.2 s wobble; measured psy centroid 860–1910 vs the 2200–5500 window).
  3. Octave-aware bpm axis in analyze_genre_detail: when PR-G3's bpmOctaveEvidence contests the shipped bpm, each signature's bpm window scores against both hypotheses (alternate discounted 10%). Forced by measurement: every hardcore clip ships a halved bpm (84–128 for true 156–190) — a gabber signature can never fire on the shipped value alone. Never touches bpm itself (invariant feat: value-first backport — genre profiles, MixDoctor, broken-pipe fixes #1).
  4. Family plumbing on all four cross-boundary sites (tripwire Preserve signal monitor playback during analysis and harden run flow #3): _GENRE_FAMILY_MAP gains garage (fixing the audit's unmapped uk-garage/bassline/garage) plus hardcore, trap, electro, downtempo; the TS genreFamily union + validFamilies allowlist mirror it; JSON_SCHEMA.md now pins the closed set.
  5. Four measured mix-doctor profiles (electro, downtempo, hardstyle, gabber) with p25/p75/p50 band targets and family fallbacks in mapLegacyToEnhanced. Knowledge-based genres get no profiles — targets are not invented; trap falls back to its hiphop lineage.

Measured validation — real-clip classifier replay (old table → new)

Beatport label Old top read New top read
breaks (15) acid-techno 8 breaks 7
chill-out (15) hiphop 5 / acid 4 downtempo 12
dubstep (10) hiphop 4 / trance 4 dubstep 4
electro-house (15) acid-techno 8 electro 8
hard-dance (11) hiphop 3 hardstyle 6 (+gabber 1)
hardcore (17) hiphop 8 gabber 10
psy-trance (10) acid 5 / hiphop 4 psytrance 4

Correct-family top-1: ~0/93 → 51/93. Honest limits: LOFI previews under-read the top octave (bright-side windows widened, flagged for re-sourcing), and measured pumpingStrength runs 0.15–0.42 everywhere vs the 0.35–0.75 many ORIGINAL entries assume — full-table recalibration is a named follow-up, not smuggled into this PR.

Validation

  1. Backend: full unittest discover — 1366 tests, OK (3 skipped; exit codes captured directly) (6 new classifier tests incl. gabber-fires-via-octave-evidence and no-op-when-evidence-supports-shipped).
  2. Synthetic eval: 114/0 active on this branch base (pre-G6 38-clip corpus — G7 touches no eval surface; CI validates the merged ref against the 40-clip main) (genre isn't gated there; regression assurance).
  3. Golden: passes without re-baseline.
  4. CI-mirror fundamentals gate: 15/15, allPassed.
  5. UI npm run verify: 51 smoke passed.
Full measured percentiles (93 clips)
93 rows, 0 errors

=== breaks (n=15)
  bpm              p10=  125.10 p25=  128.40 p50=  130.00 p75=  137.05 p90=  140.00 n=15
  subBass          p10=  -14.16 p25=  -11.10 p50=  -10.10 p75=   -8.35 p90=   -7.56 n=15
  crestFactor      p10=    9.86 p25=   10.80 p50=   11.70 p75=   12.95 p90=   14.16 n=15
  onsetRate        p10=    4.27 p25=    5.03 p50=    5.49 p75=    6.02 p90=    6.49 n=15
  spectralCentroid p10= 1303.92 p25= 1411.75 p50= 1572.30 p75= 2069.60 p90= 2226.04 n=15
  pumpingStrength  p10=    0.22 p25=    0.27 p50=    0.29 p75=    0.32 p90=    0.34 n=15
  bassDecayMs      p10=   82.40 p25=  110.50 p50=  206.00 p75=  262.50 p90=  470.40 n=15
  rt60             p10=    1.92 p25=    2.17 p50=    2.59 p75=    2.97 p90=    3.00 n=14
  kickThd          p10=    0.38 p25=    0.45 p50=    0.47 p75=    0.65 p90=    0.82 n=15
  lufsIntegrated   p10=  -11.70 p25=  -10.80 p50=   -9.70 p75=   -8.50 p90=   -7.54 n=15
  plr              p10=    9.06 p25=   10.25 p50=   10.70 p75=   11.60 p90=   12.74 n=15
  lowBass          p10=  -14.14 p25=  -13.40 p50=  -11.50 p75=  -11.05 p90=  -10.14 n=15
  lowMids          p10=  -22.56 p25=  -21.45 p50=  -19.50 p75=  -17.20 p90=  -15.94 n=15
  mids             p10=  -19.84 p25=  -18.75 p50=  -17.60 p75=  -16.30 p90=  -13.32 n=15
  upperMids        p10=  -24.96 p25=  -23.15 p50=  -21.30 p75=  -18.85 p90=  -17.54 n=15
  highs            p10=  -26.88 p25=  -24.80 p50=  -21.90 p75=  -20.35 p90=  -19.56 n=15
  brilliance       p10=  -35.46 p25=  -32.05 p50=  -27.10 p75=  -25.20 p90=  -23.24 n=15
  classifier reads today: [('acid-techno', 8), ('trance', 3), ('rock', 1), ('progressive-house', 1)]

=== chill-out (n=15)
  bpm              p10=   83.34 p25=   92.45 p50=   99.80 p75=  117.20 p90=  126.10 n=15
  subBass          p10=  -20.20 p25=  -17.85 p50=  -12.80 p75=   -9.75 p90=   -7.76 n=15
  crestFactor      p10=   11.00 p25=   12.50 p50=   14.60 p75=   15.65 p90=   15.96 n=15
  onsetRate        p10=    2.79 p25=    3.40 p50=    4.39 p75=    5.05 p90=    5.60 n=15
  spectralCentroid p10=  615.28 p25=  752.80 p50=  885.00 p75= 1366.70 p90= 1589.62 n=15
  pumpingStrength  p10=    0.27 p25=    0.29 p50=    0.31 p75=    0.34 p90=    0.37 n=15
  bassDecayMs      p10=   81.60 p25=  110.00 p50=  194.00 p75=  332.50 p90=  398.80 n=15
  rt60             p10=    1.64 p25=    2.29 p50=    2.63 p75=    2.95 p90=    3.00 n=14
  kickThd          p10=    0.50 p25=    0.54 p50=    0.65 p75=    0.84 p90=    0.87 n=15
  lufsIntegrated   p10=  -14.76 p25=  -13.10 p50=  -12.00 p75=  -11.25 p90=   -9.84 n=15
  plr              p10=   11.14 p25=   11.85 p50=   12.30 p75=   12.90 p90=   14.30 n=15
  lowBass          p10=  -20.00 p25=  -17.15 p50=  -16.30 p75=  -13.35 p90=  -10.32 n=15
  lowMids          p10=  -24.06 p25=  -22.05 p50=  -20.20 p75=  -17.45 p90=  -13.64 n=15
  mids             p10=  -21.48 p25=  -20.70 p50=  -19.50 p75=  -18.75 p90=  -15.22 n=15
  upperMids        p10=  -32.20 p25=  -30.70 p50=  -28.70 p75=  -25.40 p90=  -23.52 n=15
  highs            p10=  -36.34 p25=  -35.50 p50=  -34.00 p75=  -29.20 p90=  -26.06 n=15
  brilliance       p10=  -46.44 p25=  -42.85 p50=  -38.60 p75=  -32.65 p90=  -29.56 n=15
  classifier reads today: [('hiphop', 5), ('acid-techno', 4), ('rock', 3), ('organic-house', 1)]

=== dubstep (n=10)
  bpm              p10=   69.77 p25=   69.93 p50=  124.95 p75=  139.97 p90=  140.00 n=10
  subBass          p10=   -9.91 p25=   -9.05 p50=   -7.50 p75=   -6.47 p90=   -4.57 n=10
  crestFactor      p10=    8.07 p25=    8.93 p50=   10.50 p75=   11.10 p90=   11.45 n=10
  onsetRate        p10=    3.37 p25=    4.40 p50=    4.84 p75=    5.24 p90=    5.35 n=10
  spectralCentroid p10=  912.39 p25= 1151.65 p50= 1350.30 p75= 2286.70 p90= 2552.87 n=10
  pumpingStrength  p10=    0.26 p25=    0.29 p50=    0.31 p75=    0.35 p90=    0.35 n=10
  bassDecayMs      p10=  107.90 p25=  191.25 p50=  262.50 p75=  281.50 p90=  401.40 n=10
  rt60             p10=    2.23 p25=    2.32 p50=    3.00 p75=    3.00 p90=    3.00 n=9
  kickThd          p10=    0.35 p25=    0.38 p50=    0.53 p75=    0.60 p90=    0.64 n=10
  lufsIntegrated   p10=  -10.63 p25=   -9.43 p50=   -8.55 p75=   -7.92 p90=   -5.25 n=10
  plr              p10=    6.79 p25=    9.72 p50=    9.80 p75=   10.07 p90=   11.17 n=10
  lowBass          p10=  -14.21 p25=  -13.25 p50=  -10.80 p75=  -10.07 p90=   -8.89 n=10
  lowMids          p10=  -22.79 p25=  -20.60 p50=  -19.45 p75=  -18.07 p90=  -17.59 n=10
  mids             p10=  -21.63 p25=  -17.62 p50=  -15.90 p75=  -14.80 p90=  -12.51 n=10
  upperMids        p10=  -25.05 p25=  -23.27 p50=  -20.65 p75=  -17.62 p90=  -14.80 n=10
  highs            p10=  -26.74 p25=  -24.68 p50=  -22.40 p75=  -20.50 p90=  -19.52 n=10
  brilliance       p10=  -33.90 p25=  -31.18 p50=  -27.90 p75=  -24.40 p90=  -22.79 n=10
  classifier reads today: [('hiphop', 4), ('trance', 4), ('acid-techno', 1), ('psytrance', 1)]

=== electro-house (n=15)
  bpm              p10=  124.88 p25=  126.95 p50=  128.10 p75=  128.35 p90=  129.52 n=15
  subBass          p10=   -9.28 p25=   -8.60 p50=   -7.90 p75=   -7.20 p90=   -6.70 n=15
  crestFactor      p10=    8.96 p25=    9.35 p50=   10.00 p75=   10.55 p90=   10.90 n=15
  onsetRate        p10=    2.91 p25=    3.25 p50=    3.81 p75=    4.42 p90=    5.09 n=15
  spectralCentroid p10= 1295.18 p25= 1399.55 p50= 1741.90 p75= 1868.65 p90= 2008.90 n=15
  pumpingStrength  p10=    0.22 p25=    0.24 p50=    0.27 p75=    0.32 p90=    0.33 n=15
  bassDecayMs      p10=  109.80 p25=  135.50 p50=  175.00 p75=  213.50 p90=  231.00 n=15
  rt60             p10=    1.64 p25=    1.86 p50=    2.38 p75=    2.63 p90=    2.73 n=10
  kickThd          p10=    0.47 p25=    0.56 p50=    0.62 p75=    0.68 p90=    0.74 n=15
  lufsIntegrated   p10=   -9.84 p25=   -8.80 p50=   -7.30 p75=   -6.70 p90=   -5.28 n=15
  plr              p10=    7.34 p25=    7.95 p50=    9.00 p75=   10.00 p90=   10.42 n=15
  lowBass          p10=  -14.06 p25=  -11.70 p50=  -11.00 p75=   -9.25 p90=   -7.92 n=15
  lowMids          p10=  -19.62 p25=  -18.70 p50=  -16.90 p75=  -16.40 p90=  -15.60 n=15
  mids             p10=  -16.32 p25=  -15.45 p50=  -15.00 p75=  -13.30 p90=  -11.88 n=15
  upperMids        p10=  -21.04 p25=  -20.10 p50=  -18.90 p75=  -17.20 p90=  -16.22 n=15
  highs            p10=  -25.10 p25=  -23.50 p50=  -21.00 p75=  -19.60 p90=  -18.88 n=15
  brilliance       p10=  -30.84 p25=  -28.35 p50=  -26.00 p75=  -25.25 p90=  -24.54 n=15
  classifier reads today: [('acid-techno', 8), ('progressive-house', 3), ('hiphop', 1), ('industrial-techno', 1)]

=== hard-dance (n=11)
  bpm              p10=   74.90 p25=   91.90 p50=  144.50 p75=  148.00 p90=  148.00 n=11
  subBass          p10=  -10.90 p25=  -10.20 p50=   -9.40 p75=   -7.30 p90=   -6.40 n=11
  crestFactor      p10=    8.60 p25=    9.75 p50=   11.10 p75=   11.70 p90=   11.90 n=11
  onsetRate        p10=    2.52 p25=    3.20 p50=    3.67 p75=    4.46 p90=    4.85 n=11
  spectralCentroid p10= 1660.00 p25= 1898.45 p50= 2250.90 p75= 2394.40 p90= 2603.10 n=11
  pumpingStrength  p10=    0.18 p25=    0.23 p50=    0.27 p75=    0.31 p90=    0.33 n=11
  bassDecayMs      p10=  121.00 p25=  155.00 p50=  198.00 p75=  282.00 p90=  298.00 n=11
  rt60             p10=    1.76 p25=    1.84 p50=    2.27 p75=    2.75 p90=    2.90 n=5
  kickThd          p10=    0.56 p25=    0.58 p50=    0.69 p75=    0.73 p90=    0.76 n=11
  lufsIntegrated   p10=   -9.20 p25=   -8.90 p50=   -8.10 p75=   -6.50 p90=   -5.60 n=11
  plr              p10=    6.80 p25=    8.10 p50=    9.50 p75=    9.70 p90=   10.20 n=11
  lowBass          p10=  -14.10 p25=  -13.40 p50=  -12.50 p75=  -11.60 p90=  -11.10 n=11
  lowMids          p10=  -20.50 p25=  -18.60 p50=  -18.00 p75=  -16.10 p90=  -14.00 n=11
  mids             p10=  -16.50 p25=  -16.05 p50=  -14.50 p75=  -12.75 p90=  -10.60 n=11
  upperMids        p10=  -19.20 p25=  -19.05 p50=  -18.30 p75=  -16.80 p90=  -14.40 n=11
  highs            p10=  -22.60 p25=  -21.75 p50=  -20.60 p75=  -19.05 p90=  -18.00 n=11
  brilliance       p10=  -29.00 p25=  -28.00 p50=  -25.20 p75=  -24.60 p90=  -21.90 n=11
  classifier reads today: [('hiphop', 3), ('techno', 2), ('acid-techno', 2), ('pop', 1)]

=== hardcore-hard-techno (n=17)
  bpm              p10=   84.54 p25=   85.10 p50=   92.40 p75=  104.00 p90=  120.94 n=17
  subBass          p10=  -11.38 p25=   -9.00 p50=   -8.30 p75=   -7.30 p90=   -5.82 n=17
  crestFactor      p10=    7.72 p25=    8.30 p50=    9.20 p75=    9.90 p90=   11.76 n=17
  onsetRate        p10=    2.94 p25=    3.27 p50=    4.03 p75=    4.39 p90=    5.03 n=17
  spectralCentroid p10= 1907.02 p25= 2096.10 p50= 2408.10 p75= 2490.10 p90= 2874.44 n=17
  pumpingStrength  p10=    0.15 p25=    0.20 p50=    0.24 p75=    0.30 p90=    0.33 n=17
  bassDecayMs      p10=   85.00 p25=  111.00 p50=  189.00 p75=  227.00 p90=  354.60 n=17
  rt60             p10=    1.12 p25=    1.32 p50=    1.76 p75=    1.79 p90=    2.52 n=5
  kickThd          p10=    0.52 p25=    0.55 p50=    0.68 p75=    0.70 p90=    0.74 n=17
  lufsIntegrated   p10=   -8.26 p25=   -6.70 p50=   -6.10 p75=   -5.00 p90=   -4.42 n=17
  plr              p10=    6.14 p25=    6.60 p50=    7.20 p75=    8.50 p90=    9.56 n=17
  lowBass          p10=  -12.32 p25=  -11.50 p50=   -9.00 p75=   -7.80 p90=   -6.62 n=17
  lowMids          p10=  -20.66 p25=  -17.80 p50=  -16.00 p75=  -14.40 p90=  -12.66 n=17
  mids             p10=  -16.40 p25=  -14.80 p50=  -13.70 p75=  -11.80 p90=  -10.48 n=17
  upperMids        p10=  -19.10 p25=  -17.20 p50=  -16.70 p75=  -15.20 p90=  -13.96 n=17
  highs            p10=  -20.80 p25=  -20.10 p50=  -16.90 p75=  -16.50 p90=  -15.00 n=17
  brilliance       p10=  -27.64 p25=  -25.60 p50=  -23.40 p75=  -20.60 p90=  -20.32 n=17
  classifier reads today: [('hiphop', 8), ('acid-techno', 4), ('rock', 2), ('techno', 1)]

=== psy-trance (n=10)
  bpm              p10=   73.18 p25=   73.80 p50=  115.30 p75=  136.05 p90=  137.63 n=10
  subBass          p10=  -11.41 p25=  -10.70 p50=   -8.90 p75=   -7.25 p90=   -6.76 n=10
  crestFactor      p10=    9.85 p25=   10.33 p50=   11.45 p75=   12.85 p90=   13.41 n=10
  onsetRate        p10=    4.07 p25=    4.20 p50=    4.77 p75=    6.18 p90=    6.86 n=10
  spectralCentroid p10=  860.96 p25= 1391.08 p50= 1442.30 p75= 1719.92 p90= 1911.64 n=10
  pumpingStrength  p10=    0.28 p25=    0.30 p50=    0.31 p75=    0.34 p90=    0.35 n=10
  bassDecayMs      p10=   61.80 p25=   92.00 p50=  116.50 p75=  153.00 p90=  190.80 n=10
  rt60             p10=    1.90 p25=    2.60 p50=    2.83 p75=    3.00 p90=    3.00 n=6
  kickThd          p10=    0.38 p25=    0.44 p50=    0.59 p75=    0.70 p90=    0.78 n=10
  lufsIntegrated   p10=  -11.32 p25=  -10.60 p50=   -9.05 p75=   -8.25 p90=   -7.78 n=10
  plr              p10=    8.89 p25=    9.57 p50=   10.25 p75=   11.73 p90=   12.87 n=10
  lowBass          p10=  -14.13 p25=  -13.82 p50=  -12.25 p75=  -10.97 p90=  -10.47 n=10
  lowMids          p10=  -22.36 p25=  -22.05 p50=  -21.50 p75=  -18.75 p90=  -17.49 n=10
  mids             p10=  -21.19 p25=  -18.70 p50=  -17.00 p75=  -15.60 p90=  -15.01 n=10
  upperMids        p10=  -26.07 p25=  -24.20 p50=  -22.50 p75=  -20.82 p90=  -18.61 n=10
  highs            p10=  -27.97 p25=  -25.73 p50=  -22.85 p75=  -22.25 p90=  -20.48 n=10
  brilliance       p10=  -31.35 p25=  -29.88 p50=  -28.55 p75=  -26.52 p90=  -26.40 n=10
  classifier reads today: [('acid-techno', 5), ('hiphop', 4), ('trance', 1)]

🤖 Generated with Claude Code

…g families (accuracy PR-G7)

Nine new signatures — measured from 93 GiantSteps reference clips
(gabber, hardstyle, electro, downtempo) and knowledge-based flagged
in-line (trap, footwork, two-step, speed-garage, halftime-dnb) — plus
measured retunes of the three controls whose old windows never fired
on real audio (breaks, dubstep, psytrance). The classifier's bpm axis
becomes octave-aware via PR-G3's bpmOctaveEvidence (every measured
hardcore clip ships a halved bpm; the alternate hypothesis is
discounted 10% and never touches bpm itself). Family plumbing lands on
all four cross-boundary sites: _GENRE_FAMILY_MAP (+garage/hardcore/
trap/electro/downtempo, fixing the unmapped garage ids), the TS
genreFamily union + validFamilies, JSON_SCHEMA.md's now-closed set,
and mapLegacyToEnhanced fallbacks. Four measured mix-doctor profiles;
knowledge-based genres get none (targets are not invented).

Real-clip replay: correct-family top-1 went from ~0/93 to 51/93.
Provenance, method, and caveats (LOFI bright-side skew, preview
length, rt60 saturation, table-wide pumping mismatch follow-up):
audits/genre-target-sourcing-2026-07-13.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@slittycode
slittycode merged commit 0ed792f into main Jul 13, 2026
5 checks passed
@slittycode
slittycode deleted the accuracy/genre-classifier-widening branch July 13, 2026 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant