use std::sync::Arc;
use windows::{
core::HSTRING, Media::SpeechSynthesis::SpeechSynthesizer, Storage::Streams::DataReader,
};
#[derive(Clone, Debug)]
pub struct Sapi5TtsSynthesizer {
synth: Arc<SpeechSynthesizer>,
}
impl Sapi5TtsSynthesizer {
pub fn new() -> Self {
let synth = SpeechSynthesizer::new().expect("Can't create the speech synthesizer.");
Self {
synth: synth.into(),
}
}
pub fn set_speed(&self, speed: f64) {
let options = self.synth.Options().unwrap();
options
.SetSpeakingRate(speed)
.expect("Can't set the speed value.");
}
pub fn set_pitch(&self, pitch: f64) {
let options = self.synth.Options().unwrap();
options
.SetAudioPitch(pitch)
.expect("Can't set the pitch value.");
}
pub fn set_volume(&self, volume: f64) {
let options = self.synth.Options().unwrap();
options
.SetAudioVolume(volume)
.expect("Can't set the volume value.");
}
pub fn get_voice_list(&self) -> Vec<(String, String)> {
let mut v: Vec<(String, String)> = vec![];
for x in SpeechSynthesizer::AllVoices().unwrap() {
v.push((
x.Id().unwrap().to_string(),
x.DisplayName().unwrap().to_string(),
))
}
v
}
pub fn set_voice(&self, voice: String) {
for x in SpeechSynthesizer::AllVoices().unwrap() {
if x.Id().unwrap().to_string() == voice {
self.synth.SetVoice(&x).unwrap_or(());
return;
}
}
}
pub fn synth(&self, text: &str, recv: impl Fn(Vec<u8>) -> bool) -> Option<[u8; 44]> {
let Ok(stream) = self.synth.SynthesizeTextToStreamAsync(&HSTRING::from(text)) else {
return None;
};
let Ok(stream) = stream.get() else {
return None;
};
let Ok(size) = stream.Size() else {
return None;
};
let Ok(reader) = DataReader::CreateDataReader(&stream) else {
return None;
};
let _ = reader.LoadAsync(size as u32);
let mut head: [u8; 44] = [0; 44];
reader.ReadBytes(&mut head).unwrap();
let mut last_len = size as u32 - 44;
let mut buffer: [u8; 3200] = [0; 3200];
loop {
if reader.ReadBytes(&mut buffer).is_err() {
break;
}
match reader.UnconsumedBufferLength() {
Ok(len) if last_len != len => {
if !recv(buffer[0..(last_len - len) as usize].to_vec()) {
break;
}
last_len = len;
}
_ => continue,
}
}
Some(head)
}
}
#[cfg(test)]
mod test_tts {
use crate::tts::Sapi5TtsSynthesizer;
#[test]
fn main() {
let synth = Sapi5TtsSynthesizer::new();
let (tx, rx) = std::sync::mpsc::channel();
synth.synth("你好呀,我们是一群追求梦想的人。", move |data| {
for i in data {
let _ = tx.send(i);
}
true
}).unwrap();
let v = rx.iter().collect::<Vec<_>>();
dbg!(v.len());
}
}