use crate::buffer::AudioBuffer;
pub use shabda::engine::{G2PEngine, Language};
pub use shabda::rules;
pub use shabda::normalize;
pub use shabda::syllable;
pub use shabda::prosody;
pub use shabda::arpabet;
pub use shabda::dictionary;
pub use svara::sequence::PhonemeEvent;
pub use svara::sequence::PhonemeSequence;
pub use shabda::error::ShabdaError;
pub fn text_to_phonemes(engine: &G2PEngine, text: &str) -> crate::Result<Vec<PhonemeEvent>> {
engine
.convert(text)
.map_err(|e| crate::NadaError::Dsp(format!("G2P conversion failed: {e}")))
}
pub fn speak(
engine: &G2PEngine,
text: &str,
voice: &svara::voice::VoiceProfile,
sample_rate: u32,
) -> crate::Result<AudioBuffer> {
let samples = engine
.speak(text, voice, sample_rate as f32)
.map_err(|e| crate::NadaError::Dsp(format!("speak failed: {e}")))?;
AudioBuffer::from_interleaved(samples, 1, sample_rate)
.map_err(|e| crate::NadaError::Dsp(format!("buffer from speech output: {e}")))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn english_g2p() {
let engine = G2PEngine::new(Language::English);
let phonemes = text_to_phonemes(&engine, "hello").unwrap();
assert!(!phonemes.is_empty());
}
#[test]
fn speak_hello() {
let engine = G2PEngine::new(Language::English);
let voice = svara::voice::VoiceProfile::new_female();
let buf = speak(&engine, "hello", &voice, 44100).unwrap();
assert!(buf.frames() > 0);
assert!(buf.rms() > 0.0);
assert!(buf.samples().iter().all(|s| s.is_finite()));
}
#[test]
fn phonemes_to_sequence() {
let engine = G2PEngine::new(Language::English);
let phonemes = text_to_phonemes(&engine, "test").unwrap();
let mut seq = PhonemeSequence::new();
for p in phonemes {
seq.push(p);
}
let voice = svara::voice::VoiceProfile::new_male();
let buf = crate::voice_synth::render_sequence(&seq, &voice, 44100).unwrap();
assert!(buf.frames() > 0);
}
}