This commit is contained in:
Bear_03 2022-10-16 22:04:36 +02:00 committed by GitHub
commit a34c43eef9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 12 deletions

View File

@ -250,6 +250,7 @@ impl Backend for Android {
utterance_callbacks: true, utterance_callbacks: true,
voice: false, voice: false,
get_voice: false, get_voice: false,
synthesize: false,
} }
} }
@ -284,6 +285,10 @@ impl Backend for Android {
} }
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
unimplemented!();
}
fn stop(&mut self) -> Result<(), Error> { fn stop(&mut self) -> Result<(), Error> {
let vm = Self::vm()?; let vm = Self::vm()?;
let env = vm.get_env()?; let env = vm.get_env()?;

View File

@ -123,6 +123,10 @@ impl Backend for AppKit {
Ok(None) Ok(None)
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
unimplemented!();
}
fn stop(&mut self) -> Result<(), Error> { fn stop(&mut self) -> Result<(), Error> {
trace!("stop()"); trace!("stop()");
unsafe { unsafe {

View File

@ -169,6 +169,7 @@ impl Backend for AvFoundation {
voice: true, voice: true,
get_voice: false, get_voice: false,
utterance_callbacks: true, utterance_callbacks: true,
synthesize: false,
} }
} }
@ -205,6 +206,10 @@ impl Backend for AvFoundation {
Ok(Some(UtteranceId::AvFoundation(utterance))) Ok(Some(UtteranceId::AvFoundation(utterance)))
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
unimplemented!();
}
fn stop(&mut self) -> Result<(), Error> { fn stop(&mut self) -> Result<(), Error> {
trace!("stop()"); trace!("stop()");
unsafe { unsafe {

View File

@ -85,6 +85,7 @@ impl Backend for SpeechDispatcher {
voice: true, voice: true,
get_voice: false, get_voice: false,
utterance_callbacks: true, utterance_callbacks: true,
synthesize: false,
} }
} }
@ -108,6 +109,10 @@ impl Backend for SpeechDispatcher {
} }
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
unimplemented!();
}
fn stop(&mut self) -> Result<(), Error> { fn stop(&mut self) -> Result<(), Error> {
trace!("stop()"); trace!("stop()");
self.0.cancel()?; self.0.cancel()?;

View File

@ -39,6 +39,10 @@ impl Backend for Tolk {
Ok(None) Ok(None)
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
unimplemented!();
}
fn stop(&mut self) -> Result<(), Error> { fn stop(&mut self) -> Result<(), Error> {
trace!("stop()"); trace!("stop()");
self.0.silence(); self.0.silence();

View File

@ -59,6 +59,7 @@ impl Backend for Web {
voice: true, voice: true,
get_voice: true, get_voice: true,
utterance_callbacks: true, utterance_callbacks: true,
synthesize: false,
} }
} }
@ -121,6 +122,10 @@ impl Backend for Web {
} }
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
unimplemented!();
}
fn stop(&mut self) -> Result<(), Error> { fn stop(&mut self) -> Result<(), Error> {
trace!("stop()"); trace!("stop()");
if let Some(window) = web_sys::window() { if let Some(window) = web_sys::window() {

View File

@ -13,8 +13,11 @@ use windows::{
Media::{ Media::{
Core::MediaSource, Core::MediaSource,
Playback::{MediaPlayer, MediaPlayerAudioCategory}, Playback::{MediaPlayer, MediaPlayerAudioCategory},
SpeechSynthesis::{SpeechSynthesizer, VoiceGender, VoiceInformation}, SpeechSynthesis::{
SpeechSynthesisStream, SpeechSynthesizer, VoiceGender, VoiceInformation,
},
}, },
Storage::Streams::DataReader,
}; };
use crate::{Backend, BackendId, Error, Features, Gender, UtteranceId, Voice, CALLBACKS}; use crate::{Backend, BackendId, Error, Features, Gender, UtteranceId, Voice, CALLBACKS};
@ -139,6 +142,20 @@ impl WinRt {
voice: SpeechSynthesizer::DefaultVoice()?, voice: SpeechSynthesizer::DefaultVoice()?,
}) })
} }
fn create_synthesis_stream(&mut self, text: &str) -> Result<SpeechSynthesisStream, Error> {
self.synth.Options()?.SetSpeakingRate(self.rate.into())?;
self.synth.Options()?.SetAudioPitch(self.pitch.into())?;
self.synth.Options()?.SetAudioVolume(self.volume.into())?;
self.synth.SetVoice(&self.voice)?;
let stream = self
.synth
.SynthesizeTextToStreamAsync(&text.into())?
.get()?;
Ok(stream)
}
} }
impl Backend for WinRt { impl Backend for WinRt {
@ -156,6 +173,7 @@ impl Backend for WinRt {
voice: true, voice: true,
get_voice: true, get_voice: true,
utterance_callbacks: true, utterance_callbacks: true,
synthesize: true,
} }
} }
@ -190,18 +208,12 @@ impl Backend for WinRt {
} }
} }
if no_utterances { if no_utterances {
self.synth.Options()?.SetSpeakingRate(self.rate.into())?; let stream = self.create_synthesis_stream(text)?;
self.synth.Options()?.SetAudioPitch(self.pitch.into())?;
self.synth.Options()?.SetAudioVolume(self.volume.into())?; let media_source = MediaSource::CreateFromStream(&stream, &stream.ContentType()?)?;
self.synth.SetVoice(&self.voice)?; self.player.SetSource(&media_source)?;
let stream = self
.synth
.SynthesizeTextToStreamAsync(&text.into())?
.get()?;
let content_type = stream.ContentType()?;
let source = MediaSource::CreateFromStream(&stream, &content_type)?;
self.player.SetSource(&source)?;
self.player.Play()?; self.player.Play()?;
let mut callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let callbacks = callbacks.get_mut(&self.id).unwrap(); let callbacks = callbacks.get_mut(&self.id).unwrap();
if let Some(callback) = callbacks.utterance_begin.as_mut() { if let Some(callback) = callbacks.utterance_begin.as_mut() {
@ -211,6 +223,18 @@ impl Backend for WinRt {
Ok(Some(utterance_id)) Ok(Some(utterance_id))
} }
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error> {
let stream = self.create_synthesis_stream(text)?;
let size = stream.Size()?;
let data_reader = DataReader::CreateDataReader(&stream.GetInputStreamAt(0)?)?;
let mut bytes = vec![0; size as usize];
data_reader.LoadAsync(size as u32)?;
data_reader.ReadBytes(&mut bytes)?;
Ok(bytes)
}
fn stop(&mut self) -> std::result::Result<(), Error> { fn stop(&mut self) -> std::result::Result<(), Error> {
trace!("stop()"); trace!("stop()");
if !self.is_speaking()? { if !self.is_speaking()? {

View File

@ -162,6 +162,7 @@ unsafe impl Sync for UtteranceId {}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Features { pub struct Features {
pub is_speaking: bool, pub is_speaking: bool,
pub synthesize: bool,
pub pitch: bool, pub pitch: bool,
pub rate: bool, pub rate: bool,
pub stop: bool, pub stop: bool,
@ -217,6 +218,7 @@ pub trait Backend: Clone {
fn id(&self) -> Option<BackendId>; fn id(&self) -> Option<BackendId>;
fn supported_features(&self) -> Features; fn supported_features(&self) -> Features;
fn speak(&mut self, text: &str, interrupt: bool) -> Result<Option<UtteranceId>, Error>; fn speak(&mut self, text: &str, interrupt: bool) -> Result<Option<UtteranceId>, Error>;
fn synthesize(&mut self, text: &str) -> Result<Vec<u8>, Error>;
fn stop(&mut self) -> Result<(), Error>; fn stop(&mut self) -> Result<(), Error>;
fn min_rate(&self) -> f32; fn min_rate(&self) -> f32;
fn max_rate(&self) -> f32; fn max_rate(&self) -> f32;
@ -373,6 +375,15 @@ impl Tts {
.speak(text.into().as_str(), interrupt) .speak(text.into().as_str(), interrupt)
} }
pub fn synthesize<S: Into<String>>(&mut self, text: S) -> Result<Vec<u8>, Error> {
let Features { synthesize, .. } = self.supported_features();
if synthesize {
self.0.write().unwrap().synthesize(text.into().as_str())
} else {
Err(Error::UnsupportedFeature)
}
}
/// Stops current speech. /// Stops current speech.
pub fn stop(&mut self) -> Result<&Self, Error> { pub fn stop(&mut self) -> Result<&Self, Error> {
let Features { stop, .. } = self.supported_features(); let Features { stop, .. } = self.supported_features();