#!/usr/bin/env python3 """ refine_onsets.py — VALIDATOR (not modifier). The score (.np file → events.json with `snappedStart` beat positions) is the authoritative source of timing in this pipeline. The visual storyboard rigidly follows the score; any drift between score and audio is a *pitchsnap* problem to fix at the audio generation layer, not papered over visually. This script measures the gap between score-defined slide.start times and detected audio onsets, prints a report of mismatches, and exits. It does NOT modify the storyboard. Use the report to identify which words pitchsnap rendered late/early — that's where the audio pipeline needs slot-rigid trimming/padding. Usage: refine_onsets.py """ import json import sys from pathlib import Path import numpy as np import librosa SEARCH_WIN_S = 0.85 # how far from snappedStart to look for an onset MIN_FIX_MS = 25 # don't override if onset is within this of original # (avoids jitter from low-confidence detections) def main(): if len(sys.argv) < 3: print("usage: refine_onsets.py