diff --git a/clap_detection.py b/clap_detection.py index 2135e97..2c4ec84 100644 --- a/clap_detection.py +++ b/clap_detection.py @@ -77,9 +77,26 @@ def _extract_audio_wav(input_path: str, audio_stream_index: Optional[int] = None os.close(fd) cmd = ["ffmpeg", "-y", "-i", input_path, "-vn"] cmd += ["-map", f"0:{audio_stream_index}" if audio_stream_index is not None else "a:0"] + # aresample=async=1 keeps the decoded audio conformed to its own + # internal PTS, filling any gap with silence instead of silently + # closing it up. Long recordings (stream captures, OBS-style long + # sessions) can have a genuine multi-second discontinuity mid-file -- + # e.g. a brief audio-device dropout -- from a real capture glitch, not + # anything to do with sync between tracks. Plain -vn extraction just + # concatenates packets and ignores the gap, silently shortening the + # output and shifting every onset after that point earlier by however + # long the gap was. Confirmed on a real ~110min capture with exactly + # one such gap (+1.621s at ~15.5min in): without this filter the + # extracted WAV came out 1.6s short of the source's true duration; + # with it, the duration matches exactly. This is a different failure + # mode from the leading start_time offset below (which aresample alone + # does NOT fix -- it re-zeros to its own first frame, same as plain + # extraction), so both are needed together, not either/or. + af_chain = ["aresample=async=1"] if audio_start > 0.001: delay_ms = int(round(audio_start * 1000)) - cmd += ["-af", f"adelay={delay_ms}|{delay_ms}"] + af_chain.append(f"adelay={delay_ms}|{delay_ms}") + cmd += ["-af", ",".join(af_chain)] cmd += ["-acodec", "pcm_s16le", "-ar", "22050", "-ac", "1", wav_path] result = subprocess.run(cmd, capture_output=True, text=True)