2020-08-18 20:16:30 +00:00
|
|
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
2020-08-13 16:08:00 +00:00
|
|
|
#[link(name = "AVFoundation", kind = "framework")]
|
|
|
|
use cocoa_foundation::base::{id, nil};
|
|
|
|
use cocoa_foundation::foundation::NSString;
|
|
|
|
use log::{info, trace};
|
|
|
|
use objc::runtime::*;
|
|
|
|
use objc::*;
|
|
|
|
|
|
|
|
use crate::{Backend, Error, Features};
|
|
|
|
|
2020-09-03 14:50:11 +00:00
|
|
|
mod voices;
|
|
|
|
use voices::AVSpeechSynthesisVoice;
|
|
|
|
|
2020-08-13 16:08:00 +00:00
|
|
|
pub struct AvFoundation {
|
|
|
|
synth: *mut Object,
|
|
|
|
rate: f32,
|
|
|
|
volume: f32,
|
|
|
|
pitch: f32,
|
2020-09-03 14:50:11 +00:00
|
|
|
voice: AVSpeechSynthesisVoice,
|
2020-08-13 16:08:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AvFoundation {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
info!("Initializing AVFoundation backend");
|
|
|
|
unsafe {
|
|
|
|
let synth: *mut Object = msg_send![class!(AVSpeechSynthesizer), new];
|
|
|
|
AvFoundation {
|
|
|
|
synth: synth,
|
|
|
|
rate: 0.5,
|
|
|
|
volume: 1.,
|
|
|
|
pitch: 1.,
|
2020-09-03 16:40:32 +00:00
|
|
|
voice: AVSpeechSynthesisVoice::default(),
|
2020-08-13 16:08:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Backend for AvFoundation {
|
|
|
|
fn supported_features(&self) -> Features {
|
|
|
|
Features {
|
|
|
|
stop: true,
|
|
|
|
rate: true,
|
|
|
|
pitch: true,
|
|
|
|
volume: true,
|
|
|
|
is_speaking: true,
|
2020-09-03 14:50:11 +00:00
|
|
|
voices: true,
|
2020-08-13 16:08:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn speak(&mut self, text: &str, interrupt: bool) -> Result<(), Error> {
|
|
|
|
trace!("speak({}, {})", text, interrupt);
|
|
|
|
if interrupt {
|
|
|
|
self.stop()?;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
let str = NSString::alloc(nil).init_str(text);
|
|
|
|
let utterance: id = msg_send![class!(AVSpeechUtterance), alloc];
|
|
|
|
let _: () = msg_send![utterance, initWithString: str];
|
|
|
|
let _: () = msg_send![utterance, setRate: self.rate];
|
|
|
|
let _: () = msg_send![utterance, setVolume: self.volume];
|
|
|
|
let _: () = msg_send![utterance, setPitchMultiplier: self.pitch];
|
2020-09-03 16:40:32 +00:00
|
|
|
let _: () = msg_send![utterance, setVoice: self.voice];
|
2020-08-13 16:08:00 +00:00
|
|
|
let _: () = msg_send![self.synth, speakUtterance: utterance];
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stop(&mut self) -> Result<(), Error> {
|
|
|
|
trace!("stop()");
|
|
|
|
unsafe {
|
|
|
|
let _: () = msg_send![self.synth, stopSpeakingAtBoundary: 0];
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn min_rate(&self) -> f32 {
|
|
|
|
0.1
|
|
|
|
}
|
|
|
|
|
|
|
|
fn max_rate(&self) -> f32 {
|
|
|
|
2.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn normal_rate(&self) -> f32 {
|
|
|
|
0.5
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_rate(&self) -> Result<f32, Error> {
|
|
|
|
Ok(self.rate)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_rate(&mut self, rate: f32) -> Result<(), Error> {
|
|
|
|
trace!("set_rate({})", rate);
|
|
|
|
self.rate = rate;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn min_pitch(&self) -> f32 {
|
|
|
|
0.5
|
|
|
|
}
|
|
|
|
|
|
|
|
fn max_pitch(&self) -> f32 {
|
|
|
|
2.0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn normal_pitch(&self) -> f32 {
|
|
|
|
1.0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_pitch(&self) -> Result<f32, Error> {
|
|
|
|
Ok(self.pitch)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_pitch(&mut self, pitch: f32) -> Result<(), Error> {
|
|
|
|
self.pitch = pitch;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn min_volume(&self) -> f32 {
|
|
|
|
0.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn max_volume(&self) -> f32 {
|
|
|
|
1.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn normal_volume(&self) -> f32 {
|
|
|
|
1.
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_volume(&self) -> Result<f32, Error> {
|
|
|
|
Ok(self.volume)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_volume(&mut self, volume: f32) -> Result<(), Error> {
|
|
|
|
self.volume = volume;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_speaking(&self) -> Result<bool, Error> {
|
|
|
|
let is_speaking: i8 = unsafe { msg_send![self.synth, isSpeaking] };
|
2020-08-18 20:16:30 +00:00
|
|
|
Ok(is_speaking == 1)
|
2020-08-13 16:08:00 +00:00
|
|
|
}
|
2020-09-03 14:50:11 +00:00
|
|
|
|
|
|
|
fn voice(&self) -> Result<String,Error> {
|
|
|
|
Ok(self.voice.identifier())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn list_voices(&self) -> Vec<String> {
|
|
|
|
AVSpeechSynthesisVoice::list().iter().map(|v| {v.identifier()}).collect()
|
|
|
|
}
|
|
|
|
|
2020-09-04 13:48:56 +00:00
|
|
|
fn set_voice(&mut self, voice: &str) -> Result<(),Error> {
|
2020-09-03 16:40:32 +00:00
|
|
|
self.voice = AVSpeechSynthesisVoice::new(voice);
|
2020-09-03 14:50:11 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2020-08-13 16:08:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for AvFoundation {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
let _: Object = msg_send![self.synth, release];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|