first implementation of a voice trait for macOS

WARN: not tested
This commit is contained in:
François Caddet 2020-09-27 20:04:12 +02:00
parent f7297e18fd
commit e19eb56169
4 changed files with 28 additions and 8 deletions

View File

@ -24,6 +24,7 @@ crate-type = ["lib", "cdylib", "staticlib"]
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"
thiserror = "1" thiserror = "1"
unic-langid = "0.9.0"
[dev-dependencies] [dev-dependencies]
env_logger = "0.7" env_logger = "0.7"

View File

@ -59,7 +59,7 @@ fn main() -> Result<(), Error> {
tts.speak("This is normal volume.", false)?; tts.speak("This is normal volume.", false)?;
tts.set_volume(original_volume)?; tts.set_volume(original_volume)?;
} }
/* let Features { voices, .. } = tts.supported_features(); let Features { voices, .. } = tts.supported_features();
if voices { if voices {
let original_voice = tts.voice()?; let original_voice = tts.voice()?;
let voices_list = tts.list_voices(); let voices_list = tts.list_voices();
@ -72,7 +72,7 @@ fn main() -> Result<(), Error> {
tts.speak(v,false)?; tts.speak(v,false)?;
} }
tts.set_voice(original_voice)?; tts.set_voice(original_voice)?;
}*/ }
tts.speak("Goodbye.", false)?; tts.speak("Goodbye.", false)?;
let mut _input = String::new(); let mut _input = String::new();
// The below is only needed to make the example run on MacOS because there is no NSRunLoop in this context. // The below is only needed to make the example run on MacOS because there is no NSRunLoop in this context.

View File

@ -6,6 +6,10 @@ use cocoa_foundation::foundation::NSString;
use cocoa_foundation::base::{nil,id}; use cocoa_foundation::base::{nil,id};
use core_foundation::string::CFString; use core_foundation::string::CFString;
use crate::backends::AvFoundation;
use crate::voices;
use crate::voices::Gender;
#[derive(Copy,Clone)] #[derive(Copy,Clone)]
pub struct AVSpeechSynthesisVoice(*const Object); pub struct AVSpeechSynthesisVoice(*const Object);
@ -18,25 +22,39 @@ impl AVSpeechSynthesisVoice {
}; };
AVSpeechSynthesisVoice{0:voice} AVSpeechSynthesisVoice{0:voice}
} }
}
pub fn default() -> Self { impl voices::Backend for AVSpeechSynthesisVoice {
AVSpeechSynthesisVoice::list()[0] type Backend = AvFoundation;
}
pub fn list() -> Vec<Self> { fn list() -> Vec<Self> {
let voices: CFArray = unsafe{msg_send![class!(AVSpeechSynthesisVoice), speechVoices]}; let voices: CFArray = unsafe{msg_send![class!(AVSpeechSynthesisVoice), speechVoices]};
voices.iter().map(|v| { voices.iter().map(|v| {
AVSpeechSynthesisVoice{0: *v as *const Object} AVSpeechSynthesisVoice{0: *v as *const Object}
}).collect() }).collect()
} }
pub fn name(self) -> String { fn name(self) -> String {
let name: CFString = unsafe{msg_send![self.0, name]}; let name: CFString = unsafe{msg_send![self.0, name]};
name.to_string() name.to_string()
} }
pub fn identifier(self) -> String { fn gender(self) -> Gender {
let gender: i64 = unsafe{ msg_send![self.0, gender] };
match gender {
1 => Gender::Male,
2 => Gender::Female,
_ => Gender::Other,
}
}
fn id(self) -> String {
let identifier: CFString = unsafe{msg_send![self.0, identifier]}; let identifier: CFString = unsafe{msg_send![self.0, identifier]};
identifier.to_string() identifier.to_string()
} }
fn language(self) -> voices::LanguageIdentifier {
let lang: CFString = unsafe{msg_send![self.0, language]};
lang.to_string().parse().unwrap()
}
} }

View File

@ -32,6 +32,7 @@ use web_sys::SpeechSynthesisUtterance;
use tts_winrt_bindings::windows::media::playback::MediaPlaybackItem; use tts_winrt_bindings::windows::media::playback::MediaPlaybackItem;
mod backends; mod backends;
mod voices;
pub enum Backends { pub enum Backends {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]