diff --git a/apply_sync.py b/apply_sync.py index e9d2ea2..18aa97e 100644 --- a/apply_sync.py +++ b/apply_sync.py @@ -159,11 +159,10 @@ def main(): # Auto-launch verify_sync in full mode verify_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "verify_sync.py") if os.path.exists(verify_script): - import subprocess as _sp verify_cmd = [sys.executable, verify_script, "--config", args.config or "config.toml", "--lag", f"{args.lag:.6f}", "--mode", "full"] print(f"Launching verify: {' '.join(verify_cmd)}") - _sp.Popen(verify_cmd) + subprocess.Popen(verify_cmd) sys.exit(0) diff --git a/rename_audio.py b/rename_audio.py index 00a5420..9c1f205 100644 --- a/rename_audio.py +++ b/rename_audio.py @@ -25,7 +25,6 @@ import shutil import subprocess import sys import tempfile -import numpy as np try: import whisper @@ -195,41 +194,6 @@ def get_lang_name(code: str) -> str: return LANG_NAMES.get(code, code.upper()) -def apply_metadata(file_path: str, stream_idx: int, lang_code_3: str, - title: str, dry_run: bool = True) -> str: - """ - Apply language metadata to a specific audio stream. - Returns the ffmpeg command (for display) or runs it. - """ - # Use 3-letter ISO 639-2/B code for MKV - meta_key = f"metadata:s:a:{stream_idx}" - - cmd = [ - "ffmpeg", "-y", - "-i", file_path, - "-map", "0", - "-c", "copy", - f"{meta_key}:language={lang_code_3}", - f"{meta_key}:title={title}", - ] - - if dry_run: - return " ".join(cmd) - - # Write to temp file, then replace - base, ext = os.path.splitext(file_path) - tmp_out = f"{tmp_out_base}{ext}" - cmd.append(tmp_out) - - r = subprocess.run(cmd, capture_output=True, timeout=300) - if r.returncode != 0: - print(f" ERROR: ffmpeg metadata failed: {r.stderr.decode()[-200:]}", file=sys.stderr) - return "" - - # Replace original - shutil.move(tmp_out, file_path) - return file_path - def main(): ap = argparse.ArgumentParser(description="Detect audio languages via Whisper and set MKV metadata") diff --git a/sync_audio.py b/sync_audio.py index d8179df..96a7168 100644 --- a/sync_audio.py +++ b/sync_audio.py @@ -15,7 +15,6 @@ Usage: from __future__ import annotations import os import sys -import math from typing import Tuple, Literal import numpy as np @@ -120,24 +119,14 @@ def correlate( # fftshift to center 0 lag corr_t = torch.roll(corr_t, shifts=N // 2) corr = corr_t.cpu().numpy() - # keep only valid length n centered - start = N // 2 - (len(b) - 1) - # Actually after roll, we want slice; simpler: use raw without roll and map lag later - # Recompute without roll for correct indexing, keep roll for display but fix lag calc - # For lag calc we need not shift: peak at N - lag etc. So we use shifted version + offset mapping - # To avoid confusion, return shifted corr and map lag accordingly - peak_idx = int(np.argmax(np.abs(corr))) - # lag = peak_idx - (len(b)-1) - (N//2 - (len(b)-1))? Let's instead use unshifted for lag and shifted for display - # Fallback: compute lag from unshifted + # compute lag from unshifted correlation for correct indexing corr_raw = torch.fft.irfft(R, n=N).cpu().numpy() peak_raw = int(np.argmax(np.abs(corr_raw))) - # raw layout: lag 0 at 0, positive lag (b delayed) wraps to end if peak_raw > N // 2: lag = peak_raw - N else: lag = peak_raw peak_val = float(np.abs(corr_raw[peak_raw])) - # return shifted display corr + lag return lag, peak_val, corr except Exception as e: print(f"torch cuda failed ({e}), falling back cpu", file=sys.stderr) @@ -156,10 +145,7 @@ def correlate( else: lag = peak_raw peak_val = float(np.abs(corr_raw[peak_raw])) - # shifted for display centered at 0 corr_shifted = np.fft.fftshift(corr_raw) - # but we return raw shifted centered? Provide shifted for plotting - # For consistency with torch branch we return shifted display array return lag, peak_val, corr_shifted @@ -170,9 +156,7 @@ def lag_to_seconds(lag_samples: int, sr: int = 48000) -> float: def apply_lag_with_silence(wav: np.ndarray, lag_samples: int) -> np.ndarray: """ Apply lag by padding silence at start (no sound for delay). - lag >0: b delayed vs a => pad b at start with lag silence to align to a, or trim a. - For mux: if lag>0 (b starts later), we need to delay a by lag or提前 b. - This helper pads with zeros (silence) at start; negative lag pads the other direction. + lag > 0: b delayed vs a. lag < 0: a delayed vs b. Caller decides which file to pad. """ if lag_samples == 0: @@ -200,7 +184,7 @@ def device_info() -> str: if __name__ == "__main__": - import argparse, pathlib + import argparse ap = argparse.ArgumentParser() ap.add_argument("a", help="wav A") ap.add_argument("b", help="wav B") diff --git a/sync_audio_test.py b/sync_audio_test.py index 4447bdd..7f61ed6 100644 --- a/sync_audio_test.py +++ b/sync_audio_test.py @@ -13,7 +13,7 @@ Run: make ast or .venv/bin/python sync_audio_test.py --config config.toml """ from __future__ import annotations -import os, sys, math, argparse, pathlib +import os, sys, math, argparse import numpy as np # allow tomllib (py3.11+) with tomli fallback @@ -31,12 +31,6 @@ except ImportError as e: print(e, file=sys.stderr) sys.exit(1) -try: - import soundfile as sf - HAS_SF = True -except ImportError: - HAS_SF = False - try: import sounddevice as sd HAS_SD = True @@ -152,15 +146,9 @@ class SyncWindow(QtWidgets.QMainWindow): # xcorr display β€” corr is already fftshifted N = len(self.corr) - # lags in seconds for display - total = len(self.a) + len(self.b) - 1 - n_pow2 = N # shifted lags: -N//2 .. N//2-1 self.corr_lags = np.arange(N) - N//2 self.corr_lags_sec = self.corr_lags / sr - # find peak index in raw (unshifted) for decimation - peak_raw_idx = int(np.argmax(np.abs(self.corr))) # this is fftshifted, peak near center - # for decimation we need the index in the shifted array central = QtWidgets.QWidget() self.setCentralWidget(central) diff --git a/verify_sync.py b/verify_sync.py index 5712c6a..611ad8c 100644 --- a/verify_sync.py +++ b/verify_sync.py @@ -22,7 +22,7 @@ Usage: """ from __future__ import annotations -import os, sys, math, argparse, subprocess, json, shutil, time, threading, tempfile, warnings +import os, sys, math, argparse, subprocess, json, shutil, threading, tempfile, warnings import numpy as np warnings.filterwarnings("ignore", category=RuntimeWarning, module="pyqtgraph") @@ -54,12 +54,6 @@ try: except ImportError: HAS_SD = False -try: - import soundfile as sf - HAS_SF = True -except ImportError: - HAS_SF = False - from sync_audio import load_wav from waveform_cache import cached_load_wav