pub mod error;
pub mod models;
mod utils;
#[cfg(test)]
mod test;
use crate::models::NaturalModelTrait;
use derive_builder::Builder;
use models::AudioHandler;
use rodio::{OutputStream, Sink};
use std::path::PathBuf;
#[cfg(feature = "tts-rs")]
use tts::Tts;
#[cfg(feature = "coqui")]
use crate::models::coqui;
#[cfg(feature = "gtts")]
use crate::models::gtts;
#[cfg(feature = "meta")]
use crate::models::meta;
#[cfg(feature = "msedge")]
use crate::models::msedge;
#[cfg(feature = "parler")]
use crate::models::parler;
#[cfg(feature = "tts-rs")]
use crate::models::tts_rs::TtsModel;
use crate::error::TtsError;
#[derive(Builder, Default, Clone)]
#[builder(setter(into))]
pub struct NaturalTts {
pub default_model: Option<Model>,
#[builder(default = "None")]
pub audio_handler: Option<AudioHandler>,
#[cfg(feature = "tts-rs")]
#[builder(default = "None")]
pub tts_model: Option<TtsModel>,
#[cfg(feature = "parler")]
#[builder(default = "None")]
pub parler_model: Option<parler::ParlerModel>,
#[cfg(feature = "coqui")]
#[builder(default = "None")]
pub coqui_model: Option<coqui::CoquiModel>,
#[cfg(feature = "gtts")]
#[builder(default = "None")]
pub gtts_model: Option<gtts::GttsModel>,
#[cfg(feature = "msedge")]
#[builder(default = "None")]
pub msedge_model: Option<msedge::MSEdgeModel>,
#[cfg(feature = "meta")]
#[builder(default = "None")]
pub meta_model: Option<meta::MetaModel>,
}
impl NaturalTts {
#[cfg(feature = "tts-rs")]
pub fn get_tts_handler(&mut self) -> Result<&mut Tts, TtsError> {
if let Some(tts) = &mut self.tts_model {
Ok(&mut tts.0)
} else {
Err(TtsError::NotLoaded)
}
}
pub fn get_rodio_sink_mut(&mut self) -> Result<(&mut Sink, &mut OutputStream), TtsError> {
match &mut self.audio_handler {
Some(AudioHandler::Sink { sink, stream }) => Ok((sink, stream)),
#[cfg(feature = "tts-rs")]
Some(_) => Err(TtsError::NotSupported),
_ => Err(TtsError::NotLoaded),
}
}
pub fn get_rodio_sink(&self) -> Result<(&Sink, &OutputStream), TtsError> {
match &self.audio_handler {
Some(AudioHandler::Sink { sink, stream }) => Ok((sink, stream)),
#[cfg(feature = "tts-rs")]
Some(_) => Err(TtsError::NotSupported),
_ => Err(TtsError::NotLoaded),
}
}
pub fn sleep_until_end(&self) {
match &self.audio_handler {
Some(AudioHandler::Sink { sink, stream: _ }) => sink.sleep_until_end(),
#[cfg(feature = "tts-rs")]
_ => {
use std::{thread, time::Duration};
if let Some(x) = &self.tts_model {
while x.0.is_speaking().unwrap_or_default() {
thread::sleep(Duration::from_millis(100));
}
}
}
#[allow(unreachable_patterns)]
_ => {}
}
}
pub fn start(&mut self, message: String, path: &PathBuf) -> Result<(), TtsError> {
if let Some(model) = &self.default_model {
self.audio_handler = Some(match model {
#[cfg(feature = "coqui")]
Model::Coqui => match &mut self.coqui_model {
Some(x) => x.start(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "parler")]
Model::Parler => match &mut self.parler_model {
Some(x) => x.start(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "tts-rs")]
Model::TTS => match &mut self.tts_model {
Some(x) => x.start(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "msedge")]
Model::MSEdge => match &mut self.msedge_model {
Some(x) => x.start(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "meta")]
Model::Meta => match &mut self.meta_model {
Some(x) => x.start(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "gtts")]
_ => match &mut self.gtts_model {
Some(x) => x.start(message, path),
None => Err(TtsError::NotLoaded),
},
}?);
return Ok(());
}
Err(TtsError::NoDefaultModel)
}
pub fn synthesize(
&mut self,
message: String,
path: &PathBuf,
) -> Result<models::SynthesizedAudio<f32>, TtsError> {
if let Some(model) = &self.default_model {
return match model {
#[cfg(feature = "coqui")]
Model::Coqui => match &mut self.coqui_model {
Some(x) => x.synthesize(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "parler")]
Model::Parler => match &mut self.parler_model {
Some(x) => x.synthesize(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "tts-rs")]
Model::TTS => match &mut self.tts_model {
Some(x) => x.synthesize(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "msedge")]
Model::MSEdge => match &mut self.msedge_model {
Some(x) => x.synthesize(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "meta")]
Model::Meta => match &mut self.meta_model {
Some(x) => x.synthesize(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "gtts")]
_ => match &mut self.gtts_model {
Some(x) => x.synthesize(message, path),
None => Err(TtsError::NotLoaded),
},
};
}
Err(TtsError::NoDefaultModel)
}
pub fn save(&mut self, message: String, path: &PathBuf) -> Result<(), TtsError> {
if let Some(model) = &self.default_model {
return match model {
#[cfg(feature = "coqui")]
Model::Coqui => match &mut self.coqui_model {
Some(x) => x.save(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "parler")]
Model::Parler => match &mut self.parler_model {
Some(x) => x.save(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "tts-rs")]
Model::TTS => match &mut self.tts_model {
Some(x) => x.save(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "msedge")]
Model::MSEdge => match &mut self.msedge_model {
Some(x) => x.save(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "meta")]
Model::Meta => match &mut self.meta_model {
Some(x) => x.save(message, path),
None => Err(TtsError::NotLoaded),
},
#[cfg(feature = "gtts")]
_ => match &mut self.gtts_model {
Some(x) => x.save(message, path),
None => Err(TtsError::NotLoaded),
},
};
}
Err(TtsError::NoDefaultModel)
}
pub fn resume(&mut self) -> Result<(), TtsError> {
match &mut self.audio_handler {
Some(AudioHandler::Sink { sink, stream: _ }) => sink.play(),
#[cfg(feature = "tts-rs")]
Some(_) => return Err(TtsError::NotSupported),
_ => return Err(TtsError::NotLoaded),
}
Ok(())
}
pub fn stop(&mut self) -> Result<(), TtsError> {
match &mut self.audio_handler {
Some(AudioHandler::Sink { sink, stream: _ }) => sink.stop(),
#[cfg(feature = "tts-rs")]
Some(AudioHandler::Tts) => match &mut self.tts_model {
Some(x) => {
let _ = x.0.stop()?;
}
None => return Err(TtsError::NotSupported),
},
_ => return Err(TtsError::NotLoaded),
}
Ok(())
}
}
#[derive(Clone)]
pub enum Model {
#[cfg(feature = "coqui")]
Coqui,
#[cfg(feature = "parler")]
Parler,
#[cfg(feature = "tts-rs")]
TTS,
#[cfg(feature = "msedge")]
MSEdge,
#[cfg(feature = "meta")]
Meta,
#[cfg(feature = "gtts")]
Gtts,
}
impl Default for Model {
fn default() -> Self {
#[cfg(feature = "gtts")]
#[allow(unreachable_code)]
{
return Self::Gtts;
}
#[cfg(feature = "parler")]
#[allow(unreachable_code)]
{
return Self::Parler;
}
#[cfg(feature = "meta")]
#[allow(unreachable_code)]
{
return Self::Meta;
}
#[cfg(feature = "msedge")]
#[allow(unreachable_code)]
{
return Self::MSEdge;
}
#[cfg(feature = "tts-rs")]
#[allow(unreachable_code)]
{
return Self::TTS;
}
#[cfg(feature = "coqui")]
#[allow(unreachable_code)]
{
return Self::Coqui;
}
}
}