diff --git a/xtts/f5tts/bridge.py b/xtts/f5tts/bridge.py index f1e9603..e409568 100644 --- a/xtts/f5tts/bridge.py +++ b/xtts/f5tts/bridge.py @@ -256,39 +256,48 @@ def voice_paths(name: str) -> tuple[Path, Path]: def normalize_ref_wav(src_wav: Path, max_seconds: float = REF_MAX_SECONDS) -> tuple[Path, bool]: """Bringt die Referenz-WAV in F5-TTS-freundliche Form: - 24kHz mono + max max_seconds Dauer. Original wird ueberschrieben wenn - Aenderungen noetig waren. + + * 24kHz mono + * max max_seconds Dauer + * Stille am Anfang + Ende abgeschnitten (silenceremove-Filter) + * Lautheit auf -16 LUFS normalisiert (loudnorm-Filter) damit + das Modell konsistente Amplituden sieht + + F5-TTS reagiert empfindlich auf leise / verrauschte / zerhackte + Referenzen. Konsistente, saubere Input-Lautheit hilft der Quali. Returns: (path, was_modified) — was_modified=True wenn die Datei wirklich geaendert wurde (Caller sollte dann den passenden .txt invalidieren). """ - try: - info = sf.info(str(src_wav)) - # Schon gut? Sample-Rate, Kanaele und Dauer passen? - if (info.samplerate == TARGET_SR and info.channels == 1 - and info.duration <= max_seconds + 0.1): - return src_wav, False - except Exception: - info = None - tmp_out = src_wav.with_suffix(".conv.wav") + # silenceremove am Anfang: bis -50dB gesprochen wird + # silenceremove am Ende: ueber -50dB rein, dann 0.5s stille als Cutoff + # loudnorm: EBU R128, Ziel -16 LUFS + af = ("silenceremove=start_periods=1:start_duration=0.05:start_threshold=-50dB," + "silenceremove=stop_periods=1:stop_duration=0.5:stop_threshold=-50dB," + "loudnorm=I=-16:TP=-1.5:LRA=11") cmd = ["ffmpeg", "-y", "-i", str(src_wav), + "-af", af, "-ar", str(TARGET_SR), "-ac", "1", "-t", str(max_seconds), "-f", "wav", str(tmp_out)] r = subprocess.run(cmd, capture_output=True, timeout=30) if r.returncode != 0: logger.warning("ffmpeg-Normalisierung von %s fehlgeschlagen: %s", - src_wav, r.stderr.decode(errors="replace")[:200]) + src_wav, r.stderr.decode(errors="replace")[:300]) try: tmp_out.unlink() except OSError: pass return src_wav, False os.replace(tmp_out, src_wav) - logger.info("Referenz-WAV normalisiert: %s (24kHz mono, max %.1fs)", - src_wav.name, max_seconds) + try: + info = sf.info(str(src_wav)) + logger.info("Referenz-WAV normalisiert: %s (%.1fs, %dHz mono, -16 LUFS, silence getrimmt)", + src_wav.name, info.duration, info.samplerate) + except Exception: + logger.info("Referenz-WAV normalisiert: %s", src_wav.name) return src_wav, True