From 41b57a985119962695013aca0d1e832d25207fc1 Mon Sep 17 00:00:00 2001 From: Sam Tupy Date: Fri, 4 Oct 2024 15:39:12 -0500 Subject: [PATCH] small maintenance * Fix issue in atomics function registrations, forgot to uppercase enum usage there. * Release ttsObj JNI local reference when tts_voice object is destroyed. * Astyle TTS.java and tts.cpp. * Fix speech not interrupting when menus wrap in menu.nvgt. --- jni/src/main/java/com/samtupy/nvgt/TTS.java | 24 ++++++--------- release/include/menu.nvgt | 1 + src/threading.cpp | 34 ++++++++++----------- src/tts.cpp | 33 ++++++++++---------- 4 files changed, 44 insertions(+), 48 deletions(-) diff --git a/jni/src/main/java/com/samtupy/nvgt/TTS.java b/jni/src/main/java/com/samtupy/nvgt/TTS.java index d2468f15..c08168a0 100644 --- a/jni/src/main/java/com/samtupy/nvgt/TTS.java +++ b/jni/src/main/java/com/samtupy/nvgt/TTS.java @@ -90,9 +90,8 @@ public void onInit(int status) { tts.setSpeechRate(1.0f); AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY).setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build(); tts.setAudioAttributes(audioAttributes); - } else { + } else isTTSInitialized = false; - } isTTSInitializedLatch.countDown(); } }); @@ -106,9 +105,8 @@ public boolean isActive() { } public boolean isSpeaking() { - if (isActive()) { + if (isActive()) return tts.isSpeaking(); - } return false; } @@ -117,16 +115,15 @@ public boolean speak(String text, boolean interrupt) { Bundle params = new Bundle(); params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, ttsVolume); params.putFloat(TextToSpeech.Engine.KEY_PARAM_PAN, ttsPan); - if (text.length() > tts.getMaxSpeechInputLength()) { + if (text.length() > tts.getMaxSpeechInputLength()) return false; - } - return tts.speak(text, interrupt? TextToSpeech.QUEUE_FLUSH : TextToSpeech.QUEUE_ADD, params, null) == TextToSpeech.SUCCESS; + return tts.speak(text, interrupt ? TextToSpeech.QUEUE_FLUSH : TextToSpeech.QUEUE_ADD, params, null) == TextToSpeech.SUCCESS; } return false; } public boolean silence() { - return isActive()? tts.stop() == TextToSpeech.SUCCESS : false; + return isActive() ? tts.stop() == TextToSpeech.SUCCESS : false; } public String getVoice() { @@ -163,9 +160,8 @@ public void setVolume(float volume) { @Override public void finalize() { - if (isActive()) { + if (isActive()) tts.shutdown(); - } } public List getVoices() { @@ -176,14 +172,12 @@ public boolean setVoice(String name) { if (isActive()) { Set voices = tts.getVoices(); Optional desiredVoice = voices.stream().filter(voice -> voice.getName().equals(name)).findFirst(); - if (desiredVoice.isPresent()) { + if (desiredVoice.isPresent()) return tts.setVoice(desiredVoice.get()) == TextToSpeech.SUCCESS; - } else { + else return false; - } - } else { + } else return false; - } } public int getMaxSpeechInputLength() { diff --git a/release/include/menu.nvgt b/release/include/menu.nvgt index 8a3bbfd5..49f3c8dd 100644 --- a/release/include/menu.nvgt +++ b/release/include/menu.nvgt @@ -157,6 +157,7 @@ class menu { return 0; } play(wrap_sound); + stop_speech(); wait(wrap_delay); f.set_list_position(0, int(args["key"]) == KEY_DOWN? 0 : f.get_list_count(0) -1, true); return 1; diff --git a/src/threading.cpp b/src/threading.cpp index 20ac1781..64a8cdc5 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -275,26 +275,26 @@ template void register_atomic_typ engine->RegisterObjectBehaviour(type_name.c_str(), asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(atomics_construct), asCALL_CDECL_OBJFIRST); engine->RegisterObjectBehaviour(type_name.c_str(), asBEHAVE_DESTRUCT, "void f()", asFUNCTION(atomics_destruct), asCALL_CDECL_OBJFIRST); engine->RegisterObjectMethod(type_name.c_str(), "bool is_lock_free()", asMETHODPR(atomic_type, is_lock_free, () const noexcept, bool), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("void store(%s val, memory_order order = memory_order_seq_cst)", regular_type_name).c_str(), asMETHODPR(atomic_type, store, (divisible_type, std::memory_order) noexcept, void), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("void store(%s val, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name).c_str(), asMETHODPR(atomic_type, store, (divisible_type, std::memory_order) noexcept, void), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opAssign(%s val)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator=, (divisible_type) noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s load(memory_order order = memory_order_seq_cst)", regular_type_name).c_str(), asMETHODPR(atomic_type, load, (std::memory_order) const noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s load(memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name).c_str(), asMETHODPR(atomic_type, load, (std::memory_order) const noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opImplConv()", regular_type_name).c_str(), asMETHODPR(atomic_type, operator divisible_type, () const noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s exchange(%s desired, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, exchange, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s exchange(%s desired, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, exchange, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("bool compare_exchange_weak(%s& expected, %s desired, memory_order success, memory_order failure)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, compare_exchange_weak, (divisible_type&, divisible_type, std::memory_order, std::memory_order) noexcept, bool), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("bool compare_exchange_weak(%s& expected, %s desired, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, compare_exchange_weak, (divisible_type&, divisible_type, std::memory_order) noexcept, bool), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("bool compare_exchange_weak(%s& expected, %s desired, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, compare_exchange_weak, (divisible_type&, divisible_type, std::memory_order) noexcept, bool), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("bool compare_exchange_strong(%s& expected, %s desired, memory_order success, memory_order failure)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, compare_exchange_strong, (divisible_type&, divisible_type, std::memory_order, std::memory_order) noexcept, bool), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("bool compare_exchange_strong(%s& expected, %s desired, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, compare_exchange_strong, (divisible_type&, divisible_type, std::memory_order) noexcept, bool), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("void wait(%s old, memory_order order = memory_order_seq_cst)", regular_type_name).c_str(), asMETHODPR(atomic_type, wait, (divisible_type, std::memory_order) const noexcept, void), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("bool compare_exchange_strong(%s& expected, %s desired, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, compare_exchange_strong, (divisible_type&, divisible_type, std::memory_order) noexcept, bool), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("void wait(%s old, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name).c_str(), asMETHODPR(atomic_type, wait, (divisible_type, std::memory_order) const noexcept, void), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), "void notify_one()", asMETHODPR(atomic_type, notify_one, () noexcept, void), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), "void notify_all()", asMETHODPR(atomic_type, notify_all, () noexcept, void), asCALL_THISCALL); // Begin type-specific atomics if constexpr((std::is_integral_v || std::is_floating_point_v) && !std::is_same_v) { - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_add(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_add, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_sub(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_sub, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_add(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_add, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_sub(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_sub, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); #ifdef __cpp_lib_atomic_min_max // Only available in C++26 mode or later if constexpr(std::is_integral_v) { - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_max(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_max, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_min(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_min, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_max(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_max, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_min(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_min, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); } #endif engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opAddAssign(%s arg)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator+=, (divisible_type) noexcept, divisible_type), asCALL_THISCALL); @@ -304,9 +304,9 @@ template void register_atomic_typ engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opPostInc(%s arg)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator++, (int) noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opPreDec()", regular_type_name).c_str(), asMETHODPR(atomic_type, operator--, () noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opPostDec(%s arg)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator--, (int) noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_and(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_and, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_or(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_or, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); - engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_xor(%s arg, memory_order order = memory_order_seq_cst)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_xor, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_and(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_and, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_or(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_or, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); + engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s fetch_xor(%s arg, memory_order order = MEMORY_ORDER_SEQ_CST)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, fetch_xor, (divisible_type, std::memory_order) noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opAndAssign(%s arg)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator&=, (divisible_type) noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opOrAssign(%s arg)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator|=, (divisible_type) noexcept, divisible_type), asCALL_THISCALL); engine->RegisterObjectMethod(type_name.c_str(), Poco::format("%s opXorAssign(%s arg)", regular_type_name, regular_type_name).c_str(), asMETHODPR(atomic_type, operator^=, (divisible_type) noexcept, divisible_type), asCALL_THISCALL); @@ -327,10 +327,10 @@ void RegisterAtomics(asIScriptEngine* engine) { engine->RegisterObjectType("atomic_flag", sizeof(std::atomic_flag), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits()); engine->RegisterObjectBehaviour("atomic_flag", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(atomics_construct), asCALL_CDECL_OBJFIRST); engine->RegisterObjectBehaviour("atomic_flag", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(atomics_destruct), asCALL_CDECL_OBJFIRST); - engine->RegisterObjectMethod("atomic_flag", "bool test(memory_order order = memory_order_seq_cst)", asMETHODPR(std::atomic_flag, test, (std::memory_order) const noexcept, bool), asCALL_THISCALL); - engine->RegisterObjectMethod("atomic_flag", "void clear(memory_order order = memory_order_seq_cst)", asMETHODPR(std::atomic_flag, clear, (std::memory_order), void), asCALL_THISCALL); - engine->RegisterObjectMethod("atomic_flag", "bool test_and_set(memory_order order = memory_order_seq_cst)", asMETHODPR(std::atomic_flag, test_and_set, (std::memory_order) noexcept, bool), asCALL_THISCALL); - engine->RegisterObjectMethod("atomic_flag", "void wait(bool old, memory_order order = memory_order_seq_cst)", asMETHODPR(std::atomic_flag, wait, (bool, std::memory_order) const noexcept, void), asCALL_THISCALL); + engine->RegisterObjectMethod("atomic_flag", "bool test(memory_order order = MEMORY_ORDER_SEQ_CST)", asMETHODPR(std::atomic_flag, test, (std::memory_order) const noexcept, bool), asCALL_THISCALL); + engine->RegisterObjectMethod("atomic_flag", "void clear(memory_order order = MEMORY_ORDER_SEQ_CST)", asMETHODPR(std::atomic_flag, clear, (std::memory_order), void), asCALL_THISCALL); + engine->RegisterObjectMethod("atomic_flag", "bool test_and_set(memory_order order = MEMORY_ORDER_SEQ_CST)", asMETHODPR(std::atomic_flag, test_and_set, (std::memory_order) noexcept, bool), asCALL_THISCALL); + engine->RegisterObjectMethod("atomic_flag", "void wait(bool old, memory_order order = MEMORY_ORDER_SEQ_CST)", asMETHODPR(std::atomic_flag, wait, (bool, std::memory_order) const noexcept, void), asCALL_THISCALL); engine->RegisterObjectMethod("atomic_flag", "void notify_one()", asMETHOD(std::atomic_flag, notify_one), asCALL_THISCALL); engine->RegisterObjectMethod("atomic_flag", "void notify_all()", asMETHOD(std::atomic_flag, notify_all), asCALL_THISCALL); register_atomic_type(engine, "atomic_int", "int"); diff --git a/src/tts.cpp b/src/tts.cpp index 64f22580..75153e64 100644 --- a/src/tts.cpp +++ b/src/tts.cpp @@ -17,16 +17,16 @@ #endif #include #ifdef __APPLE__ -#include "apple.h" + #include "apple.h" #endif #include "riffheader.h" #include "tts.h" #include "UI.h" #ifdef __ANDROID__ -#include -#include -#include -#include + #include + #include + #include + #include #endif char* minitrim(char* data, unsigned long* bufsize, int bitrate, int channels) { @@ -127,6 +127,9 @@ void tts_voice::destroy() { if (!inst) return; delete inst; inst = nullptr; + #elif defined(__ANDROID__) + env->DeleteLocalRef(TTSObj); + TTSObj = nullptr; #endif destroyed = true; voice_index = -1; @@ -169,9 +172,8 @@ bool tts_voice::speak(const std::string& text, bool interrupt) { } } #elif defined(__APPLE__) - else { + else return inst->speak(text, interrupt); - } #elif defined (__ANDROID__) else { jstring jtext = env->NewStringUTF(text.c_str()); @@ -236,9 +238,8 @@ bool tts_voice::speak_to_file(const std::string& filename, const std::string& te return false; // not implemented yet. } #elif defined(__ANDROID__) - else { + else return false; - } #endif char* ptr = minitrim(data, &bufsize, bitrate, channels); FILE* f = fopen(filename.c_str(), "wb"); @@ -298,7 +299,7 @@ bool tts_voice::speak_wait(const std::string& text, bool interrupt) { #ifdef __APPLE__ while (voice_index == builtin_index && BASS_ChannelIsActive(audioout) == BASS_ACTIVE_PLAYING || inst->isSpeaking()) #elif defined(__ANDROID__) - while (voice_index == builtin_index && BASS_ChannelIsActive(audioout) == BASS_ACTIVE_PLAYING || get_speaking()) + while (voice_index == builtin_index && BASS_ChannelIsActive(audioout) == BASS_ACTIVE_PLAYING || get_speaking()) #else while (BASS_ChannelIsActive(audioout) == BASS_ACTIVE_PLAYING) #endif @@ -323,7 +324,7 @@ int tts_voice::get_rate() { #elif defined(__APPLE__) return inst->getRate() * 7; #elif defined (__ANDROID__) - return static_cast((env->CallFloatMethod(TTSObj, midGetRate) -1) * 10.0); + return static_cast((env->CallFloatMethod(TTSObj, midGetRate) - 1) * 10.0); #endif return 0; } @@ -334,7 +335,7 @@ int tts_voice::get_pitch() { #elif defined(__APPLE__) return inst->getPitch(); #elif defined (__ANDROID__) - return static_cast((env->CallFloatMethod(TTSObj, midGetPitch) -1) * 10.0); + return static_cast((env->CallFloatMethod(TTSObj, midGetPitch) - 1) * 10.0); #endif return 0; } @@ -349,7 +350,7 @@ int tts_voice::get_volume() { #elif defined(__APPLE__) return inst->getRate(); #elif defined(__ANDROID__) - return static_cast(env->CallFloatMethod(TTSObj, midGetVolume)-100.0); + return static_cast(env->CallFloatMethod(TTSObj, midGetVolume) - 100.0); #endif return 0; } @@ -361,7 +362,7 @@ void tts_voice::set_rate(int rate) { #elif defined(__APPLE__) inst->setRate(rate / 7.0); #elif defined(__ANDROID__) - env->CallBooleanMethod(TTSObj, midSetRate, (static_cast(rate)/10.0) +1.0); + env->CallBooleanMethod(TTSObj, midSetRate, (static_cast(rate) / 10.0) + 1.0); #endif } void tts_voice::set_pitch(int pitch) { @@ -371,7 +372,7 @@ void tts_voice::set_pitch(int pitch) { #elif defined(__APPLE__) inst->setPitch(pitch); #elif defined(__ANDROID__) - env->CallBooleanMethod(TTSObj, midSetPitch, (static_cast(pitch)/10.0) +1.0); + env->CallBooleanMethod(TTSObj, midSetPitch, (static_cast(pitch) / 10.0) + 1.0); #endif return; } @@ -383,7 +384,7 @@ void tts_voice::set_volume(int volume) { #elif defined(__APPLE__) inst->setVolume(volume); #elif defined(__ANDROID__) - env->CallBooleanMethod(TTSObj, midSetVolume, static_cast(volume)+100.0); + env->CallBooleanMethod(TTSObj, midSetVolume, static_cast(volume) + 100.0); #endif } bool tts_voice::set_voice(int voice) {