pub mod mock;
pub mod onnx;
pub mod phonemes;
pub use mock::MockTts;
pub use onnx::OnnxTts;
use crate::config::Config;
use crate::error::Result;
pub const TTS_SAMPLE_RATE: u32 = 24_000;
const DEFAULT_VOICE: &str = "af";
const DEFAULT_SPEED: f32 = 1.0;
#[derive(Debug, Clone)]
pub struct TtsClip {
pub samples: Vec<f32>,
pub sample_rate: u32,
}
pub trait TtsEngine: Send {
fn synthesize(&mut self, text: &str) -> Result<TtsClip>;
}
pub fn build_engine(cfg: &Config) -> Result<Box<dyn TtsEngine>> {
if !cfg.mock_tts {
match (&cfg.tts_model, &cfg.tts_voices) {
(Some(model), Some(voices)) if model.exists() && voices.exists() => {
match OnnxTts::load(model, voices, DEFAULT_VOICE, DEFAULT_SPEED) {
Ok(engine) => return Ok(Box::new(engine)),
Err(e) => {
tracing::warn!(
error = %e,
"failed to load Kokoro TTS; falling back to sine-wave MockTts"
);
}
}
}
(model, voices) => {
tracing::warn!(
tts_model = ?model,
tts_voices = ?voices,
"Kokoro TTS files absent or incomplete; falling back to sine-wave \
MockTts (run scripts/download_models.sh --with-kokoro)"
);
}
}
}
Ok(Box::new(MockTts::new()))
}