fix(tools): avsync says "unmeasurable" instead of trusting a 0.08 correlation

On ty-20261112-1401-952-0000-2.mp4 the per-window estimates ranged from +400 to -370 ms and
only one window cleared 0.35, yet the tool printed "-370 ms, adjust by +370" from an overall
correlation of 0.08. A number that wrong is worse than no number: it invites another build.

Now: windows above 0.35 must also agree within 150 ms, and anything weaker reports
"unmeasurable" with the remedy — three claps with the hands in the webcam frame, two seconds
apart, which gives a sharp visual and audio transient instead of a mouth-motion proxy.

Also reverted an onset-based envelope tried on the same clip: it dropped the best window's
correlation from 0.47 to 0.08, so the plain level envelope stays.

What the run did establish: lengths match (15.555 s video against 15.601 s audio, 0.3%), and
the log confirms "mic delay 350 ms" was applied — the drift fix and the delay wiring both hold.
This commit is contained in:
2026-11-12 14:03:45 -08:00
parent bb3bc12784
commit 514fb8480d
+15 -4
View File
@@ -129,10 +129,16 @@ def offset_ms(audio: np.ndarray, motion: np.ndarray, fps: float, max_ms: float =
lag, corr = best_for(m[start:start + seg], a[start:start + seg])
windows.append((start / grid, lag, corr))
strong = sorted(lag for _, lag, corr in windows if corr >= 0.35)
if strong:
if len(strong) >= 2:
mid = len(strong) // 2
robust = strong[mid] if len(strong) % 2 else (strong[mid - 1] + strong[mid]) / 2
spread = strong[-1] - strong[0]
if spread > 150:
# Windows that disagree this much cannot be averaged into an answer. Say so.
return float("nan"), max(corr for _, _, corr in windows), windows
return robust, max(corr for _, _, corr in windows), windows
if strong:
return float("nan"), max(corr for _, _, corr in windows), windows
return overall_lag, overall_corr, windows
@@ -168,13 +174,18 @@ def main() -> int:
print(f"delta {diff:+8.3f} s ({pct:+.2f}% of the video length)")
verdict = "lengths match" if abs(diff) < 0.05 else "LENGTH MISMATCH — a clock problem"
print(f" {verdict}")
quality = "strong" if corr >= 0.35 else "weak — treat the offset as a hint only"
for start, wlag, wcorr in windows:
mark = "*" if wcorr >= 0.35 else " "
print(f" {start:5.1f}s {wlag:+7.0f} ms corr {wcorr:.2f} {mark}")
print(f"offset {lag:+8.0f} ms (correlation {corr:.2f}, {quality})")
direction = "sound LATER than the lips" if lag > 0 else "sound EARLIER than the lips"
if lag != lag or corr < 0.35:
print("offset unmeasurable — too little agreement between mouth motion and speech")
print(" record 3 claps with your hands in the webcam frame, 2 s apart")
return 0
print(f"offset {lag:+8.0f} ms (correlation {corr:.2f})")
if abs(lag) >= 20:
direction = "sound LATER than the lips" if lag > 0 else "sound EARLIER than the lips"
print(f" {direction} — adjust the mic delay by {-lag:+.0f} ms")
else:
print(" within a frame or two — leave it alone")