# -*- coding: utf-8 -*- """Test der ROBUSTEN Stream-Kopf-Logik: fester 1.8s-Kopf + Crop am ersten SUBSTANZIELLEN Wort-Segment (ignoriert Mini-Blips) + FIXER Gain. Ziel: Start immer echtes Wort, out_rms stabil ~0.09, kein Clip.""" import os, numpy as np, librosa, soundfile as sf from pocket_tts import TTSModel from faster_whisper import WhisperModel BASE = r"F:\Coding Stuff\mission-control-2\client\lucy-tts" src,_ = librosa.load(os.path.join(BASE,"ref.mp3"), sr=24000, mono=True) srt,_ = librosa.effects.trim(src, top_db=30); ref=os.path.join(BASE,"ref.wav") sf.write(ref, srt[:int(18*24000)], 24000) TARGET_RMS=0.09; LEAD="Tja. " BASE_GAIN = TARGET_RMS / 0.18 # ~0.5 (raw full-rms ~0.18 konsistent) GMIN, GMAX = 0.7*BASE_GAIN, 1.4*BASE_GAIN # Gain-Clamp -> kann NIE explodieren HEAD_FIXED = int(2.0*24000) m = TTSModel.load_model(language="german_24l", lsd_decode_steps=6, temp=0.9) vs = m.get_state_for_audio_prompt(ref); sr=m.sample_rate w = WhisperModel("small", device="cpu", compute_type="int8") TEXTS = ["Hallo Commander, ich höre dich.", "Natürlich, Commander. Das Backup ist sauber durchgelaufen."] def crop_and_gain(a): """Crop am ersten SUBSTANZIELLEN Wort-Segment nach dem Lead (>=0.2s, ignoriert Mini-Blips); Gain aus voiced-rms, GECLAMPT (kann nie explodieren).""" iv = librosa.effects.split(a, top_db=35) voiced = np.concatenate([a[s:e] for s,e in iv]) if len(iv) else a rms = float(np.sqrt(np.mean(voiced**2))) or 1e-9 gain = float(np.clip(TARGET_RMS/rms, GMIN, GMAX)) cut = 0 if len(iv) >= 2: for k in range(1, len(iv)): if (iv[k][1]-iv[k][0]) >= int(0.20*sr): cut = max(iv[k-1][1], iv[k][0]-int(0.06*sr)); break return a[cut:], round(cut/sr,2), round(gain,2) def run_once(text): head=[]; hl=0; head_done=False; head_arr=None; rest=[] for c in m.generate_audio_stream(vs, LEAD+text, frames_after_eos=4): c=c.numpy() if hasattr(c,"numpy") else np.asarray(c); c=np.asarray(c,dtype=np.float32).reshape(-1) if not head_done: head.append(c); hl+=c.size if hl>=HEAD_FIXED: head_arr=np.concatenate(head); head_done=True else: rest.append(c) if head_arr is None: head_arr=np.concatenate(head) cropped_head, cutpt, gain = crop_and_gain(head_arr) full = np.concatenate([cropped_head]+rest) out=np.clip(full*gain,-0.95,0.95) sf.write(os.path.join(BASE,"out_diag_s3.wav"), out, sr) seg,_=w.transcribe(os.path.join(BASE,"out_diag_s3.wav"), language="de", beam_size=5) start=(" ".join(x.text for x in seg)).strip()[:32] return dict(cut=cutpt, gain=gain, out_rms=round(float(np.sqrt(np.mean(out**2))),3), out_peak=round(float(np.abs(out).max()),3), start=start) print(f"gain-clamp=[{round(GMIN,2)},{round(GMAX,2)}] head={HEAD_FIXED/24000}s") for text in TEXTS: print(f"=== {text[:28]!r} ===") for i in range(5): print(f" run{i}:", run_once(text)) print("DIAG3_DONE")