2018-12-28 15:39:50 +00:00
|
|
|
/*!
|
|
|
|
* a Text-To-Speech (TTS) library providing high-level interfaces to a variety of backends.
|
2018-12-30 17:20:03 +00:00
|
|
|
* Currently supported backends are:
|
2020-05-18 20:01:28 +00:00
|
|
|
* * [Speech Dispatcher](https://freebsoft.org/speechd) (Linux)
|
|
|
|
* * Windows screen readers and SAPI via [Tolk](https://github.com/dkager/tolk/)
|
2018-12-30 17:20:03 +00:00
|
|
|
* * WebAssembly
|
2018-12-28 15:39:50 +00:00
|
|
|
*/
|
|
|
|
|
2018-12-14 19:35:49 +00:00
|
|
|
use std::boxed::Box;
|
2018-12-30 17:13:48 +00:00
|
|
|
|
2020-05-18 20:01:28 +00:00
|
|
|
use thiserror::Error;
|
2018-12-14 19:35:49 +00:00
|
|
|
|
|
|
|
mod backends;
|
|
|
|
|
|
|
|
pub enum Backends {
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
SpeechDispatcher,
|
2018-12-30 17:13:48 +00:00
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
Web,
|
2019-03-25 19:15:08 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
Tolk,
|
2020-05-18 20:01:28 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
WinRT,
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
|
|
|
|
2019-03-24 21:30:45 +00:00
|
|
|
pub struct Features {
|
2019-03-25 16:34:30 +00:00
|
|
|
pub stop: bool,
|
|
|
|
pub rate: bool,
|
|
|
|
pub pitch: bool,
|
|
|
|
pub volume: bool,
|
2020-06-02 19:53:14 +00:00
|
|
|
pub is_speaking: bool,
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
|
|
|
|
2020-05-18 20:01:28 +00:00
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum Error {
|
|
|
|
#[error("IO error: {0}")]
|
|
|
|
IO(#[from] std::io::Error),
|
2020-06-02 19:53:14 +00:00
|
|
|
#[error("Value not received")]
|
|
|
|
NoneError,
|
2020-06-02 19:57:21 +00:00
|
|
|
#[cfg(target_arch = "wasm32")]
|
2020-06-02 19:53:14 +00:00
|
|
|
#[error("JavaScript error: [0])]")]
|
|
|
|
JavaScriptError(wasm_bindgen::JsValue),
|
2020-05-18 20:01:28 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
#[error("WinRT error")]
|
|
|
|
WinRT(winrt::Error),
|
|
|
|
#[error("Unsupported feature")]
|
|
|
|
UnsupportedFeature,
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
#[error("Out of range")]
|
|
|
|
OutOfRange,
|
2020-05-18 20:01:28 +00:00
|
|
|
}
|
|
|
|
|
2019-03-24 21:30:45 +00:00
|
|
|
pub trait Backend {
|
|
|
|
fn supported_features(&self) -> Features;
|
2018-12-30 17:13:48 +00:00
|
|
|
fn speak(&self, text: &str, interrupt: bool) -> Result<(), Error>;
|
|
|
|
fn stop(&self) -> Result<(), Error>;
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
fn min_rate(&self) -> f32;
|
|
|
|
fn max_rate(&self) -> f32;
|
|
|
|
fn normal_rate(&self) -> f32;
|
|
|
|
fn get_rate(&self) -> Result<f32, Error>;
|
|
|
|
fn set_rate(&mut self, rate: f32) -> Result<(), Error>;
|
|
|
|
fn min_pitch(&self) -> f32;
|
|
|
|
fn max_pitch(&self) -> f32;
|
|
|
|
fn normal_pitch(&self) -> f32;
|
|
|
|
fn get_pitch(&self) -> Result<f32, Error>;
|
|
|
|
fn set_pitch(&mut self, pitch: f32) -> Result<(), Error>;
|
|
|
|
fn min_volume(&self) -> f32;
|
|
|
|
fn max_volume(&self) -> f32;
|
|
|
|
fn normal_volume(&self) -> f32;
|
|
|
|
fn get_volume(&self) -> Result<f32, Error>;
|
|
|
|
fn set_volume(&mut self, volume: f32) -> Result<(), Error>;
|
2020-06-02 19:53:14 +00:00
|
|
|
fn is_speaking(&self) -> Result<bool, Error>;
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
|
|
|
|
2019-09-30 15:36:20 +00:00
|
|
|
pub struct TTS(Box<dyn Backend>);
|
2018-12-14 19:35:49 +00:00
|
|
|
|
2019-01-03 17:20:04 +00:00
|
|
|
unsafe impl std::marker::Send for TTS {}
|
|
|
|
|
|
|
|
unsafe impl std::marker::Sync for TTS {}
|
|
|
|
|
2018-12-14 19:35:49 +00:00
|
|
|
impl TTS {
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Create a new `TTS` instance with the specified backend.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
2018-12-30 17:13:48 +00:00
|
|
|
pub fn new(backend: Backends) -> Result<TTS, Error> {
|
2018-12-14 19:35:49 +00:00
|
|
|
match backend {
|
|
|
|
#[cfg(target_os = "linux")]
|
2018-12-30 17:13:48 +00:00
|
|
|
Backends::SpeechDispatcher => Ok(TTS(Box::new(backends::SpeechDispatcher::new()))),
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
Backends::Web => {
|
|
|
|
let tts = backends::Web::new()?;
|
|
|
|
Ok(TTS(Box::new(tts)))
|
2019-01-03 16:16:54 +00:00
|
|
|
}
|
2019-03-25 19:15:08 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
Backends::Tolk => {
|
|
|
|
let tts = backends::Tolk::new();
|
|
|
|
Ok(TTS(Box::new(tts)))
|
2019-12-23 13:37:48 +00:00
|
|
|
}
|
2020-05-18 20:01:28 +00:00
|
|
|
#[cfg(windows)]
|
|
|
|
Backends::WinRT => {
|
|
|
|
let tts = backends::winrt::WinRT::new()?;
|
|
|
|
Ok(TTS(Box::new(tts)))
|
|
|
|
}
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-30 17:13:48 +00:00
|
|
|
pub fn default() -> Result<TTS, Error> {
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
let tts = TTS::new(Backends::SpeechDispatcher);
|
2019-03-25 19:15:08 +00:00
|
|
|
#[cfg(windows)]
|
2020-05-18 20:01:28 +00:00
|
|
|
let tts = {
|
|
|
|
let tolk = tolk::Tolk::new();
|
|
|
|
if tolk.detect_screen_reader().is_some() {
|
|
|
|
TTS::new(Backends::Tolk)
|
|
|
|
} else {
|
|
|
|
TTS::new(Backends::WinRT)
|
|
|
|
}
|
|
|
|
};
|
2018-12-30 17:13:48 +00:00
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
|
|
let tts = TTS::new(Backends::Web);
|
|
|
|
tts
|
|
|
|
}
|
|
|
|
|
2019-03-24 21:30:45 +00:00
|
|
|
/**
|
|
|
|
* Returns the features supported by this TTS engine
|
|
|
|
*/
|
|
|
|
pub fn supported_features(&self) -> Features {
|
|
|
|
self.0.supported_features()
|
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Speaks the specified text, optionally interrupting current speech.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
2018-12-30 17:13:48 +00:00
|
|
|
pub fn speak<S: Into<String>>(&self, text: S, interrupt: bool) -> Result<&Self, Error> {
|
|
|
|
self.0.speak(text.into().as_str(), interrupt)?;
|
|
|
|
Ok(self)
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Stops current speech.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
2018-12-30 17:13:48 +00:00
|
|
|
pub fn stop(&self) -> Result<&Self, Error> {
|
2019-03-24 21:30:45 +00:00
|
|
|
let Features { stop, .. } = self.supported_features();
|
|
|
|
if stop {
|
|
|
|
self.0.stop()?;
|
|
|
|
Ok(self)
|
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-28 14:49:02 +00:00
|
|
|
}
|
|
|
|
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the minimum rate for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn min_rate(&self) -> f32 {
|
|
|
|
self.0.min_rate()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the maximum rate for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn max_rate(&self) -> f32 {
|
|
|
|
self.0.max_rate()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the normal rate for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn normal_rate(&self) -> f32 {
|
|
|
|
self.0.normal_rate()
|
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Gets the current speech rate.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
pub fn get_rate(&self) -> Result<f32, Error> {
|
2019-03-24 21:30:45 +00:00
|
|
|
let Features { rate, .. } = self.supported_features();
|
|
|
|
if rate {
|
|
|
|
self.0.get_rate()
|
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Sets the desired speech rate.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
pub fn set_rate(&mut self, rate: f32) -> Result<&Self, Error> {
|
2019-03-25 16:34:30 +00:00
|
|
|
let Features {
|
|
|
|
rate: rate_feature, ..
|
|
|
|
} = self.supported_features();
|
2019-03-24 21:30:45 +00:00
|
|
|
if rate_feature {
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
if rate < self.0.min_rate() || rate > self.0.max_rate() {
|
|
|
|
Err(Error::OutOfRange)
|
|
|
|
} else {
|
|
|
|
self.0.set_rate(rate)?;
|
|
|
|
Ok(self)
|
|
|
|
}
|
2019-03-24 21:30:45 +00:00
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
2018-12-15 15:56:13 +00:00
|
|
|
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the minimum pitch for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn min_pitch(&self) -> f32 {
|
|
|
|
self.0.min_pitch()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the maximum pitch for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn max_pitch(&self) -> f32 {
|
|
|
|
self.0.max_pitch()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the normal pitch for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn normal_pitch(&self) -> f32 {
|
|
|
|
self.0.normal_pitch()
|
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Gets the current speech pitch.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
pub fn get_pitch(&self) -> Result<f32, Error> {
|
2019-03-24 21:30:45 +00:00
|
|
|
let Features { pitch, .. } = self.supported_features();
|
|
|
|
if pitch {
|
|
|
|
self.0.get_pitch()
|
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-15 15:56:13 +00:00
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Sets the desired speech pitch.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
pub fn set_pitch(&mut self, pitch: f32) -> Result<&Self, Error> {
|
2019-03-25 16:34:30 +00:00
|
|
|
let Features {
|
|
|
|
pitch: pitch_feature,
|
|
|
|
..
|
|
|
|
} = self.supported_features();
|
2019-03-24 21:30:45 +00:00
|
|
|
if pitch_feature {
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
if pitch < self.0.min_pitch() || pitch > self.0.max_pitch() {
|
|
|
|
Err(Error::OutOfRange)
|
|
|
|
} else {
|
|
|
|
self.0.set_pitch(pitch)?;
|
|
|
|
Ok(self)
|
|
|
|
}
|
2019-03-24 21:30:45 +00:00
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-15 15:56:13 +00:00
|
|
|
}
|
|
|
|
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
/**
|
|
|
|
* Returns the minimum volume for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn min_volume(&self) -> f32 {
|
|
|
|
self.0.min_volume()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the maximum volume for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn max_volume(&self) -> f32 {
|
|
|
|
self.0.max_volume()
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the normal volume for this speech synthesizer.
|
|
|
|
*/
|
|
|
|
pub fn normal_volume(&self) -> f32 {
|
|
|
|
self.0.normal_volume()
|
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Gets the current speech volume.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
pub fn get_volume(&self) -> Result<f32, Error> {
|
2019-03-24 21:30:45 +00:00
|
|
|
let Features { volume, .. } = self.supported_features();
|
|
|
|
if volume {
|
|
|
|
self.0.get_volume()
|
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-15 15:56:13 +00:00
|
|
|
}
|
|
|
|
|
2018-12-28 15:39:50 +00:00
|
|
|
/**
|
|
|
|
* Sets the desired speech volume.
|
2019-01-03 16:16:54 +00:00
|
|
|
*/
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
pub fn set_volume(&mut self, volume: f32) -> Result<&Self, Error> {
|
2019-03-25 16:34:30 +00:00
|
|
|
let Features {
|
|
|
|
volume: volume_feature,
|
|
|
|
..
|
|
|
|
} = self.supported_features();
|
2019-03-24 21:30:45 +00:00
|
|
|
if volume_feature {
|
Clean up speech synthesis properties, and implement everything for WinRT.
I'd previously attempted to normalize everything to `u8`, but this had some drawbacks:
* It failed to account for some synthesis drivers defining normal as mid-range, while most define it very low.
* It didn't track the normal value for a given synthesizer.
* There was no clean way to map a curve between the minimum, normal, and maximum rates.
Here we track the minimum, normal, and maximum values of rate, pitch, and volume. Sanity checks are done on set.
Also, as a further proof-of-concept, all properties are now implemented for the WinRT driver.
2020-05-18 23:12:59 +00:00
|
|
|
if volume < self.0.min_volume() || volume > self.0.max_volume() {
|
|
|
|
Err(Error::OutOfRange)
|
|
|
|
} else {
|
|
|
|
self.0.set_volume(volume)?;
|
|
|
|
Ok(self)
|
|
|
|
}
|
2019-03-24 21:30:45 +00:00
|
|
|
} else {
|
2020-05-18 20:01:28 +00:00
|
|
|
Err(Error::UnsupportedFeature)
|
2019-03-24 21:30:45 +00:00
|
|
|
}
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|
2020-06-02 19:53:14 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether this speech synthesizer is speaking.
|
|
|
|
*/
|
|
|
|
pub fn is_speaking(&self) -> Result<bool, Error> {
|
|
|
|
let Features { is_speaking, .. } = self.supported_features();
|
|
|
|
if is_speaking {
|
|
|
|
self.0.is_speaking()
|
|
|
|
} else {
|
|
|
|
Err(Error::UnsupportedFeature)
|
|
|
|
}
|
|
|
|
}
|
2018-12-14 19:35:49 +00:00
|
|
|
}
|