import os import shutil import subprocess import json from typing import Optional def _find_ffmpeg() -> str: path = shutil.which("ffmpeg") if path: return path winget_path = os.path.join( os.environ.get("LOCALAPPDATA", ""), "Microsoft", "WinGet", "Links", "ffmpeg.exe" ) if os.path.exists(winget_path): return winget_path alt_paths = [ r"C:\ffmpeg\bin\ffmpeg.exe", r"C:\Program Files\ffmpeg\bin\ffmpeg.exe", ] for p in alt_paths: if os.path.exists(p): return p raise RuntimeError("FFmpeg not found. Install it via: winget install ffmpeg") def get_audio_channels(input_path: str) -> int: ffmpeg_path = _find_ffmpeg() cmd = [ ffmpeg_path, "-i", input_path, "-f", "null", "-" ] result = subprocess.run(cmd, capture_output=True, text=True) stderr = result.stderr for line in stderr.split("\n"): if "Audio:" in line: if "stereo" in line or "2 channels" in line: return 2 elif "mono" in line or "1 channel" in line: return 1 import re m = re.search(r"(\d+)\s+channels?", line) if m: return int(m.group(1)) return 2 def convert_to_wav(input_path: str, output_dir: str, sample_rate: int = 16000) -> Optional[str]: os.makedirs(output_dir, exist_ok=True) base = os.path.splitext(os.path.basename(input_path))[0] output_path = os.path.join(output_dir, f"{base}_16khz.wav") channels = get_audio_channels(input_path) ac = "2" if channels == 2 else "1" ffmpeg_path = _find_ffmpeg() cmd = [ ffmpeg_path, "-y", "-i", input_path, "-acodec", "pcm_s16le", "-ac", ac, "-ar", str(sample_rate), output_path ] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: raise RuntimeError(f"FFmpeg error: {result.stderr}") return output_path, channels def split_stereo_channels(wav_path: str, output_dir: str) -> tuple[Optional[str], Optional[str]]: base = os.path.splitext(os.path.basename(wav_path))[0] left_path = os.path.join(output_dir, f"{base}_left.wav") right_path = os.path.join(output_dir, f"{base}_right.wav") ffmpeg_path = _find_ffmpeg() cmd = [ ffmpeg_path, "-y", "-i", wav_path, "-filter_complex", "[0:a]pan=mono|c0=c0[left];[0:a]pan=mono|c0=c1[right]", "-map", "[left]", left_path, "-map", "[right]", right_path, ] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: raise RuntimeError(f"FFmpeg split error: {result.stderr}") return left_path, right_path