Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import io | |
| import wave | |
| import numpy as np | |
| from piper import PiperVoice | |
| def load_voice(voice_path: str = "models/piper/cs_CZ-jirka-medium.onnx") -> PiperVoice: | |
| return PiperVoice.load(voice_path) | |
| def synthesize(voice: PiperVoice, text: str) -> tuple[np.ndarray, int]: | |
| """Synthesize `text` and return (mono float32 waveform in [-1,1], sample_rate).""" | |
| buf = io.BytesIO() | |
| with wave.open(buf, "wb") as wf: | |
| voice.synthesize_wav(text, wf) | |
| buf.seek(0) | |
| with wave.open(buf, "rb") as wf: | |
| sr = wf.getframerate() | |
| n_channels = wf.getnchannels() | |
| sampwidth = wf.getsampwidth() | |
| raw = wf.readframes(wf.getnframes()) | |
| if sampwidth != 2: | |
| raise RuntimeError(f"Unexpected Piper sample width: {sampwidth} bytes") | |
| pcm = np.frombuffer(raw, dtype=np.int16).astype(np.float32) / 32768.0 | |
| if n_channels > 1: | |
| pcm = pcm.reshape(-1, n_channels).mean(axis=1) | |
| return pcm, sr | |
| def synthesize_duration(voice: PiperVoice, text: str) -> tuple[float, np.ndarray, int]: | |
| """Convenience: returns (duration_seconds, waveform, sample_rate).""" | |
| wav, sr = synthesize(voice, text) | |
| return len(wav) / sr, wav, sr | |