From da125f1a1bd3ffe1b3363b586a9789c9617c04c7 Mon Sep 17 00:00:00 2001 From: Juho Hiltunen Date: Sat, 3 Mar 2018 23:39:09 +0200 Subject: [PATCH] move GetVoiceFromStack() --- src/libespeak-ng/readclause.c | 98 ++++------------------------------- src/libespeak-ng/ssml.c | 81 ++++++++++++++++++++++++++++- src/libespeak-ng/ssml.h | 4 +- 3 files changed, 92 insertions(+), 91 deletions(-) diff --git a/src/libespeak-ng/readclause.c b/src/libespeak-ng/readclause.c index d2b7190c..c26faeaf 100644 --- a/src/libespeak-ng/readclause.c +++ b/src/libespeak-ng/readclause.c @@ -550,82 +550,6 @@ static int AnnouncePunctuation(Translator *tr, int c1, int *c2_ptr, char *output return short_pause; } -const char *VoiceFromStack() -{ - // Use the voice properties from the SSML stack to choose a voice, and switch - // to that voice if it's not the current voice - - int ix; - const char *p; - SSML_STACK *sp; - const char *v_id; - int voice_name_specified; - int voice_found; - espeak_VOICE voice_select; - static char voice_name[40]; - char language[40]; - char buf[80]; - - strcpy(voice_name, ssml_stack[0].voice_name); - strcpy(language, ssml_stack[0].language); - voice_select.age = ssml_stack[0].voice_age; - voice_select.gender = ssml_stack[0].voice_gender; - voice_select.variant = ssml_stack[0].voice_variant_number; - voice_select.identifier = NULL; - - for (ix = 0; ix < n_ssml_stack; ix++) { - sp = &ssml_stack[ix]; - voice_name_specified = 0; - - if ((sp->voice_name[0] != 0) && (SelectVoiceByName(NULL, sp->voice_name) != NULL)) { - voice_name_specified = 1; - strcpy(voice_name, sp->voice_name); - language[0] = 0; - voice_select.gender = ENGENDER_UNKNOWN; - voice_select.age = 0; - voice_select.variant = 0; - } - if (sp->language[0] != 0) { - strcpy(language, sp->language); - - // is this language provided by the base voice? - p = base_voice.languages; - while (*p++ != 0) { - if (strcmp(p, language) == 0) { - // yes, change the language to the main language of the base voice - strcpy(language, &base_voice.languages[1]); - break; - } - p += (strlen(p) + 1); - } - - if (voice_name_specified == 0) - voice_name[0] = 0; // forget a previous voice name if a language is specified - } - if (sp->voice_gender != ENGENDER_UNKNOWN) - voice_select.gender = sp->voice_gender; - - if (sp->voice_age != 0) - voice_select.age = sp->voice_age; - if (sp->voice_variant_number != 0) - voice_select.variant = sp->voice_variant_number; - } - - voice_select.name = voice_name; - voice_select.languages = language; - v_id = SelectVoice(&voice_select, &voice_found); - if (v_id == NULL) - return "default"; - - if ((strchr(v_id, '+') == NULL) && ((voice_select.gender == ENGENDER_UNKNOWN) || (voice_select.gender == base_voice.gender)) && (base_voice_variant_name[0] != 0)) { - // a voice variant has not been selected, use the original voice variant - sprintf(buf, "%s+%s", v_id, base_voice_variant_name); - strncpy0(voice_name, buf, sizeof(voice_name)); - return voice_name; - } - return v_id; -} - static void ProcessParamStack(char *outbuf, int *outix) { // Set the speech parameters from the parameter stack @@ -1210,57 +1134,57 @@ static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int *outix, int n_outb if ((index = AddNameData(buf, 0)) >= 0) xmlbase = &namedata[index]; } - if (GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id) == 0) + if (GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name) == 0) return 0; // no voice change return CLAUSE_VOICE; case SSML_VOICE: - if (GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id) == 0) + if (GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name) == 0) return 0; // no voice change return CLAUSE_VOICE; case SSML_SPEAK + SSML_CLOSE: // unwind stack until the previous or tag while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_SPEAK)) n_ssml_stack--; - return CLAUSE_PERIOD + GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + return CLAUSE_PERIOD + GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); case SSML_VOICE + SSML_CLOSE: // unwind stack until the previous or tag while ((n_ssml_stack > 1) && (ssml_stack[n_ssml_stack-1].tag_type != SSML_VOICE)) n_ssml_stack--; terminator = 0; // ?? Sentence intonation, but no pause ?? - return terminator + GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + return terminator + GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); case HTML_BREAK: case HTML_BREAK + SSML_CLOSE: return CLAUSE_COLON; case SSML_SENTENCE: if (ssml_sp->tag_type == SSML_SENTENCE) { // new sentence implies end-of-sentence - voice_change_flag = GetVoiceAttributes(px, SSML_SENTENCE+SSML_CLOSE, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + voice_change_flag = GetVoiceAttributes(px, SSML_SENTENCE+SSML_CLOSE, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); } - voice_change_flag |= GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + voice_change_flag |= GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); return CLAUSE_PARAGRAPH + voice_change_flag; case SSML_PARAGRAPH: if (ssml_sp->tag_type == SSML_SENTENCE) { // new paragraph implies end-of-sentence or end-of-paragraph - voice_change_flag = GetVoiceAttributes(px, SSML_SENTENCE+SSML_CLOSE, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + voice_change_flag = GetVoiceAttributes(px, SSML_SENTENCE+SSML_CLOSE, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); } if (ssml_sp->tag_type == SSML_PARAGRAPH) { // new paragraph implies end-of-sentence or end-of-paragraph - voice_change_flag |= GetVoiceAttributes(px, SSML_PARAGRAPH+SSML_CLOSE, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + voice_change_flag |= GetVoiceAttributes(px, SSML_PARAGRAPH+SSML_CLOSE, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); } - voice_change_flag |= GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + voice_change_flag |= GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); return CLAUSE_PARAGRAPH + voice_change_flag; case SSML_SENTENCE + SSML_CLOSE: if (ssml_sp->tag_type == SSML_SENTENCE) { // end of a sentence which specified a language - voice_change_flag = GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id); + voice_change_flag = GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name); } return CLAUSE_PERIOD + voice_change_flag; case SSML_PARAGRAPH + SSML_CLOSE: if ((ssml_sp->tag_type == SSML_SENTENCE) || (ssml_sp->tag_type == SSML_PARAGRAPH)) { // End of a paragraph which specified a language. // (End-of-paragraph also implies end-of-sentence) - return GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, ¤t_voice_id) + CLAUSE_PARAGRAPH; + return GetVoiceAttributes(px, tag_type, ssml_sp, ssml_stack, n_ssml_stack, current_voice_id, &base_voice, base_voice_variant_name) + CLAUSE_PARAGRAPH; } return CLAUSE_PARAGRAPH; } diff --git a/src/libespeak-ng/ssml.c b/src/libespeak-ng/ssml.c index 9b61641f..a43f0f79 100644 --- a/src/libespeak-ng/ssml.c +++ b/src/libespeak-ng/ssml.c @@ -158,7 +158,7 @@ int attr_prosody_value(int param_type, const wchar_t *pw, int *value_out) return sign; // -1, 0, or 1 } -int GetVoiceAttributes(wchar_t *pw, int tag_type, SSML_STACK *ssml_sp, SSML_STACK *ssml_stack, int n_ssml_stack, char current_voice_id[]) +int GetVoiceAttributes(wchar_t *pw, int tag_type, SSML_STACK *ssml_sp, SSML_STACK *ssml_stack, int n_ssml_stack, char current_voice_id[40], espeak_VOICE *base_voice, char base_voice_variant_name[40]) { // Determines whether voice attribute are specified in this tag, and if so, whether this means // a voice change. @@ -217,7 +217,7 @@ int GetVoiceAttributes(wchar_t *pw, int tag_type, SSML_STACK *ssml_sp, SSML_STAC ssml_sp->tag_type = tag_type; } - new_voice_id = VoiceFromStack(); + new_voice_id = VoiceFromStack(ssml_stack, n_ssml_stack, base_voice, base_voice_variant_name); if (strcmp(new_voice_id, current_voice_id) != 0) { // add an embedded command to change the voice strcpy(current_voice_id, new_voice_id); @@ -226,3 +226,80 @@ int GetVoiceAttributes(wchar_t *pw, int tag_type, SSML_STACK *ssml_sp, SSML_STAC return 0; } + +const char *VoiceFromStack(SSML_STACK *ssml_stack, int n_ssml_stack, espeak_VOICE *base_voice, char base_voice_variant_name[40]) +{ + // Use the voice properties from the SSML stack to choose a voice, and switch + // to that voice if it's not the current voice + + int ix; + const char *p; + SSML_STACK *sp; + const char *v_id; + int voice_name_specified; + int voice_found; + espeak_VOICE voice_select; + static char voice_name[40]; + char language[40]; + char buf[80]; + + strcpy(voice_name, ssml_stack[0].voice_name); + strcpy(language, ssml_stack[0].language); + voice_select.age = ssml_stack[0].voice_age; + voice_select.gender = ssml_stack[0].voice_gender; + voice_select.variant = ssml_stack[0].voice_variant_number; + voice_select.identifier = NULL; + + for (ix = 0; ix < n_ssml_stack; ix++) { + sp = &ssml_stack[ix]; + voice_name_specified = 0; + + if ((sp->voice_name[0] != 0) && (SelectVoiceByName(NULL, sp->voice_name) != NULL)) { + voice_name_specified = 1; + strcpy(voice_name, sp->voice_name); + language[0] = 0; + voice_select.gender = ENGENDER_UNKNOWN; + voice_select.age = 0; + voice_select.variant = 0; + } + if (sp->language[0] != 0) { + strcpy(language, sp->language); + + // is this language provided by the base voice? + p = base_voice->languages; + while (*p++ != 0) { + if (strcmp(p, language) == 0) { + // yes, change the language to the main language of the base voice + strcpy(language, &base_voice->languages[1]); + break; + } + p += (strlen(p) + 1); + } + + if (voice_name_specified == 0) + voice_name[0] = 0; // forget a previous voice name if a language is specified + } + if (sp->voice_gender != ENGENDER_UNKNOWN) + voice_select.gender = sp->voice_gender; + + if (sp->voice_age != 0) + voice_select.age = sp->voice_age; + if (sp->voice_variant_number != 0) + voice_select.variant = sp->voice_variant_number; + } + + voice_select.name = voice_name; + voice_select.languages = language; + v_id = SelectVoice(&voice_select, &voice_found); + if (v_id == NULL) + return "default"; + + if ((strchr(v_id, '+') == NULL) && ((voice_select.gender == ENGENDER_UNKNOWN) || (voice_select.gender == base_voice->gender)) && (base_voice_variant_name[0] != 0)) { + // a voice variant has not been selected, use the original voice variant + sprintf(buf, "%s+%s", v_id, base_voice_variant_name); + strncpy0(voice_name, buf, sizeof(voice_name)); + return voice_name; + } + return v_id; +} + diff --git a/src/libespeak-ng/ssml.h b/src/libespeak-ng/ssml.h index 36df1471..ae45486c 100644 --- a/src/libespeak-ng/ssml.h +++ b/src/libespeak-ng/ssml.h @@ -73,5 +73,5 @@ int attrlookup(const wchar_t *string1, const MNEM_TAB *mtab); int attrnumber(const wchar_t *pw, int default_value, int type); int attr_prosody_value(int param_type, const wchar_t *pw, int *value_out); int attrcopy_utf8(char *buf, const wchar_t *pw, int len); -int GetVoiceAttributes(wchar_t *pw, int tag_type, SSML_STACK *ssml_sp, SSML_STACK *ssml_stack, int n_ssml_stack, char current_voice_id[]); - +int GetVoiceAttributes(wchar_t *pw, int tag_type, SSML_STACK *ssml_sp, SSML_STACK *ssml_stack, int n_ssml_stack, char current_voice_id[40], espeak_VOICE *base_voice, char base_voice_variant_name[40]); +const char *VoiceFromStack(SSML_STACK *ssml_stack, int n_ssml_stack, espeak_VOICE *base_voice, char base_voice_variant_name[40]);