Merge pull request #1 from rnconrad/accessibility-tts

Add message text to speech
This commit is contained in:
MelonSpeedruns 2022-04-13 09:29:34 -04:00 committed by GitHub
commit 69d8139690
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 116 additions and 4 deletions

View file

@ -279,21 +279,22 @@ namespace Ship {
WmApi->set_keyboard_callbacks(Window::KeyDown, Window::KeyUp, Window::AllKeysUp); 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; const int w = 512;
int* wp = const_cast <int*> (&w); int* wp = const_cast <int*> (&w);
*wp = strlen(textToRead); *wp = strlen(textToRead.c_str());
wchar_t wtext[w]; 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); pVoice->Speak(wtext, SPF_IS_XML | SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL);
} }
void Window::ReadText(const char textToRead[]) void Window::ReadText(const char textToRead[])
{ {
std::thread t1(task1, textToRead); std::string textCopy(textToRead);
std::thread t1(task1, textCopy);
t1.detach(); t1.detach();
} }

View file

@ -118,6 +118,11 @@ s16 sOcarinaNoteCEnvR;
s16 sOcarinaNoteCEnvB; s16 sOcarinaNoteCEnvB;
s16 sOcarinaNoteCEnvG; s16 sOcarinaNoteCEnvG;
static u8 sTtsHasNewMessage;
static u8 sTtsHasMessage;
static s8 sTtsCurrentChoice;
static u8 sTtsMessageBuf[256];
void Message_ResetOcarinaNoteState(void) { void Message_ResetOcarinaNoteState(void) {
R_OCARINA_NOTES_YPOS(0) = 189; R_OCARINA_NOTES_YPOS(0) = 189;
R_OCARINA_NOTES_YPOS(1) = 184; R_OCARINA_NOTES_YPOS(1) = 184;
@ -3004,6 +3009,108 @@ void Message_Draw(GlobalContext* globalCtx) {
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_message_PAL.c", 3582); 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 MESSAGE_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:
case MESSAGE_TEXTID:
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)) {
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 (sTtsHasNewMessage == 1) {
sTtsHasNewMessage = 0;
sTtsHasMessage = 1;
sTtsCurrentChoice = 0;
u32 size = msgCtx->decodedTextLen;
Message_TTS_Decode(msgCtx->msgBufDecoded, sTtsMessageBuf, 0, size);
OTRTextToSpeechCallback(sTtsMessageBuf);
} else if (msgCtx->msgMode == MSGMODE_TEXT_DONE && msgCtx->choiceNum > 0 &&
msgCtx->choiceIndex != sTtsCurrentChoice) {
sTtsCurrentChoice = 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, sTtsMessageBuf, startOffset, size);
OTRTextToSpeechCallback(sTtsMessageBuf);
}
}
}
} else if (sTtsHasMessage == 1) {
sTtsHasMessage = 0;
sTtsHasNewMessage = 0;
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)
}
}
}
void Message_Update(GlobalContext* globalCtx) { void Message_Update(GlobalContext* globalCtx) {
static s16 sTextboxXPositions[] = { static s16 sTextboxXPositions[] = {
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
@ -3067,6 +3174,10 @@ void Message_Update(GlobalContext* globalCtx) {
return; 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 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); : CHECK_BTN_ALL(input->press.button, BTN_B);