This commit is contained in:
pporcheret
2026-11-01 15:01:22 +01:00
parent 2c5537aff1
commit e2340807aa
36 changed files with 4952 additions and 8 deletions
+55
View File
@@ -91,6 +91,58 @@ def stop_playback():
pass
# DONA_WAVES_V1 — volume réel du WAV Wyoming Piper (50 ms, hors micro).
from array import array as _dona_array
import sys as _dona_sys
_dona_level_callback = None
def dona_set_level_callback(callback):
global _dona_level_callback
_dona_level_callback = callback
def _dona_emit_level(value):
if _dona_level_callback is not None:
try:
_dona_level_callback(max(0.0, min(1.0, float(value))))
except Exception:
pass # Une erreur côté interface ne doit jamais interrompre Piper.
def _dona_waves_stream_envelope(wav_path, proc):
"""Échantillonne le PCM pendant aplay, sans enregistrer ni exposer le son."""
try:
with wave.open(wav_path, 'rb') as stream:
if stream.getsampwidth() != 2:
return # Autre format : état « speaking » en secours côté navigateur.
rate=stream.getframerate()
if rate <= 0:
return
frames=max(1,int(rate * .05))
started=time.monotonic()
index=0
while proc.poll() is None:
raw=stream.readframes(frames)
if not raw:
break
samples=_dona_array('h')
samples.frombytes(raw)
if _dona_sys.byteorder=='big':
samples.byteswap()
stride=max(1,len(samples)//420)
window=samples[::stride]
rms=(sum(s*s for s in window)/max(1,len(window)))**.5
desired=started+index*frames/rate
remaining=desired-time.monotonic()
if remaining>0:
time.sleep(min(remaining,.07))
if proc.poll() is not None:
break
_dona_emit_level(min(1.0,rms/6500))
index+=1
except Exception as exc:
print('[DONA WAVES] analyse PCM impossible :',type(exc).__name__,flush=True)
finally:
_dona_emit_level(0)
def speak(text):
if not text or not text.strip():
return
@@ -123,6 +175,9 @@ def speak(text):
_playback_proc = proc
if _playback_cancel.is_set() and proc.poll() is None:
proc.terminate()
# DONA_WAVES_V1 : animation par l'amplitude du vrai son joué.
threading.Thread(target=_dona_waves_stream_envelope,
args=(wav_path,proc),daemon=True).start()
try:
result = proc.wait(timeout=120)
except subprocess.TimeoutExpired: