mirror of
https://github.com/ndarilek/tts-rs.git
synced 2024-11-23 03:59:37 +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.
This commit is contained in:
parent
3198a537f0
commit
7b4fb8dae4
|
@ -1,5 +1,4 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::u8;
|
|
||||||
|
|
||||||
use tts::*;
|
use tts::*;
|
||||||
|
|
||||||
|
@ -11,28 +10,34 @@ fn main() -> Result<(), Error> {
|
||||||
if rate {
|
if rate {
|
||||||
let original_rate = tts.get_rate()?;
|
let original_rate = tts.get_rate()?;
|
||||||
tts.speak(format!("Current rate: {}", original_rate), false)?;
|
tts.speak(format!("Current rate: {}", original_rate), false)?;
|
||||||
tts.set_rate(u8::MAX)?;
|
tts.set_rate(tts.max_rate())?;
|
||||||
tts.speak("This is very fast.", false)?;
|
tts.speak("This is very fast.", false)?;
|
||||||
tts.set_rate(0)?;
|
tts.set_rate(tts.min_rate())?;
|
||||||
tts.speak("This is very slow.", false)?;
|
tts.speak("This is very slow.", false)?;
|
||||||
|
tts.set_rate(tts.normal_rate())?;
|
||||||
|
tts.speak("This is the normal rate.", false)?;
|
||||||
tts.set_rate(original_rate)?;
|
tts.set_rate(original_rate)?;
|
||||||
}
|
}
|
||||||
let Features { pitch, .. } = tts.supported_features();
|
let Features { pitch, .. } = tts.supported_features();
|
||||||
if pitch {
|
if pitch {
|
||||||
let original_pitch = tts.get_pitch()?;
|
let original_pitch = tts.get_pitch()?;
|
||||||
tts.set_pitch(u8::MAX)?;
|
tts.set_pitch(tts.max_pitch())?;
|
||||||
tts.speak("This is high-pitch.", false)?;
|
tts.speak("This is high-pitch.", false)?;
|
||||||
tts.set_pitch(0)?;
|
tts.set_pitch(tts.min_pitch())?;
|
||||||
tts.speak("This is low pitch.", false)?;
|
tts.speak("This is low pitch.", false)?;
|
||||||
|
tts.set_pitch(tts.normal_pitch())?;
|
||||||
|
tts.speak("This is normal pitch.", false)?;
|
||||||
tts.set_pitch(original_pitch)?;
|
tts.set_pitch(original_pitch)?;
|
||||||
}
|
}
|
||||||
let Features { volume, .. } = tts.supported_features();
|
let Features { volume, .. } = tts.supported_features();
|
||||||
if volume {
|
if volume {
|
||||||
let original_volume = tts.get_volume()?;
|
let original_volume = tts.get_volume()?;
|
||||||
tts.set_volume(u8::MAX)?;
|
tts.set_volume(tts.max_volume())?;
|
||||||
tts.speak("This is loud!", false)?;
|
tts.speak("This is loud!", false)?;
|
||||||
tts.set_volume(0)?;
|
tts.set_volume(tts.min_volume())?;
|
||||||
tts.speak("This is quiet.", false)?;
|
tts.speak("This is quiet.", false)?;
|
||||||
|
tts.set_volume(tts.normal_volume())?;
|
||||||
|
tts.speak("This is normal volume.", false)?;
|
||||||
tts.set_volume(original_volume)?;
|
tts.set_volume(original_volume)?;
|
||||||
}
|
}
|
||||||
tts.speak("Goodbye.", false)?;
|
tts.speak("Goodbye.", false)?;
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use std::u8;
|
|
||||||
|
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use speech_dispatcher::*;
|
use speech_dispatcher::*;
|
||||||
|
|
||||||
|
@ -16,18 +14,6 @@ impl SpeechDispatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn u8_to_i32(v: u8) -> i32 {
|
|
||||||
let ratio: f32 = v as f32 / u8::MAX as f32;
|
|
||||||
(ratio * 200. - 100.) as i32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn i32_to_u8(v: i32) -> u8 {
|
|
||||||
let v = v as f32;
|
|
||||||
let ratio: f32 = (v + 100.) / 200.;
|
|
||||||
let v = ratio * u8::MAX as f32;
|
|
||||||
v as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Backend for SpeechDispatcher {
|
impl Backend for SpeechDispatcher {
|
||||||
fn supported_features(&self) -> Features {
|
fn supported_features(&self) -> Features {
|
||||||
Features {
|
Features {
|
||||||
|
@ -60,30 +46,66 @@ impl Backend for SpeechDispatcher {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rate(&self) -> Result<u8, Error> {
|
fn min_rate(&self) -> f32 {
|
||||||
Ok(i32_to_u8(self.0.get_voice_rate()))
|
-100.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_rate(&mut self, rate: u8) -> Result<(), Error> {
|
fn max_rate(&self) -> f32 {
|
||||||
self.0.set_voice_rate(u8_to_i32(rate));
|
100.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_rate(&self) -> f32 {
|
||||||
|
0.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rate(&self) -> Result<f32, Error> {
|
||||||
|
Ok(self.0.get_voice_rate() as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_rate(&mut self, rate: f32) -> Result<(), Error> {
|
||||||
|
self.0.set_voice_rate(rate as i32);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pitch(&self) -> Result<u8, Error> {
|
fn min_pitch(&self) -> f32 {
|
||||||
Ok(i32_to_u8(self.0.get_voice_pitch()))
|
-100.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pitch(&mut self, pitch: u8) -> Result<(), Error> {
|
fn max_pitch(&self) -> f32 {
|
||||||
self.0.set_voice_pitch(u8_to_i32(pitch));
|
100.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_pitch(&self) -> f32 {
|
||||||
|
0.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pitch(&self) -> Result<f32, Error> {
|
||||||
|
Ok(self.0.get_voice_pitch() as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_pitch(&mut self, pitch: f32) -> Result<(), Error> {
|
||||||
|
self.0.set_voice_pitch(pitch as i32);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_volume(&self) -> Result<u8, Error> {
|
fn min_volume(&self) -> f32 {
|
||||||
Ok(i32_to_u8(self.0.get_volume()))
|
-100.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_volume(&mut self, volume: u8) -> Result<(), Error> {
|
fn max_volume(&self) -> f32 {
|
||||||
self.0.set_volume(u8_to_i32(volume));
|
100.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_volume(&self) -> f32 {
|
||||||
|
0.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_volume(&self) -> Result<f32, Error> {
|
||||||
|
Ok(self.0.get_volume() as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_volume(&mut self, volume: f32) -> Result<(), Error> {
|
||||||
|
self.0.set_volume(volume as i32);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,27 +37,63 @@ impl Backend for Tolk {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rate(&self) -> Result<u8, Error> {
|
fn min_rate(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_rate(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_rate(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rate(&self) -> Result<f32, Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_rate(&mut self, _rate: u8) -> Result<(), Error> {
|
fn set_rate(&mut self, _rate: f32) -> Result<(), Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pitch(&self) -> Result<u8, Error> {
|
fn min_pitch(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_pitch(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_pitch(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pitch(&self) -> Result<f32, Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pitch(&mut self, _pitch: u8) -> Result<(), Error> {
|
fn set_pitch(&mut self, _pitch: f32) -> Result<(), Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_volume(&self) -> Result<u8, Error> {
|
fn min_volume(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_volume(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_volume(&self) -> f32 {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_volume(&self) -> Result<f32, Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_volume(&mut self, _volume: u8) -> Result<(), Error> {
|
fn set_volume(&mut self, _volume: f32) -> Result<(), Error> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use std::u8;
|
|
||||||
|
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use web_sys::SpeechSynthesisUtterance;
|
use web_sys::SpeechSynthesisUtterance;
|
||||||
|
|
||||||
use crate::{Backend, Error};
|
use crate::{Backend, Error, Features};
|
||||||
|
|
||||||
pub struct Web {
|
pub struct Web {
|
||||||
rate: u8,
|
rate: f32,
|
||||||
pitch: u8,
|
pitch: f32,
|
||||||
volume: u8,
|
volume: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Web {
|
impl Web {
|
||||||
pub fn new() -> Result<Self, Error> {
|
pub fn new() -> Result<Self, Error> {
|
||||||
info!("Initializing Web backend");
|
info!("Initializing Web backend");
|
||||||
Ok(Web {
|
Ok(Web {
|
||||||
rate: 25,
|
rate: 1.,
|
||||||
pitch: 127,
|
pitch: 1.,
|
||||||
volume: u8::MAX,
|
volume: 1.,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,15 +34,9 @@ impl Backend for Web {
|
||||||
fn speak(&self, text: &str, interrupt: bool) -> Result<(), Error> {
|
fn speak(&self, text: &str, interrupt: bool) -> Result<(), Error> {
|
||||||
trace!("speak({}, {})", text, interrupt);
|
trace!("speak({}, {})", text, interrupt);
|
||||||
let utterance = SpeechSynthesisUtterance::new_with_text(text).unwrap();
|
let utterance = SpeechSynthesisUtterance::new_with_text(text).unwrap();
|
||||||
let mut rate: f32 = self.rate as f32;
|
utterance.set_rate(self.rate);
|
||||||
rate = rate / u8::MAX as f32 * 10.;
|
utterance.set_pitch(self.pitch);
|
||||||
utterance.set_rate(rate);
|
utterance.set_volume(self.volume);
|
||||||
let mut pitch: f32 = self.pitch as f32;
|
|
||||||
pitch = pitch / u8::MAX as f32 * 2.;
|
|
||||||
utterance.set_pitch(pitch);
|
|
||||||
let mut volume: f32 = self.volume as f32;
|
|
||||||
volume = volume / u8::MAX as f32 * 1.;
|
|
||||||
utterance.set_volume(volume);
|
|
||||||
if interrupt {
|
if interrupt {
|
||||||
self.stop()?;
|
self.stop()?;
|
||||||
}
|
}
|
||||||
|
@ -64,29 +56,65 @@ impl Backend for Web {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rate(&self) -> Result<u8, Error> {
|
fn min_rate(&self) -> f32 {
|
||||||
|
0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_rate(&self) -> f32 {
|
||||||
|
10.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_rate(&self) -> f32 {
|
||||||
|
1.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rate(&self) -> Result<f32, Error> {
|
||||||
Ok(self.rate)
|
Ok(self.rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_rate(&mut self, rate: u8) -> Result<(), Error> {
|
fn set_rate(&mut self, rate: f32) -> Result<(), Error> {
|
||||||
self.rate = rate;
|
self.rate = rate;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pitch(&self) -> Result<u8, Error> {
|
fn min_pitch(&self) -> f32 {
|
||||||
|
0.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_pitch(&self) -> f32 {
|
||||||
|
2.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_pitch(&self) -> f32 {
|
||||||
|
1.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pitch(&self) -> Result<f32, Error> {
|
||||||
Ok(self.pitch)
|
Ok(self.pitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pitch(&mut self, pitch: u8) -> Result<(), Error> {
|
fn set_pitch(&mut self, pitch: f32) -> Result<(), Error> {
|
||||||
self.pitch = pitch;
|
self.pitch = pitch;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_volume(&self) -> Result<u8, Error> {
|
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)
|
Ok(self.volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_volume(&mut self, volume: u8) -> Result<(), Error> {
|
fn set_volume(&mut self, volume: f32) -> Result<(), Error> {
|
||||||
self.volume = volume;
|
self.volume = volume;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,9 @@ impl Backend for WinRT {
|
||||||
fn supported_features(&self) -> Features {
|
fn supported_features(&self) -> Features {
|
||||||
Features {
|
Features {
|
||||||
stop: true,
|
stop: true,
|
||||||
rate: false,
|
rate: true,
|
||||||
pitch: false,
|
pitch: true,
|
||||||
volume: false,
|
volume: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,27 +71,69 @@ impl Backend for WinRT {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rate(&self) -> std::result::Result<u8, Error> {
|
fn min_rate(&self) -> f32 {
|
||||||
unimplemented!();
|
0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_rate(&mut self, _rate: u8) -> std::result::Result<(), Error> {
|
fn max_rate(&self) -> f32 {
|
||||||
unimplemented!();
|
6.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pitch(&self) -> std::result::Result<u8, Error> {
|
fn normal_rate(&self) -> f32 {
|
||||||
unimplemented!();
|
1.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pitch(&mut self, _pitch: u8) -> std::result::Result<(), Error> {
|
fn get_rate(&self) -> std::result::Result<f32, Error> {
|
||||||
unimplemented!();
|
let rate = self.synth.options()?.speaking_rate()?;
|
||||||
|
Ok(rate as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_volume(&self) -> std::result::Result<u8, Error> {
|
fn set_rate(&mut self, rate: f32) -> std::result::Result<(), Error> {
|
||||||
unimplemented!();
|
self.synth.options()?.set_speaking_rate(rate.into())?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_volume(&mut self, _volume: u8) -> std::result::Result<(), Error> {
|
fn min_pitch(&self) -> f32 {
|
||||||
unimplemented!();
|
0.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_pitch(&self) -> f32 {
|
||||||
|
2.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_pitch(&self) -> f32 {
|
||||||
|
1.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pitch(&self) -> std::result::Result<f32, Error> {
|
||||||
|
let pitch = self.synth.options()?.audio_pitch()?;
|
||||||
|
Ok(pitch as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_pitch(&mut self, pitch: f32) -> std::result::Result<(), Error> {
|
||||||
|
self.synth.options()?.set_audio_pitch(pitch.into())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn min_volume(&self) -> f32 {
|
||||||
|
0.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_volume(&self) -> f32 {
|
||||||
|
1.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normal_volume(&self) -> f32 {
|
||||||
|
1.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_volume(&self) -> std::result::Result<f32, Error> {
|
||||||
|
let volume = self.synth.options()?.audio_volume()?;
|
||||||
|
Ok(volume as f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_volume(&mut self, volume: f32) -> std::result::Result<(), Error> {
|
||||||
|
self.synth.options()?.set_audio_volume(volume.into())?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
122
src/lib.rs
122
src/lib.rs
|
@ -39,18 +39,29 @@ pub enum Error {
|
||||||
WinRT(winrt::Error),
|
WinRT(winrt::Error),
|
||||||
#[error("Unsupported feature")]
|
#[error("Unsupported feature")]
|
||||||
UnsupportedFeature,
|
UnsupportedFeature,
|
||||||
|
#[error("Out of range")]
|
||||||
|
OutOfRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Backend {
|
pub trait Backend {
|
||||||
fn supported_features(&self) -> Features;
|
fn supported_features(&self) -> Features;
|
||||||
fn speak(&self, text: &str, interrupt: bool) -> Result<(), Error>;
|
fn speak(&self, text: &str, interrupt: bool) -> Result<(), Error>;
|
||||||
fn stop(&self) -> Result<(), Error>;
|
fn stop(&self) -> Result<(), Error>;
|
||||||
fn get_rate(&self) -> Result<u8, Error>;
|
fn min_rate(&self) -> f32;
|
||||||
fn set_rate(&mut self, rate: u8) -> Result<(), Error>;
|
fn max_rate(&self) -> f32;
|
||||||
fn get_pitch(&self) -> Result<u8, Error>;
|
fn normal_rate(&self) -> f32;
|
||||||
fn set_pitch(&mut self, pitch: u8) -> Result<(), Error>;
|
fn get_rate(&self) -> Result<f32, Error>;
|
||||||
fn get_volume(&self) -> Result<u8, Error>;
|
fn set_rate(&mut self, rate: f32) -> Result<(), Error>;
|
||||||
fn set_volume(&mut self, volume: u8) -> 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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TTS(Box<dyn Backend>);
|
pub struct TTS(Box<dyn Backend>);
|
||||||
|
@ -130,10 +141,31 @@ impl TTS {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current speech rate.
|
* Gets the current speech rate.
|
||||||
*/
|
*/
|
||||||
pub fn get_rate(&self) -> Result<u8, Error> {
|
pub fn get_rate(&self) -> Result<f32, Error> {
|
||||||
let Features { rate, .. } = self.supported_features();
|
let Features { rate, .. } = self.supported_features();
|
||||||
if rate {
|
if rate {
|
||||||
self.0.get_rate()
|
self.0.get_rate()
|
||||||
|
@ -145,22 +177,47 @@ impl TTS {
|
||||||
/**
|
/**
|
||||||
* Sets the desired speech rate.
|
* Sets the desired speech rate.
|
||||||
*/
|
*/
|
||||||
pub fn set_rate(&mut self, rate: u8) -> Result<&Self, Error> {
|
pub fn set_rate(&mut self, rate: f32) -> Result<&Self, Error> {
|
||||||
let Features {
|
let Features {
|
||||||
rate: rate_feature, ..
|
rate: rate_feature, ..
|
||||||
} = self.supported_features();
|
} = self.supported_features();
|
||||||
if rate_feature {
|
if rate_feature {
|
||||||
self.0.set_rate(rate)?;
|
if rate < self.0.min_rate() || rate > self.0.max_rate() {
|
||||||
Ok(self)
|
Err(Error::OutOfRange)
|
||||||
|
} else {
|
||||||
|
self.0.set_rate(rate)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnsupportedFeature)
|
Err(Error::UnsupportedFeature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current speech pitch.
|
* Gets the current speech pitch.
|
||||||
*/
|
*/
|
||||||
pub fn get_pitch(&self) -> Result<u8, Error> {
|
pub fn get_pitch(&self) -> Result<f32, Error> {
|
||||||
let Features { pitch, .. } = self.supported_features();
|
let Features { pitch, .. } = self.supported_features();
|
||||||
if pitch {
|
if pitch {
|
||||||
self.0.get_pitch()
|
self.0.get_pitch()
|
||||||
|
@ -172,23 +229,48 @@ impl TTS {
|
||||||
/**
|
/**
|
||||||
* Sets the desired speech pitch.
|
* Sets the desired speech pitch.
|
||||||
*/
|
*/
|
||||||
pub fn set_pitch(&mut self, pitch: u8) -> Result<&Self, Error> {
|
pub fn set_pitch(&mut self, pitch: f32) -> Result<&Self, Error> {
|
||||||
let Features {
|
let Features {
|
||||||
pitch: pitch_feature,
|
pitch: pitch_feature,
|
||||||
..
|
..
|
||||||
} = self.supported_features();
|
} = self.supported_features();
|
||||||
if pitch_feature {
|
if pitch_feature {
|
||||||
self.0.set_pitch(pitch)?;
|
if pitch < self.0.min_pitch() || pitch > self.0.max_pitch() {
|
||||||
Ok(self)
|
Err(Error::OutOfRange)
|
||||||
|
} else {
|
||||||
|
self.0.set_pitch(pitch)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnsupportedFeature)
|
Err(Error::UnsupportedFeature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current speech volume.
|
* Gets the current speech volume.
|
||||||
*/
|
*/
|
||||||
pub fn get_volume(&self) -> Result<u8, Error> {
|
pub fn get_volume(&self) -> Result<f32, Error> {
|
||||||
let Features { volume, .. } = self.supported_features();
|
let Features { volume, .. } = self.supported_features();
|
||||||
if volume {
|
if volume {
|
||||||
self.0.get_volume()
|
self.0.get_volume()
|
||||||
|
@ -200,14 +282,18 @@ impl TTS {
|
||||||
/**
|
/**
|
||||||
* Sets the desired speech volume.
|
* Sets the desired speech volume.
|
||||||
*/
|
*/
|
||||||
pub fn set_volume(&mut self, volume: u8) -> Result<&Self, Error> {
|
pub fn set_volume(&mut self, volume: f32) -> Result<&Self, Error> {
|
||||||
let Features {
|
let Features {
|
||||||
volume: volume_feature,
|
volume: volume_feature,
|
||||||
..
|
..
|
||||||
} = self.supported_features();
|
} = self.supported_features();
|
||||||
if volume_feature {
|
if volume_feature {
|
||||||
self.0.set_volume(volume)?;
|
if volume < self.0.min_volume() || volume > self.0.max_volume() {
|
||||||
Ok(self)
|
Err(Error::OutOfRange)
|
||||||
|
} else {
|
||||||
|
self.0.set_volume(volume)?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnsupportedFeature)
|
Err(Error::UnsupportedFeature)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user