From 8479340f52554cfafabba57be045eeae397b0dd8 Mon Sep 17 00:00:00 2001
From: bruvzg <7645683+bruvzg@users.noreply.github.com>
Date: Mon, 22 May 2023 16:41:09 +0300
Subject: [PATCH] Add audio/general/text_to_speech project setting to
enable/disable TTS.
---
core/config/project_settings.cpp | 2 +
doc/classes/OS.xml | 9 ++++
doc/classes/ProjectSettings.xml | 4 ++
.../pandemonium/Pandemonium.java | 7 ++--
.../pandemonium/PandemoniumLib.java | 4 +-
.../pandemonium/tts/PandemoniumTTS.java | 20 ++++++---
platform/android/java_pandemonium_lib_jni.cpp | 8 ++--
platform/android/tts_android.cpp | 41 ++++++++++++++-----
platform/android/tts_android.h | 3 ++
platform/iphone/os_iphone.mm | 12 +++++-
platform/javascript/os_javascript.cpp | 10 +++++
platform/javascript/os_javascript.h | 1 +
platform/osx/os_osx.mm | 12 +++++-
platform/windows/os_windows.cpp | 12 +++++-
platform/x11/os_x11.cpp | 16 +++++++-
15 files changed, 131 insertions(+), 30 deletions(-)
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 09ed90b1c..9db9935de 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1080,6 +1080,8 @@ ProjectSettings::ProjectSettings() {
ProjectSettings::get_singleton()->set_custom_property_info("audio/general/ios/session_category", PropertyInfo(Variant::INT, "audio/general/ios/session_category", PROPERTY_HINT_ENUM, "Ambient,Multi Route,Play and Record,Playback,Record,Solo Ambient"));
GLOBAL_DEF("audio/general/ios/mix_with_others", false);
+ GLOBAL_DEF_RST("audio/general/text_to_speech", false);
+
PoolStringArray extensions = PoolStringArray();
extensions.push_back("gd");
extensions.push_back("gdshader");
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 161d942c1..1a0c0aad0 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -1131,6 +1131,7 @@
- [code]id[/code] is voice identifier.
- [code]language[/code] is language code in [code]lang_Variant[/code] format. [code]lang[/code] part is a 2 or 3-letter code based on the ISO-639 standard, in lowercase. And [code]Variant[/code] part is an engine dependent string describing country, region or/and dialect.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1139,6 +1140,7 @@
Returns an [PoolStringArray] of voice identifiers for the [code]language[/code].
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1146,6 +1148,7 @@
Returns [code]true[/code] if the synthesizer is in a paused state.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1153,6 +1156,7 @@
Returns [code]true[/code] if the synthesizer is generating speech, or have utterance waiting in the queue.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1160,6 +1164,7 @@
Puts the synthesizer into a paused state.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1167,6 +1172,7 @@
Resumes the synthesizer if it was paused.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1180,6 +1186,7 @@
- [code]TTS_UTTERANCE_BOUNDARY[/code] callable's method should take two [int] parameters, the index of the character and the utterance id.
[b]Note:[/b] The granularity of the boundary callbacks is engine dependent.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1201,6 +1208,7 @@
[b]Note:[/b] On Windows and Linux, utterance [code]text[/code] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak].
[b]Note:[/b] The granularity of pitch, rate, and volume is engine and voice dependent. Values may be truncated.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
@@ -1208,6 +1216,7 @@
Stops synthesis in progress and removes all utterances from the queue.
[b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] [member ProjectSettings.audio/general/text_to_speech] should be [code]true[/code] to use text-to-speech.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index be3c26bb4..8ccfe1afa 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -303,6 +303,10 @@
Sets the [url=https://developer.apple.com/documentation/avfaudio/avaudiosessioncategory]AVAudioSessionCategory[/url] on iOS. Use the [code]Playback[/code] category to get sound output, even if the phone is in silent mode.
+
+ If [code]true[/code], text-to-speech support is enabled, see [method OS.tts_get_voices] and [method OS.tts_speak].
+ [b]Note:[/b] Enabling TTS can cause addition idle CPU usage and interfere with the sleep mode, so consider disabling it if TTS is not used.
+
The mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system.
diff --git a/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/Pandemonium.java b/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/Pandemonium.java
index d823d2a73..9f43461f8 100644
--- a/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/Pandemonium.java
+++ b/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/Pandemonium.java
@@ -457,7 +457,9 @@ public class Pandemonium extends Fragment implements SensorEventListener, IDownl
final String[] current_command_line = command_line;
mView.queueEvent(() -> {
- if (!PandemoniumLib.setup(current_command_line)) {
+ tts = new PandemoniumTTS(activity);
+
+ if (!PandemoniumLib.setup(current_command_line, tts)) {
pandemonium_initialized = false;
Log.e(TAG, "Unable to setup the Pandemonium engine! Aborting...");
alert(R.string.error_engine_setup_message, R.string.text_error_title, this::forceQuit);
@@ -711,7 +713,6 @@ public class Pandemonium extends Fragment implements SensorEventListener, IDownl
final Activity activity = getActivity();
io = new PandemoniumIO(activity);
netUtils = new PandemoniumNetUtils(activity);
- tts = new PandemoniumTTS(activity);
Context context = getContext();
directoryAccessHandler = new DirectoryAccessHandler(context);
@@ -723,7 +724,7 @@ public class Pandemonium extends Fragment implements SensorEventListener, IDownl
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
- PandemoniumLib.initialize(activity, this, activity.getAssets(), io, netUtils, directoryAccessHandler, fileAccessHandler, use_apk_expansion, tts);
+ PandemoniumLib.initialize(activity, this, activity.getAssets(), io, netUtils, directoryAccessHandler, fileAccessHandler, use_apk_expansion);
result_callback = null;
diff --git a/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/PandemoniumLib.java b/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/PandemoniumLib.java
index a3188937d..878d5e2d4 100644
--- a/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/PandemoniumLib.java
+++ b/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/PandemoniumLib.java
@@ -53,7 +53,7 @@ public class PandemoniumLib {
/**
* Invoked on the main thread to initialize Pandemonium native layer.
*/
- public static native void initialize(Activity activity, Pandemonium p_instance, AssetManager p_asset_manager, PandemoniumIO pandemoniumIO, PandemoniumNetUtils netUtils, DirectoryAccessHandler directoryAccessHandler, FileAccessHandler fileAccessHandler, boolean use_apk_expansion, GodotTTS tts);
+ public static native void initialize(Activity activity, Pandemonium p_instance, AssetManager p_asset_manager, PandemoniumIO pandemoniumIO, PandemoniumNetUtils netUtils, DirectoryAccessHandler directoryAccessHandler, FileAccessHandler fileAccessHandler, boolean use_apk_expansion);
/**
* Invoked on the main thread to clean up Pandemonium native layer.
@@ -65,7 +65,7 @@ public class PandemoniumLib {
* Invoked on the GL thread to complete setup for the Pandemonium native layer logic.
* @param p_cmdline Command line arguments used to configure Pandemonium native layer components.
*/
- public static native boolean setup(String[] p_cmdline);
+ public static native boolean setup(String[] p_cmdline, PandemoniumTTS tts);
/**
* Invoked on the GL thread when the underlying Android surface has changed size.
diff --git a/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/tts/PandemoniumTTS.java b/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/tts/PandemoniumTTS.java
index d8816d517..7ca7292df 100644
--- a/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/tts/PandemoniumTTS.java
+++ b/platform/android/java/lib/src/org/pandemoniumengine/pandemonium/tts/PandemoniumTTS.java
@@ -62,8 +62,9 @@ public class PandemoniumTTS extends UtteranceProgressListener {
final private static int EVENT_CANCEL = 2;
final private static int EVENT_BOUNDARY = 3;
- final private TextToSpeech synth;
- final private LinkedList queue;
+ final private Activity activity;
+ private TextToSpeech synth;
+ private LinkedList queue;
final private Object lock = new Object();
private PandemoniumUtterance lastUtterance;
@@ -71,10 +72,7 @@ public class PandemoniumTTS extends UtteranceProgressListener {
private boolean paused;
public PandemoniumTTS(Activity p_activity) {
- synth = new TextToSpeech(p_activity, null);
- queue = new LinkedList();
-
- synth.setOnUtteranceProgressListener(this);
+ activity = p_activity;
}
private void updateTTS() {
@@ -186,6 +184,16 @@ public class PandemoniumTTS extends UtteranceProgressListener {
}
}
+ /**
+ * Initialize synth and query.
+ */
+ public void init() {
+ synth = new TextToSpeech(p_activity, null);
+ queue = new LinkedList();
+
+ synth.setOnUtteranceProgressListener(this);
+ }
+
/**
* Adds an utterance to the queue.
*/
diff --git a/platform/android/java_pandemonium_lib_jni.cpp b/platform/android/java_pandemonium_lib_jni.cpp
index 26256053f..73128791c 100644
--- a/platform/android/java_pandemonium_lib_jni.cpp
+++ b/platform/android/java_pandemonium_lib_jni.cpp
@@ -160,7 +160,7 @@ JNIEXPORT void JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_set
}
}
-JNIEXPORT void JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_pandemonium_instance, jobject p_asset_manager, jobject p_pandemonium_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts) {
+JNIEXPORT void JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_pandemonium_instance, jobject p_asset_manager, jobject p_pandemonium_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion) {
initialized = true;
JavaVM *jvm;
@@ -179,7 +179,6 @@ JNIEXPORT void JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_ini
DirAccessJAndroid::setup(p_directory_access_handler);
FileAccessFilesystemJAndroid::setup(p_file_access_handler);
NetSocketAndroid::setup(p_net_utils);
- TTS_Android::setup(p_godot_tts);
os_android = new OS_Android(pandemonium_java, pandemonium_io_java, p_use_apk_expansion);
@@ -193,7 +192,7 @@ JNIEXPORT void JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_ond
_terminate(env, false);
}
-JNIEXPORT jboolean JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) {
+JNIEXPORT jboolean JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline, jobject p_godot_tts) {
setup_android_thread();
const char **cmdline = NULL;
@@ -234,7 +233,10 @@ JNIEXPORT jboolean JNICALL Java_org_pandemoniumengine_pandemonium_PandemoniumLib
return false;
}
+ TTS_Android::setup(p_godot_tts);
+
java_class_wrapper = memnew(JavaClassWrapper(pandemonium_java->get_activity()));
+
ClassDB::register_class();
_initialize_java_modules();
return true;
diff --git a/platform/android/tts_android.cpp b/platform/android/tts_android.cpp
index a659c29c9..8efde427b 100644
--- a/platform/android/tts_android.cpp
+++ b/platform/android/tts_android.cpp
@@ -35,9 +35,11 @@
#include "string_android.h"
#include "thread_jandroid.h"
+bool TTS_Android::initialized = false;
jobject TTS_Android::tts = 0;
jclass TTS_Android::cls = 0;
+jmethodID TTS_Android::_init = 0;
jmethodID TTS_Android::_is_speaking = 0;
jmethodID TTS_Android::_is_paused = 0;
jmethodID TTS_Android::_get_voices = 0;
@@ -99,23 +101,33 @@ Vector TTS_Android::str_to_utf16(const String &p_string) {
}
void TTS_Android::setup(jobject p_tts) {
- JNIEnv *env = get_jni_env();
+ bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
+ if (tts_enabled) {
+ JNIEnv *env = get_jni_env();
- tts = env->NewGlobalRef(p_tts);
+ tts = env->NewGlobalRef(p_tts);
- jclass c = env->GetObjectClass(tts);
- cls = (jclass)env->NewGlobalRef(c);
+ jclass c = env->GetObjectClass(tts);
+ cls = (jclass)env->NewGlobalRef(c);
- _is_speaking = env->GetMethodID(cls, "isSpeaking", "()Z");
- _is_paused = env->GetMethodID(cls, "isPaused", "()Z");
- _get_voices = env->GetMethodID(cls, "getVoices", "()[Ljava/lang/String;");
- _speak = env->GetMethodID(cls, "speak", "(Ljava/lang/String;Ljava/lang/String;IFFIZ)V");
- _pause_speaking = env->GetMethodID(cls, "pauseSpeaking", "()V");
- _resume_speaking = env->GetMethodID(cls, "resumeSpeaking", "()V");
- _stop_speaking = env->GetMethodID(cls, "stopSpeaking", "()V");
+ _init = env->GetMethodID(cls, "init", "()V");
+ _is_speaking = env->GetMethodID(cls, "isSpeaking", "()Z");
+ _is_paused = env->GetMethodID(cls, "isPaused", "()Z");
+ _get_voices = env->GetMethodID(cls, "getVoices", "()[Ljava/lang/String;");
+ _speak = env->GetMethodID(cls, "speak", "(Ljava/lang/String;Ljava/lang/String;IFFIZ)V");
+ _pause_speaking = env->GetMethodID(cls, "pauseSpeaking", "()V");
+ _resume_speaking = env->GetMethodID(cls, "resumeSpeaking", "()V");
+ _stop_speaking = env->GetMethodID(cls, "stopSpeaking", "()V");
+
+ if (_init) {
+ env->CallVoidMethod(tts, _init);
+ initialized = true;
+ }
+ }
}
void TTS_Android::_java_utterance_callback(int p_event, int p_id, int p_pos) {
+ ERR_FAIL_COND_MSG(!initialized, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (ids.has(p_id)) {
int pos = 0;
if ((OS::TTSUtteranceEvent)p_event == OS::TTS_UTTERANCE_BOUNDARY) {
@@ -136,6 +148,7 @@ void TTS_Android::_java_utterance_callback(int p_event, int p_id, int p_pos) {
}
bool TTS_Android::is_speaking() {
+ ERR_FAIL_COND_V_MSG(!initialized, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (_is_speaking) {
JNIEnv *env = get_jni_env();
@@ -147,6 +160,7 @@ bool TTS_Android::is_speaking() {
}
bool TTS_Android::is_paused() {
+ ERR_FAIL_COND_V_MSG(!initialized, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (_is_paused) {
JNIEnv *env = get_jni_env();
@@ -158,6 +172,7 @@ bool TTS_Android::is_paused() {
}
Array TTS_Android::get_voices() {
+ ERR_FAIL_COND_V_MSG(!initialized, Array(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
Array list;
if (_get_voices) {
JNIEnv *env = get_jni_env();
@@ -185,6 +200,7 @@ Array TTS_Android::get_voices() {
}
void TTS_Android::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND_MSG(!initialized, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (p_interrupt) {
stop();
}
@@ -207,6 +223,7 @@ void TTS_Android::speak(const String &p_text, const String &p_voice, int p_volum
}
void TTS_Android::pause() {
+ ERR_FAIL_COND_MSG(!initialized, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (_pause_speaking) {
JNIEnv *env = get_jni_env();
@@ -216,6 +233,7 @@ void TTS_Android::pause() {
}
void TTS_Android::resume() {
+ ERR_FAIL_COND_MSG(!initialized, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (_resume_speaking) {
JNIEnv *env = get_jni_env();
@@ -225,6 +243,7 @@ void TTS_Android::resume() {
}
void TTS_Android::stop() {
+ ERR_FAIL_COND_MSG(!initialized, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
const int *k = NULL;
while ((k = ids.next(k))) {
OS::get_singleton()->tts_post_utterance_event(OS::TTS_UTTERANCE_CANCELED, *k);
diff --git a/platform/android/tts_android.h b/platform/android/tts_android.h
index f7dc45111..5a1cde260 100644
--- a/platform/android/tts_android.h
+++ b/platform/android/tts_android.h
@@ -33,14 +33,17 @@
#include "core/variant/array.h"
#include "core/os/os.h"
+#include "core/config/project_settings.h"
#include "core/string/ustring.h"
#include
class TTS_Android {
+ static bool initialized;
static jobject tts;
static jclass cls;
+ static jmethodID _init;
static jmethodID _is_speaking;
static jmethodID _is_paused;
static jmethodID _get_voices;
diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm
index 92194f5fd..14ef92a66 100644
--- a/platform/iphone/os_iphone.mm
+++ b/platform/iphone/os_iphone.mm
@@ -95,36 +95,43 @@ OSIPhone *OSIPhone::get_singleton() {
};
bool OSIPhone::tts_is_speaking() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return [tts isSpeaking];
}
bool OSIPhone::tts_is_paused() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return [tts isPaused];
}
Array OSIPhone::tts_get_voices() const {
+ ERR_FAIL_COND_V_MSG(!tts, Array(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, Array());
return [tts getVoices];
}
void OSIPhone::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt];
}
void OSIPhone::tts_pause() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts pauseSpeaking];
}
void OSIPhone::tts_resume() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts resumeSpeaking];
}
void OSIPhone::tts_stop() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts stopSpeaking];
}
@@ -225,7 +232,10 @@ Error OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p
}
// Init TTS
- tts = [[TTS_IOS alloc] init];
+ bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
+ if (tts_enabled) {
+ tts = [[TTS_IOS alloc] init];
+ }
rendering_server->init();
//rendering_server->cursor_set_visible(false, 0);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index afc57ef76..737c8d68a 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -32,6 +32,7 @@
#include "os_javascript.h"
#include "core/io/json.h"
+#include "core/project_settings.h"
#include "drivers/gles2/rasterizer_gles2.h"
#ifndef GLES3_DISABLED
#include "drivers/gles3/rasterizer_gles3.h"
@@ -69,10 +70,12 @@ void OS_JavaScript::request_quit_callback() {
}
bool OS_JavaScript::tts_is_speaking() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return godot_js_tts_is_speaking();
}
bool OS_JavaScript::tts_is_paused() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return godot_js_tts_is_paused();
}
@@ -91,11 +94,13 @@ void OS_JavaScript::update_voices_callback(int p_size, const char **p_voice) {
}
Array OS_JavaScript::tts_get_voices() const {
+ ERR_FAIL_COND_V_MSG(!tts, Array(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
godot_js_tts_get_voices(update_voices_callback);
return voices;
}
void OS_JavaScript::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
if (p_interrupt) {
tts_stop();
}
@@ -112,14 +117,17 @@ void OS_JavaScript::tts_speak(const String &p_text, const String &p_voice, int p
}
void OS_JavaScript::tts_pause() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
godot_js_tts_pause();
}
void OS_JavaScript::tts_resume() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
godot_js_tts_resume();
}
void OS_JavaScript::tts_stop() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
for (Map::Element *E = utterance_ids.front(); E; E = E->next()) {
tts_post_utterance_event(OS::TTS_UTTERANCE_CANCELED, E->key());
}
@@ -1322,6 +1330,8 @@ OS_JavaScript *OS_JavaScript::get_singleton() {
}
OS_JavaScript::OS_JavaScript() {
+ tts = GLOBAL_GET("audio/general/text_to_speech");
+
// Expose method for requesting quit.
pandemonium_js_os_request_quit_cb(&request_quit_callback);
// Set canvas ID
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index b5eacff0e..6bc00e9a4 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -93,6 +93,7 @@ private:
List audio_drivers;
RenderingServer *rendering_server;
+ bool tts;
bool swap_ok_cancel;
bool idb_available;
bool idb_needs_sync;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 77a37cb84..9dfdc4bb8 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -1593,36 +1593,43 @@ int OS_OSX::get_current_video_driver() const {
}
bool OS_OSX::tts_is_speaking() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return [tts isSpeaking];
}
bool OS_OSX::tts_is_paused() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return [tts isPaused];
}
Array OS_OSX::tts_get_voices() const {
+ ERR_FAIL_COND_V_MSG(!tts, Array(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, Array());
return [tts getVoices];
}
void OS_OSX::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts speak:p_text voice:p_voice volume:p_volume pitch:p_pitch rate:p_rate utterance_id:p_utterance_id interrupt:p_interrupt];
}
void OS_OSX::tts_pause() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts pauseSpeaking];
}
void OS_OSX::tts_resume() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts resumeSpeaking];
}
void OS_OSX::tts_stop() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
[tts stopSpeaking];
}
@@ -1646,7 +1653,10 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
// Init TTS
- tts = [[TTS_OSX alloc] init];
+ bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
+ if (tts_enabled) {
+ tts = [[TTS_OSX alloc] init];
+ }
window_delegate = [[PandemoniumWindowDelegate alloc] init];
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index cab236298..b78904f90 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -263,36 +263,43 @@ void OS_Windows::_touch_event(bool p_pressed, float p_x, float p_y, int idx) {
};
bool OS_Windows::tts_is_speaking() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return tts->is_speaking();
}
bool OS_Windows::tts_is_paused() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return tts->is_paused();
}
Array OS_Windows::tts_get_voices() const {
+ ERR_FAIL_COND_V_MSG(!tts, Array(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, Array());
return tts->get_voices();
}
void OS_Windows::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
}
void OS_Windows::tts_pause() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->pause();
}
void OS_Windows::tts_resume() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->resume();
}
void OS_Windows::tts_stop() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->stop();
}
@@ -1396,7 +1403,10 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
}
// Init TTS
- tts = memnew(TTS_Windows);
+ bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
+ if (tts_enabled) {
+ tts = memnew(TTS_Windows);
+ }
use_raw_input = true;
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 850ff985c..ab6d16a57 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -115,36 +115,43 @@ static String get_atom_name(Display *p_disp, Atom p_atom) {
#ifdef SPEECHD_ENABLED
bool OS_X11::tts_is_speaking() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return tts->is_speaking();
}
bool OS_X11::tts_is_paused() const {
+ ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, false);
return tts->is_paused();
}
Array OS_X11::tts_get_voices() const {
+ ERR_FAIL_COND_V_MSG(!tts, Array(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND_V(!tts, Array());
return tts->get_voices();
}
void OS_X11::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
}
void OS_X11::tts_pause() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->pause();
}
void OS_X11::tts_resume() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->resume();
}
void OS_X11::tts_stop() {
+ ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
ERR_FAIL_COND(!tts);
tts->stop();
}
@@ -422,7 +429,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
#ifdef SPEECHD_ENABLED
// Init TTS
- tts = memnew(TTS_Linux);
+ bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
+ if (tts_enabled) {
+ tts = memnew(TTS_Linux);
+ }
#endif
rendering_server = memnew(RenderingServerRaster);
@@ -897,7 +907,9 @@ void OS_X11::finalize() {
#endif
#ifdef SPEECHD_ENABLED
- memdelete(tts);
+ if (tts) {
+ memdelete(tts);
+ }
#endif
#ifdef JOYDEV_ENABLED