Major tts-rs update.

* Initial WinRT driver, used when no Windows screen reader is detected.
 * Enhanced rate support, tracking min/max/normal rate per synthesizer.
 * `rate_percentage` properties make working with differing rate ranges easier.
This commit is contained in:
Nolan Darilek 2020-05-19 07:49:28 -05:00
parent 91faf9197c
commit 495c5eddad
3 changed files with 111 additions and 28 deletions

View File

@ -9,4 +9,4 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
gdnative = "0.8" gdnative = "0.8"
tts = "0.2" tts = { git = "https://gitlab.com/ndarilek/tts-rs" }

69
TTS.gd
View File

@ -17,13 +17,49 @@ func _ready():
else: else:
print_debug("TTS not available!") print_debug("TTS not available!")
func _get_min_rate():
if OS.has_feature('JavaScript'):
return 0.1
elif Engine.has_singleton("AndroidTTS"):
return 0.1
elif tts != null:
return tts.min_rate
else:
return 0
var min_rate setget , _get_min_rate
func _get_max_rate():
if OS.has_feature('JavaScript'):
return 10
elif Engine.has_singleton("AndroidTTS"):
return 10.0
elif tts != null:
return tts.max_rate
else:
return 0
var max_rate setget , _get_max_rate
func _get_normal_rate():
if OS.has_feature('JavaScript'):
return 1
elif Engine.has_singleton("AndroidTTS"):
return 1.0
elif tts != null:
return tts.normal_rate
else:
return 0
var normal_rate setget , _get_normal_rate
var javascript_rate = 50 var javascript_rate = 50
func set_rate(rate): func set_rate(rate):
if rate < 0: if rate < self.min_rate:
rate = 0 rate = self.min_rate
elif rate > 100: elif rate > self.max_rate:
rate = 100 rate = self.max_rate
if tts != null: if tts != null:
tts.rate = rate tts.rate = rate
elif OS.has_feature('JavaScript'): elif OS.has_feature('JavaScript'):
@ -39,20 +75,27 @@ func get_rate():
var rate setget set_rate, get_rate var rate setget set_rate, get_rate
func _get_rate_percentage():
return range_lerp(self.rate, self.min_rate, self.max_rate, 0, 100)
func _set_rate_percentage(v):
self.rate = range_lerp(v, 0, 100, self.min_rate, self.max_rate)
var rate_percentage setget _set_rate_percentage, _get_rate_percentage
func _get_normal_rate_percentage():
return range_lerp(self.normal_rate, self.min_rate, self.max_rate, 0, 100)
var normal_rate_percentage setget , _get_rate_percentage
func speak(text, interrupt := true): func speak(text, interrupt := true):
if tts != null: if tts != null:
tts.speak(text, interrupt) tts.speak(text, interrupt)
elif OS.has_feature('JavaScript'): elif OS.has_feature('JavaScript'):
var scaled_rate: float
if javascript_rate <= 50:
scaled_rate = javascript_rate / 50.0
else:
scaled_rate = javascript_rate - 50
scaled_rate = 1 + (scaled_rate / 5.0)
var code = """ var code = """
let utterance = new SpeechSynthesisUtterance("%s") let utterance = new SpeechSynthesisUtterance("%s")
utterance.rate = %s utterance.rate = %s
""" % [text.replace("\n", " "), scaled_rate] """ % [text.replace("\n", " "), javascript_rate]
if interrupt: if interrupt:
code += """ code += """
window.speechSynthesis.cancel() window.speechSynthesis.cancel()
@ -69,8 +112,8 @@ func stop():
JavaScript.eval("window.speechSynthesis.cancel()") JavaScript.eval("window.speechSynthesis.cancel()")
func get_is_rate_supported(): func get_is_rate_supported():
if Engine.get_singleton("AndroidTTS"): if Engine.has_singleton("AndroidTTS"):
return false return true
elif OS.has_feature('JavaScript'): elif OS.has_feature('JavaScript'):
return true return true
elif tts != null: elif tts != null:

View File

@ -1,5 +1,3 @@
use std::u8;
use gdnative::init::*; use gdnative::init::*;
use gdnative::*; use gdnative::*;
use tts::{Features, TTS as Tts}; use tts::{Features, TTS as Tts};
@ -18,27 +16,69 @@ impl TTS {
fn register_properties(builder: &ClassBuilder<Self>) { fn register_properties(builder: &ClassBuilder<Self>) {
builder builder
.add_property::<u8>("rate") .add_property("rate")
.with_default(50)
.with_getter(|this: &TTS, _| match this.0.get_rate() { .with_getter(|this: &TTS, _| match this.0.get_rate() {
Ok(rate) => rate / u8::MAX * 100, Ok(rate) => rate,
_ => 0, _ => 0.,
}) })
.with_setter(|this: &mut TTS, _, mut v: u8| { .with_setter(|this: &mut TTS, _, v: f32| {
if v > 100 {
v = 100;
}
let mut v = v as f32;
v = v * u8::MAX as f32 / 100.;
let Features { let Features {
rate: rate_supported, rate: rate_supported,
.. ..
} = this.0.supported_features(); } = this.0.supported_features();
if rate_supported { if rate_supported {
this.0.set_rate(v as u8).unwrap(); let mut v = v;
if v < this.0.min_rate() {
v = this.0.min_rate();
} else if v > this.0.max_rate() {
v = this.0.max_rate();
}
this.0.set_rate(v).unwrap();
} }
}) })
.done() .done();
builder
.add_property("min_rate")
.with_getter(|this: &TTS, _| {
let Features {
rate: rate_supported,
..
} = this.0.supported_features();
if rate_supported {
this.0.min_rate()
} else {
0.
}
})
.done();
builder
.add_property("max_rate")
.with_getter(|this: &TTS, _| {
let Features {
rate: rate_supported,
..
} = this.0.supported_features();
if rate_supported {
this.0.max_rate()
} else {
0.
}
})
.done();
builder
.add_property("normal_rate")
.with_getter(|this: &TTS, _| {
let Features {
rate: rate_supported,
..
} = this.0.supported_features();
if rate_supported {
this.0.normal_rate()
} else {
0.
}
})
.done();
} }
#[export] #[export]