fix(align): calibrated fit (precision, lift, beat-shift check, baseline) and aligner guards (A7, A8)
Fit flags on precision (<0.6) and chance-corrected lift (<0.25), null with <8 recording onsets; old match rate kept as audibleRate (info). Symbolic-chroma beat/bar-shift check per window. Constant-offset baseline (-2..+2 s) replaces DTW without manual anchors unless DTW precision is better by >=0.02. Stretch warning counts in the fit summary. DTW: slope-limited steps, open begin/end options; per-bar outlier rejection (1/4 beat, Theil-Sen-transported +-3 bar median); no anchor in the final partial bar. bench real: saved/computed source, baseline + method, corrupt alignment.json skipped. Parabolic onset interpolation; warp extrapolation documented; spec amended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3b002059e9
commit
3db87c0317
19 files changed
+1016
-252
No files matched your search
@@ -55,3 +55,16 @@ test("pickOnsets enforces 50 ms min gap and ignores flat input", () => {
|
||||
expect(pickOnsets(o, 100)).toEqual([0.22, 0.6]);
|
||||
expect(pickOnsets(new Float32Array(100), 100)).toEqual([]);
|
||||
});
|
||||
|
||||
test("pickOnsets refines peaks to sub-frame times by parabolic interpolation", () => {
|
||||
const o = new Float32Array(100);
|
||||
o[30] = 4; o[31] = 8; o[32] = 6; // peak leans right: δ = ½(4 − 6)/(4 − 16 + 6) = 1/6 frame
|
||||
const got = pickOnsets(o, 50);
|
||||
expect(got).toHaveLength(1);
|
||||
expect(got[0]!).toBeCloseTo((31 + 1 / 6) / 50, 9);
|
||||
// min-gap competition still compares the peak heights, not the interpolated times
|
||||
const p = new Float32Array(100);
|
||||
p[40] = 5; p[41] = 3; p[42] = 7; p[43] = 1;
|
||||
expect(pickOnsets(p, 100)).toHaveLength(1);
|
||||
expect(pickOnsets(p, 100)[0]!).toBeCloseTo((42 + 0.5 * (3 - 1) / (3 - 14 + 1)) / 100, 9);
|
||||
});
|
||||
Reference in new issue
Block a user