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
@@ -93,7 +93,7 @@ aligned MIDI.
|
||||
starting from the raw MIDI; a "reset to raw MIDI" action exists.
|
||||
- **Fit quality:** median absolute onset residual (ms) between matched recording
|
||||
onsets and warped MIDI onsets, overall and per 30 s window; shown on the page
|
||||
and in benchmark output.
|
||||
and in benchmark output. (Amended 2026-10-30: see "Fit quality — Amended" below.)
|
||||
- **Playback of the warped MIDI:** the server re-renders the warped MIDI audio
|
||||
when anchors change (alphaTab renders a 4-minute song in ~1–2 s); the page
|
||||
requests it on Play. Waveforms are sent as precomputed peaks, not full audio.
|
||||
@@ -118,6 +118,49 @@ aligned MIDI.
|
||||
match rate = share of warped MIDI onsets with a recording onset within ±70 ms,
|
||||
overall and per 30 s window. A window is flagged "don't trust" when its match
|
||||
rate < 0.5 or median residual > 60 ms; the page highlights flagged windows.
|
||||
*(Superseded by the amendment below.)*
|
||||
- **Fit quality — Amended 2026-10-30 after real-song evidence (rulings A7, A8).**
|
||||
On real full mixes the onset picker finds ~1.4 attacks/s while a scored MIDI
|
||||
has ~13 unique onsets/s, so the match rate above caps near 40 % even when
|
||||
perfectly aligned (every window was flagged on every song), and onset metrics
|
||||
cannot see whole-beat shifts (they alias onto the grid).
|
||||
- **Flag metric = precision:** share of recording onsets (onset flux, k = 4,
|
||||
parabolic sub-frame peak times) with a warped scored-role MIDI onset within
|
||||
±70 ms; per 30 s window by recording time. A window with < 8 recording
|
||||
onsets is null and never flagged; otherwise flagged when precision < 0.6.
|
||||
- **Chance-corrected lift:** precision minus the mean precision with the
|
||||
warped MIDI shifted by +0.11, +0.23 and +0.37 s (off-grid); reported per
|
||||
window and overall; a window is also flagged when lift < 0.25.
|
||||
- **Beat/bar-shift check:** per window, mean chroma cosine between the
|
||||
recording (features chroma, 10 Hz) and a symbolic MIDI chroma (piano roll of
|
||||
the warped pitched scored-role notes, no render) at the current alignment
|
||||
vs the MIDI moved by ±1, ±2 beats and ±1 bar along the MIDI's own
|
||||
tempo/time-signature grid. Flagged "beat shift suspected: ±k beat(s)/bar"
|
||||
when a shift beats the current alignment by > 0.05 (the margin keeps
|
||||
repetitive harmony, where shifts tie, from flagging). "+1 beat" means the
|
||||
MIDI content belongs one beat later in the recording.
|
||||
- **Information only:** the old match rate, renamed "MIDI onsets audible as
|
||||
attacks" (JSON `audibleRate`), and the median residual (recording onsets →
|
||||
nearest warped MIDI onset).
|
||||
- **Stretch warnings:** the fit summary (CLI, page, real report) includes the
|
||||
number of warned stretches (> 5 % tempo change) and of stretches with
|
||||
|tempo change| > 15 %.
|
||||
- **Constant-offset baseline:** grid search −2..+2 s in 10 ms steps for the
|
||||
offset maximising overall precision; precision peaks within 0.1 of the best
|
||||
are told apart by the symbolic chroma cosine (beat aliasing), and within a
|
||||
peak the offset with the smallest mean residual is taken. Reported with its
|
||||
precision. Without manual anchors, `autoAlign` returns the baseline as one
|
||||
auto anchor (`chosen: "baseline"`) unless the DTW alignment's precision
|
||||
beats it by ≥ 0.02 (`chosen: "dtw"`); with manual anchors there is never a
|
||||
substitution.
|
||||
- **Aligner guards:** both DTW passes use slope-limited steps (Sakoe–Chiba
|
||||
P = 1: (1,1), (1,2), (2,1)), so the path cannot jump; the first segment may
|
||||
start late in the recording (open begin) and the final segment uses an open
|
||||
end (the path may stop before the recording ends, or before the MIDI ends,
|
||||
each unconsumed MIDI frame costing 1), so a length mismatch is not absorbed
|
||||
as a tempo ramp. Per-bar offsets more than ¼ beat from the median of their
|
||||
±3 neighbouring bars are rejected (iterated until stable), and no auto
|
||||
anchor is placed in the MIDI's final partial bar.
|
||||
- **Editing model:** dragging an anchor only re-fits its two neighbouring
|
||||
stretches. Adding or moving a manual anchor deletes the auto anchors in the two
|
||||
affected stretches (those stretches become plain uniform scaling) until the user
|
||||
|
||||
Reference in new issue
Block a user