-
Notifications
You must be signed in to change notification settings - Fork 7
/
TTS.gd
326 lines (225 loc) · 6.45 KB
/
TTS.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
tool
extends Node
signal utterance_begin(utterance)
signal utterance_end(utterance)
signal utterance_stop(utterance)
var TTS
var tts
func _init():
if OS.get_name() == "Server" or OS.has_feature("JavaScript"):
return
elif Engine.has_singleton("GodotTTS"):
tts = Engine.get_singleton("GodotTTS")
else:
TTS = preload("godot-tts.gdns")
if TTS and (TTS.can_instance() or Engine.editor_hint):
tts = TTS.new()
if tts:
if not tts is JNISingleton:
self.add_child(tts)
if self.are_utterance_callbacks_supported:
tts.connect("utterance_begin", self, "_on_utterance_begin")
tts.connect("utterance_end", self, "_on_utterance_end")
tts.connect("utterance_stop", self, "_on_utterance_stop")
else:
print_debug("TTS not available!")
func _ready():
pause_mode = Node.PAUSE_MODE_PROCESS
func _get_min_volume():
if OS.has_feature('JavaScript'):
return 0
else:
return 0
var min_volume setget , _get_min_volume
func _get_max_volume():
if OS.has_feature('JavaScript'):
return 1.0
else:
return 0
var max_volume setget , _get_max_volume
func _get_normal_volume():
if OS.has_feature('JavaScript'):
return 1.0
else:
return 0
var normal_volume setget , _get_normal_volume
var javascript_volume = self.normal_volume
func _set_volume(volume):
if volume < self.min_volume:
volume = self.min_volume
elif volume > self.max_volume:
volume = self.max_volume
if OS.has_feature('JavaScript'):
javascript_volume = volume
func _get_volume():
if OS.has_feature('JavaScript'):
return javascript_volume
else:
return 0
var volume setget _set_volume, _get_volume
func _get_volume_percentage():
return range_lerp(self.volume, self.min_volume, self.max_volume, 0, 100)
func _set_volume_percentage(v):
self.rate = range_lerp(v, 0, 100, self.min_volume, self.max_volume)
var volume_percentage setget _set_volume_percentage, _get_volume_percentage
func _get_normal_volume_percentage():
return range_lerp(self.normal_volume, self.min_volume, self.max_volume, 0, 100)
var normal_volume_percentage setget , _get_normal_volume_percentage
func _get_min_rate():
if OS.has_feature('JavaScript'):
return 0.1
elif Engine.has_singleton("GodotTTS"):
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.0
elif Engine.has_singleton("GodotTTS"):
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.0
elif Engine.has_singleton("GodotTTS"):
return 1.0
elif tts != null:
return tts.normal_rate
else:
return 0
var normal_rate setget , _get_normal_rate
var javascript_rate = self.normal_rate
func _set_rate(rate):
if rate < self.min_rate:
rate = self.min_rate
elif rate > self.max_rate:
rate = self.max_rate
if Engine.has_singleton("GodotTTS"):
return tts.set_rate(rate)
elif tts != null:
tts.rate = rate
elif OS.has_feature('JavaScript'):
javascript_rate = rate
func _get_rate():
if Engine.has_singleton("GodotTTS"):
return tts.get_rate()
elif tts != null:
return tts.rate
elif OS.has_feature('JavaScript'):
return javascript_rate
else:
return 0
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):
var utterance
if tts != null:
utterance = tts.speak(text, interrupt)
elif OS.has_feature('JavaScript'):
var code = (
"""
let utterance = new SpeechSynthesisUtterance("%s")
utterance.rate = %s
utterance.volume = %s
"""
% [text.replace("\n", " "), javascript_rate, javascript_volume]
)
if interrupt:
code += """
window.speechSynthesis.cancel()
"""
code += "window.speechSynthesis.speak(utterance)"
JavaScript.eval(code)
else:
print_debug("%s: %s" % [text, interrupt])
return utterance
func stop():
if tts != null:
tts.stop()
elif OS.has_feature('JavaScript'):
JavaScript.eval("window.speechSynthesis.cancel()")
func _get_is_rate_supported():
if Engine.has_singleton("GodotTTS"):
return true
elif OS.has_feature('JavaScript'):
return true
elif tts != null:
return tts.is_rate_supported()
else:
return false
var is_rate_supported setget , _get_is_rate_supported
func _get_are_utterance_callbacks_supported():
if Engine.has_singleton("GodotTTS"):
return true
elif OS.has_feature('JavaScript'):
return false
elif tts != null:
return tts.are_utterance_callbacks_supported()
else:
return false
var are_utterance_callbacks_supported setget , _get_are_utterance_callbacks_supported
func _get_can_detect_is_speaking():
if Engine.has_singleton("GodotTTS"):
return true
elif OS.has_feature('JavaScript'):
return true
elif tts != null:
return tts.can_detect_is_speaking
return false
var can_detect_is_speaking setget , _get_can_detect_is_speaking
func _get_is_speaking():
if Engine.has_singleton("GodotTTS"):
return tts.is_speaking()
elif OS.has_feature('JavaScript'):
return JavaScript.eval("window.speechSynthesis.speaking")
elif tts != null:
return tts.is_speaking
return false
var is_speaking setget , _get_is_speaking
func _get_can_detect_screen_reader():
if Engine.has_singleton("GodotTTS"):
return true
elif OS.has_feature('JavaScript'):
return false
elif tts != null:
return tts.can_detect_screen_reader
return false
var can_detect_screen_reader setget , _get_can_detect_screen_reader
func _get_has_screen_reader():
if Engine.has_singleton("GodotTTS"):
return tts.has_screen_reader()
elif OS.has_feature('JavaScript'):
return false
elif tts != null:
return tts.has_screen_reader
return false
var has_screen_reader setget , _get_has_screen_reader
func singular_or_plural(count, singular, plural):
if count == 1:
return singular
else:
return plural
func _on_utterance_begin(utterance):
emit_signal("utterance_begin", utterance)
func _on_utterance_end(utterance):
emit_signal("utterance_end", utterance)
func _on_utterance_stop(utterance):
emit_signal("utterance_stop", utterance)
func _exit_tree():
if not tts or not TTS:
return
tts.free()