feat(foundry): the loop finder (engine/loops.py) — §1 pipeline, per-stem (#5)
Generates ranked loop candidates from a separated stem, the phase-2 design made
real (PHASE2_FINDINGS §1/§3/§4): drift-tolerant PLP beat grid → beat-sync SSM
(MFCC⊕chroma → recurrence affinity) → Foote checkerboard novelty → candidate
windows at {1,2,4,8} bars → §3 composite score → NMS dedup. Works PER STEM (§0),
then loosely groups candidates across stems by shared time window into Takes the
human auditions together. export_take honours the B-rulebook (B1 ZC-snap, B6 bass
mono-sum, B8 24-bit/44.1k, B10 no-normalize) and calls publish.link_kit.
DRY with the katana: the loopability score reuses engine.grade's seam_score /
zc_score on each candidate slice, and adds the two terms only the finder has the
SSM context for — structural (does the window recur off its own diagonal?) and
boundary novelty (clean segment edges). Weights w_struct .4 / w_novel .2 / w_seam
.3 / w_zc .1, minus a tempo-instability penalty (§3).
Caught while validating on the real Loituma stems: PLP latched onto the eighth-
note pulse and reported ~250 bpm (Loituma is ~125), so 2-bar windows came out
half-length — the §7 octave hazard, live. Fixed by pinning PLP's tempo range to
one musical octave (70–160) and enforcing a min inter-beat spacing in peak-pick.
Now reads ~120 bpm and 2-bar windows land at ~3.9s, squarely in the A-profile
band (3.7–8.0s). find_takes on the 4-stem catch correctly clusters time-aligned
candidates (e.g. vocals+drums sharing a 2-bar window).
CLI: python3 -m engine.loops <stem.wav> [--bars 2 4 8] [--top N] [--json].
7 new tests (checkerboard signs, Foote peak at a block seam, structural recurrence,
NMS dedup, ZC-snap, and the tempo-octave guard). Full foundry suite: 41 pass.
Showing
tools/foundry/engine/loops.py
0 → 100644
This diff is collapsed.
Click to expand it.
tools/foundry/tests/test_loops.py
0 → 100644
Please
register
or
sign in
to comment