# -*- coding: utf-8 -*- """Sweep v2: lsd 4/5/6 + FIX gegen Vorne/Hinten-Abschneiden & Clipping. - peak-normalize auf 0.95 (killt PCM-16-Clipping/Distortion; roh war peak bis 1.56) - KEIN aggressiver Front-Trim mehr (Modell startet bei 0ms Stille -> Trim fraß 1. Phonem) - nur tiefe Stille sanft trimmen (top_db=45), dann feste 90ms-Pause vorne+hinten (Atem) - frames_after_eos=4 (kurze Sätze bekamen sonst 0ms Schwanz = abgeschnitten) """ import os, time, numpy as np, soundfile as sf, librosa from pocket_tts import TTSModel BASE = r"F:\Coding Stuff\mission-control-2\client\lucy-tts" OUT = r"C:\Users\TobisPC\Desktop\lucy_lsd_v2"; os.makedirs(OUT, exist_ok=True) y, _ = librosa.load(os.path.join(BASE, "ref.mp3"), sr=24000, mono=True) yt, _ = librosa.effects.trim(y, top_db=30); ref = os.path.join(BASE, "ref.wav") sf.write(ref, yt[:int(18*24000)], 24000) SENT = { "kurz": "Hallo Commander, ich höre dich.", "mittel":"Guten Morgen, Commander. Das Backup ist sauber durchgelaufen und es gab keine Fehler.", "lang": "Natürlich kümmere ich mich darum, Commander. Ich starte den Dienst neu, prüfe die Protokolle und melde mich, sobald alles wieder läuft.", } def cleanup_v2(a, sr): a = np.asarray(a, dtype=np.float32).reshape(-1) if a.size == 0: return a # 1) Peak-Normalisierung gegen Clipping/Distortion peak = float(np.max(np.abs(a))) if peak > 0: a = a * (0.95 / peak) # 2) nur TIEFE Stille sanft wegtrimmen (top_db=45 = wenig aggressiv, lässt weiche Onsets) yt, _ = librosa.effects.trim(a, top_db=45) a = yt if yt.size else a # 3) kurze 10ms-Fades an den echten Audiokanten (gegen Klicks) fi = min(int(0.01 * sr), a.size // 2) if fi > 0: a[:fi] *= np.linspace(0.0, 1.0, fi, dtype=np.float32) a[-fi:] *= np.linspace(1.0, 0.0, fi, dtype=np.float32) # 4) feste 90ms Atem-Pause vorne+hinten (kein abruptes Einsetzen/Abschneiden) pad = np.zeros(int(0.09 * sr), dtype=np.float32) return np.concatenate([pad, a, pad]) for lsd in [4, 5, 6]: t0 = time.time() m = TTSModel.load_model(language="german_24l", lsd_decode_steps=lsd) vs = m.get_state_for_audio_prompt(ref) sr = m.sample_rate print(f"== lsd={lsd} (load {time.time()-t0:.1f}s) ==", flush=True) for name, text in SENT.items(): t0 = time.time() audio = m.generate_audio(vs, text, frames_after_eos=4) dt = time.time() - t0 a = audio.numpy() if hasattr(audio, "numpy") else np.asarray(audio) a = cleanup_v2(a, sr) secs = a.size / sr sf.write(os.path.join(OUT, f"lsd{lsd}_{name}.wav"), a, sr) print(f" [{name:6}] gen={dt:5.2f}s audio={secs:5.2f}s RTF={dt/max(secs,0.01):.2f} peak={np.abs(a).max():.3f}", flush=True) print("TUNE_V2_DONE", flush=True)