diff --git a/scripts/avsync.py b/scripts/avsync.py index 28f63c4..a452969 100644 --- a/scripts/avsync.py +++ b/scripts/avsync.py @@ -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")