From 75fd320d3fb50d0c7c528208684b9f99972b2859 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Wed, 12 Aug 2020 15:41:57 -0500 Subject: [PATCH] Implement rate/volume-setting for `NSSpeechSynthesizer`, along with other tweaks. Unfortunately, there seems to be a difference in how the `hello_world` example processes rate and volume changes. I'm not sure if it doesn't adjust rate for samples while speaking. In any case, arguably there are just going to be differences in platforms that I can't account for, so this may just have to be. Hopefully it doesn't interfere with actual usage. --- src/backends/ns_speech_synthesizer.rs | 81 +++++++++++++++------------ 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/src/backends/ns_speech_synthesizer.rs b/src/backends/ns_speech_synthesizer.rs index 2531a40..339fb11 100644 --- a/src/backends/ns_speech_synthesizer.rs +++ b/src/backends/ns_speech_synthesizer.rs @@ -20,6 +20,7 @@ impl NSSpeechSynthesizerBackend { ClassDecl::new("MyNSSpeechSynthesizerDelegate", class!(NSObject)).unwrap(); decl.add_ivar::("synth"); decl.add_ivar::("strings"); + extern "C" fn enqueue_and_speak(this: &Object, _: Sel, string: id) { unsafe { let strings: id = *this.get_ivar("strings"); @@ -32,6 +33,11 @@ impl NSSpeechSynthesizerBackend { } } } + decl.add_method( + sel!(enqueueAndSpeak:), + enqueue_and_speak as extern "C" fn(&Object, Sel, id) -> (), + ); + extern "C" fn speech_synthesizer_did_finish_speaking( this: &Object, _: Sel, @@ -50,6 +56,12 @@ impl NSSpeechSynthesizerBackend { } } } + decl.add_method( + sel!(speechSynthesizer:didFinishSpeaking:), + speech_synthesizer_did_finish_speaking + as extern "C" fn(&Object, Sel, *const Object, BOOL) -> (), + ); + extern "C" fn clear_queue(this: &Object, _: Sel) { unsafe { let strings: id = *this.get_ivar("strings"); @@ -62,19 +74,11 @@ impl NSSpeechSynthesizerBackend { } } } - decl.add_method( - sel!(speechSynthesizer:didFinishSpeaking:), - speech_synthesizer_did_finish_speaking - as extern "C" fn(&Object, Sel, *const Object, BOOL) -> (), - ); - decl.add_method( - sel!(enqueueAndSpeak:), - enqueue_and_speak as extern "C" fn(&Object, Sel, id) -> (), - ); decl.add_method( sel!(clearQueue), clear_queue as extern "C" fn(&Object, Sel) -> (), ); + let delegate_class = decl.register(); let delegate_obj: *mut Object = msg_send![delegate_class, new]; delegate_obj.as_mut().unwrap().set_ivar("synth", obj); @@ -84,22 +88,16 @@ impl NSSpeechSynthesizerBackend { NSSpeechSynthesizerBackend(obj, delegate_obj) } } - - /*fn pop_and_speak(&mut self) { - if let Some(str) = self.2.first() { - let _: BOOL = unsafe { msg_send![self.0, startSpeakingString: *str] }; - } - }*/ } impl Backend for NSSpeechSynthesizerBackend { fn supported_features(&self) -> Features { Features { - stop: false, - rate: false, + stop: true, + rate: true, pitch: false, - volume: false, - is_speaking: false, + volume: true, + is_speaking: true, } } @@ -125,35 +123,40 @@ impl Backend for NSSpeechSynthesizerBackend { } fn min_rate(&self) -> f32 { - -100. + 10. } fn max_rate(&self) -> f32 { - 100. + 500. } fn normal_rate(&self) -> f32 { - 0. + 175. } fn get_rate(&self) -> Result { - unimplemented!() + let rate: f32 = unsafe { msg_send![self.0, rate] }; + Ok(rate) } fn set_rate(&mut self, rate: f32) -> Result<(), Error> { - unimplemented!() + trace!("set_rate({})", rate); + unsafe { + let _: () = msg_send![self.0, setRate: rate]; + } + Ok(()) } fn min_pitch(&self) -> f32 { - -100. + unimplemented!() } fn max_pitch(&self) -> f32 { - 100. + unimplemented!() } fn normal_pitch(&self) -> f32 { - 0. + unimplemented!() } fn get_pitch(&self) -> Result { @@ -165,23 +168,27 @@ impl Backend for NSSpeechSynthesizerBackend { } fn min_volume(&self) -> f32 { - -100. - } - - fn max_volume(&self) -> f32 { - 100. - } - - fn normal_volume(&self) -> f32 { 0. } + fn max_volume(&self) -> f32 { + 1. + } + + fn normal_volume(&self) -> f32 { + 1. + } + fn get_volume(&self) -> Result { - unimplemented!() + let volume: f32 = unsafe { msg_send![self.0, volume] }; + Ok(volume) } fn set_volume(&mut self, volume: f32) -> Result<(), Error> { - unimplemented!() + unsafe { + let _: () = msg_send![self.0, setVolume: volume]; + } + Ok(()) } fn is_speaking(&self) -> Result {