From db69cdf20da8e463a7a689cd84fa235bb1ab36ac Mon Sep 17 00:00:00 2001 From: Ryan Conrad Date: Sun, 10 Apr 2022 10:49:36 -0500 Subject: [PATCH 1/4] Message text to speech initial commit --- libultraship/libultraship/Window.cpp | 9 ++- soh/src/code/z_message_PAL.c | 107 +++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index 00868a91d..d929b5ea3 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -279,21 +279,22 @@ namespace Ship { WmApi->set_keyboard_callbacks(Window::KeyDown, Window::KeyUp, Window::AllKeysUp); } - void task1(const char textToRead[]) + void task1(const std::string & textToRead) { const int w = 512; int* wp = const_cast (&w); - *wp = strlen(textToRead); + *wp = strlen(textToRead.c_str()); wchar_t wtext[w]; - mbstowcs(wtext, textToRead, strlen(textToRead) + 1); + mbstowcs(wtext, textToRead.c_str(), strlen(textToRead.c_str()) + 1); pVoice->Speak(wtext, SPF_IS_XML | SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL); } void Window::ReadText(const char textToRead[]) { - std::thread t1(task1, textToRead); + std::string textCopy(textToRead); + std::thread t1(task1, textCopy); t1.detach(); } diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index f932d3406..8524d6d60 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -118,6 +118,11 @@ s16 sOcarinaNoteCEnvR; s16 sOcarinaNoteCEnvB; s16 sOcarinaNoteCEnvG; +static u8 ttsHasNewMessage; +static u8 ttsHasMessage; +static s8 ttsCurrentChoice; +static u8 ttsMessageBuf[256]; + void Message_ResetOcarinaNoteState(void) { R_OCARINA_NOTES_YPOS(0) = 189; R_OCARINA_NOTES_YPOS(1) = 184; @@ -3004,6 +3009,104 @@ void Message_Draw(GlobalContext* globalCtx) { CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_message_PAL.c", 3582); } +void Message_TTS_Decode(u8* srcBuf, u8* dstBuf, u32 srcOffset, u32 size) { + u32 dstIdx = 0; + + for (u32 i = 0; i < size; i++) { + u8 currChar = srcBuf[i + srcOffset]; + + if (currChar < ' ') { + switch (currChar) { + case CTRL_NEWLINE: + dstBuf[dstIdx++] = ' '; + break; + case MESSAGE_COLOR: + case MESSAGE_SHIFT: + case MESSAGE_TEXT_SPEED: + case MESSAGE_BOX_BREAK_DELAYED: + case MESSAGE_FADE: + case MESSAGE_ITEM_ICON: + i++; + break; + case MESSAGE_FADE2: + case MESSAGE_SFX: + i += 2; + break; + default: + break; + } + } else { + dstBuf[dstIdx++] = currChar; + } + } + + dstBuf[dstIdx] = 0; +} + +void Message_TTS_Update(GlobalContext* globalCtx) { + MessageContext* msgCtx = &globalCtx->msgCtx; + + if (msgCtx->msgMode == MSGMODE_TEXT_NEXT_MSG || msgCtx->msgMode == MSGMODE_DISPLAY_SONG_PLAYED_TEXT_BEGIN || + (msgCtx->msgMode == MSGMODE_TEXT_CONTINUING && msgCtx->stateTimer == 1)) { + ttsHasNewMessage = 1; + } else if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING || msgCtx->msgMode == MSGMODE_OCARINA_STARTING || + msgCtx->msgMode == MSGMODE_OCARINA_PLAYING || msgCtx->msgMode == MSGMODE_TEXT_AWAIT_NEXT || + msgCtx->msgMode == MSGMODE_TEXT_DONE || msgCtx->msgMode == MSGMODE_DISPLAY_SONG_PLAYED_TEXT || + msgCtx->msgMode == MSGMODE_TEXT_DELAYED_BREAK) { + if (ttsHasNewMessage == 1) { + ttsHasNewMessage = 0; + ttsHasMessage = 1; + ttsCurrentChoice = 0; + + u32 size = msgCtx->decodedTextLen; + Message_TTS_Decode(msgCtx->msgBufDecoded, ttsMessageBuf, 0, size); + OTRTextToSpeechCallback(ttsMessageBuf); + } else if (msgCtx->msgMode == MSGMODE_TEXT_DONE && msgCtx->choiceNum > 0 && + msgCtx->choiceIndex != ttsCurrentChoice) { + ttsCurrentChoice = msgCtx->choiceIndex; + u32 startOffset = 0; + u32 endOffset = 0; + while (startOffset < msgCtx->decodedTextLen) { + if (msgCtx->msgBufDecoded[startOffset] == MESSAGE_TWO_CHOICE || + msgCtx->msgBufDecoded[startOffset] == MESSAGE_THREE_CHOICE) { + startOffset++; + break; + } + startOffset++; + } + if (startOffset < msgCtx->decodedTextLen) { + u8 i = msgCtx->choiceIndex; + while (i-- > 0) { + while (startOffset < msgCtx->decodedTextLen) { + if (msgCtx->msgBufDecoded[startOffset] == MESSAGE_NEWLINE) { + startOffset++; + break; + } + startOffset++; + } + } + endOffset = startOffset; + while (endOffset < msgCtx->decodedTextLen) { + if (msgCtx->msgBufDecoded[endOffset] == MESSAGE_NEWLINE) { + break; + } + endOffset++; + } + + if (startOffset < msgCtx->decodedTextLen && startOffset != endOffset) { + u32 size = endOffset - startOffset; + Message_TTS_Decode(msgCtx->msgBufDecoded, ttsMessageBuf, startOffset, size); + OTRTextToSpeechCallback(ttsMessageBuf); + } + } + } + } else if (ttsHasMessage == 1) { + ttsHasMessage = 0; + ttsHasNewMessage = 0; + OTRTextToSpeechCallback(""); // cancel current speech + } +} + void Message_Update(GlobalContext* globalCtx) { static s16 sTextboxXPositions[] = { 34, 34, 34, 34, 34, 34, @@ -3067,6 +3170,10 @@ void Message_Update(GlobalContext* globalCtx) { return; } + if (CVar_GetS32("gMessageTTS", 0) != 0) { + Message_TTS_Update(globalCtx); + } + bool isB_Held = CVar_GetS32("gFastText", 0) != 0 ? CHECK_BTN_ALL(input->cur.button, BTN_B) && !sTextboxSkipped : CHECK_BTN_ALL(input->press.button, BTN_B); From 5958a0fbf4eb09f8ffe3a9ceb330bb396a93eb49 Mon Sep 17 00:00:00 2001 From: Ryan Conrad Date: Sun, 10 Apr 2022 11:19:02 -0500 Subject: [PATCH 2/4] Adhere to static naming convention --- soh/src/code/z_message_PAL.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 8524d6d60..4743ca619 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -118,10 +118,10 @@ s16 sOcarinaNoteCEnvR; s16 sOcarinaNoteCEnvB; s16 sOcarinaNoteCEnvG; -static u8 ttsHasNewMessage; -static u8 ttsHasMessage; -static s8 ttsCurrentChoice; -static u8 ttsMessageBuf[256]; +static u8 sTtsHasNewMessage; +static u8 sTtsHasMessage; +static s8 sTtsCurrentChoice; +static u8 sTtsMessageBuf[256]; void Message_ResetOcarinaNoteState(void) { R_OCARINA_NOTES_YPOS(0) = 189; @@ -3048,22 +3048,22 @@ void Message_TTS_Update(GlobalContext* globalCtx) { if (msgCtx->msgMode == MSGMODE_TEXT_NEXT_MSG || msgCtx->msgMode == MSGMODE_DISPLAY_SONG_PLAYED_TEXT_BEGIN || (msgCtx->msgMode == MSGMODE_TEXT_CONTINUING && msgCtx->stateTimer == 1)) { - ttsHasNewMessage = 1; + sTtsHasNewMessage = 1; } else if (msgCtx->msgMode == MSGMODE_TEXT_DISPLAYING || msgCtx->msgMode == MSGMODE_OCARINA_STARTING || msgCtx->msgMode == MSGMODE_OCARINA_PLAYING || msgCtx->msgMode == MSGMODE_TEXT_AWAIT_NEXT || msgCtx->msgMode == MSGMODE_TEXT_DONE || msgCtx->msgMode == MSGMODE_DISPLAY_SONG_PLAYED_TEXT || msgCtx->msgMode == MSGMODE_TEXT_DELAYED_BREAK) { - if (ttsHasNewMessage == 1) { - ttsHasNewMessage = 0; - ttsHasMessage = 1; - ttsCurrentChoice = 0; + if (sTtsHasNewMessage == 1) { + sTtsHasNewMessage = 0; + sTtsHasMessage = 1; + sTtsCurrentChoice = 0; u32 size = msgCtx->decodedTextLen; - Message_TTS_Decode(msgCtx->msgBufDecoded, ttsMessageBuf, 0, size); - OTRTextToSpeechCallback(ttsMessageBuf); + Message_TTS_Decode(msgCtx->msgBufDecoded, sTtsMessageBuf, 0, size); + OTRTextToSpeechCallback(sTtsMessageBuf); } else if (msgCtx->msgMode == MSGMODE_TEXT_DONE && msgCtx->choiceNum > 0 && - msgCtx->choiceIndex != ttsCurrentChoice) { - ttsCurrentChoice = msgCtx->choiceIndex; + msgCtx->choiceIndex != sTtsCurrentChoice) { + sTtsCurrentChoice = msgCtx->choiceIndex; u32 startOffset = 0; u32 endOffset = 0; while (startOffset < msgCtx->decodedTextLen) { @@ -3095,14 +3095,14 @@ void Message_TTS_Update(GlobalContext* globalCtx) { if (startOffset < msgCtx->decodedTextLen && startOffset != endOffset) { u32 size = endOffset - startOffset; - Message_TTS_Decode(msgCtx->msgBufDecoded, ttsMessageBuf, startOffset, size); - OTRTextToSpeechCallback(ttsMessageBuf); + Message_TTS_Decode(msgCtx->msgBufDecoded, sTtsMessageBuf, startOffset, size); + OTRTextToSpeechCallback(sTtsMessageBuf); } } } - } else if (ttsHasMessage == 1) { - ttsHasMessage = 0; - ttsHasNewMessage = 0; + } else if (sTtsHasMessage == 1) { + sTtsHasMessage = 0; + sTtsHasNewMessage = 0; OTRTextToSpeechCallback(""); // cancel current speech } } From 90b2b70b965899bd6fc6b2b558cd4bab80550e58 Mon Sep 17 00:00:00 2001 From: Ryan Conrad Date: Sun, 10 Apr 2022 11:58:22 -0500 Subject: [PATCH 3/4] TTS message decoding fix --- soh/src/code/z_message_PAL.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index 4743ca619..cfde98309 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -3017,7 +3017,7 @@ void Message_TTS_Decode(u8* srcBuf, u8* dstBuf, u32 srcOffset, u32 size) { if (currChar < ' ') { switch (currChar) { - case CTRL_NEWLINE: + case MESSAGE_NEWLINE: dstBuf[dstIdx++] = ' '; break; case MESSAGE_COLOR: @@ -3030,6 +3030,7 @@ void Message_TTS_Decode(u8* srcBuf, u8* dstBuf, u32 srcOffset, u32 size) { break; case MESSAGE_FADE2: case MESSAGE_SFX: + case MESSAGE_TEXTID: i += 2; break; default: From fb91eeb06e24427b2913da6df94bdddf9fbb3a9a Mon Sep 17 00:00:00 2001 From: Ryan Conrad Date: Sun, 10 Apr 2022 13:32:44 -0500 Subject: [PATCH 4/4] Let faded out messages finish --- soh/src/code/z_message_PAL.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index cfde98309..2439a8edd 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -3104,7 +3104,10 @@ void Message_TTS_Update(GlobalContext* globalCtx) { } else if (sTtsHasMessage == 1) { sTtsHasMessage = 0; sTtsHasNewMessage = 0; - OTRTextToSpeechCallback(""); // cancel current speech + if (msgCtx->decodedTextLen < 3 || (msgCtx->msgBufDecoded[msgCtx->decodedTextLen - 2] != MESSAGE_FADE && + msgCtx->msgBufDecoded[msgCtx->decodedTextLen - 3] != MESSAGE_FADE2)) { + OTRTextToSpeechCallback(""); // cancel current speech (except for faded out messages) + } } }