| static int attrcopy_utf8(char *buf, const wchar_t *pw, int len) | static int attrcopy_utf8(char *buf, const wchar_t *pw, int len) | ||||
| { | { | ||||
| // Convert attribute string into utf8, write to buf, and return its utf8 length | // Convert attribute string into utf8, write to buf, and return its utf8 length | ||||
| unsigned int c; | |||||
| int ix = 0; | int ix = 0; | ||||
| int n; | |||||
| int prev_c = 0; | |||||
| if (pw != NULL) { | if (pw != NULL) { | ||||
| unsigned int c; | |||||
| int prev_c = 0; | |||||
| while ((ix < (len-4)) && ((c = *pw++) != 0)) { | while ((ix < (len-4)) && ((c = *pw++) != 0)) { | ||||
| if ((c == '"') && (prev_c != '\\')) | if ((c == '"') && (prev_c != '\\')) | ||||
| break; // " indicates end of attribute, unless preceded by backstroke | break; // " indicates end of attribute, unless preceded by backstroke | ||||
| n = utf8_out(c, &buf[ix]); | |||||
| int n = utf8_out(c, &buf[ix]); | |||||
| ix += n; | ix += n; | ||||
| prev_c = c; | prev_c = c; | ||||
| } | } | ||||
| const char *p; | const char *p; | ||||
| SSML_STACK *sp; | SSML_STACK *sp; | ||||
| const char *v_id; | const char *v_id; | ||||
| int voice_name_specified; | |||||
| int voice_found; | int voice_found; | ||||
| espeak_VOICE voice_select; | espeak_VOICE voice_select; | ||||
| static char voice_name[40]; | static char voice_name[40]; | ||||
| char language[40]; | char language[40]; | ||||
| char buf[80]; | |||||
| MAKE_MEM_UNDEFINED(&voice_name, sizeof(voice_name)); | MAKE_MEM_UNDEFINED(&voice_name, sizeof(voice_name)); | ||||
| for (ix = 0; ix < n_ssml_stack; ix++) { | for (ix = 0; ix < n_ssml_stack; ix++) { | ||||
| sp = &ssml_stack[ix]; | sp = &ssml_stack[ix]; | ||||
| voice_name_specified = 0; | |||||
| int voice_name_specified = 0; | |||||
| if ((sp->voice_name[0] != 0) && (SelectVoiceByName(NULL, sp->voice_name) != NULL)) { | if ((sp->voice_name[0] != 0) && (SelectVoiceByName(NULL, sp->voice_name) != NULL)) { | ||||
| voice_name_specified = 1; | voice_name_specified = 1; | ||||
| if ((strchr(v_id, '+') == NULL) && ((voice_select.gender == ENGENDER_UNKNOWN) || (voice_select.gender == base_voice->gender)) && (base_voice_variant_name[0] != 0)) { | 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 | // a voice variant has not been selected, use the original voice variant | ||||
| char buf[80]; | |||||
| sprintf(buf, "%s+%s", v_id, base_voice_variant_name); | sprintf(buf, "%s+%s", v_id, base_voice_variant_name); | ||||
| strncpy0(voice_name, buf, sizeof(voice_name)); | strncpy0(voice_name, buf, sizeof(voice_name)); | ||||
| return voice_name; | return voice_name; | ||||
| // a voice change. | // a voice change. | ||||
| // Returns CLAUSE_TYPE_VOICE_CHANGE if there is a voice change | // Returns CLAUSE_TYPE_VOICE_CHANGE if there is a voice change | ||||
| const wchar_t *lang; | |||||
| const wchar_t *gender; | |||||
| const wchar_t *name; | |||||
| const wchar_t *age; | |||||
| const wchar_t *variant; | |||||
| int value; | |||||
| const char *new_voice_id; | const char *new_voice_id; | ||||
| static const MNEM_TAB mnem_gender[] = { | static const MNEM_TAB mnem_gender[] = { | ||||
| if (n_ssml_stack > 1) | if (n_ssml_stack > 1) | ||||
| n_ssml_stack--; | n_ssml_stack--; | ||||
| } else { | } else { | ||||
| const wchar_t *lang; | |||||
| const wchar_t *gender; | |||||
| const wchar_t *name; | |||||
| const wchar_t *age; | |||||
| const wchar_t *variant; | |||||
| // add a stack frame if any voice details are specified | // add a stack frame if any voice details are specified | ||||
| lang = GetSsmlAttribute(pw, "xml:lang"); | lang = GetSsmlAttribute(pw, "xml:lang"); | ||||
| ssml_sp = &ssml_stack[n_ssml_stack++]; | ssml_sp = &ssml_stack[n_ssml_stack++]; | ||||
| int value; | |||||
| attrcopy_utf8(ssml_sp->language, lang, sizeof(ssml_sp->language)); | attrcopy_utf8(ssml_sp->language, lang, sizeof(ssml_sp->language)); | ||||
| attrcopy_utf8(ssml_sp->voice_name, name, sizeof(ssml_sp->voice_name)); | attrcopy_utf8(ssml_sp->voice_name, name, sizeof(ssml_sp->voice_name)); | ||||
| if ((value = attrnumber(variant, 1, 0)) > 0) | if ((value = attrnumber(variant, 1, 0)) > 0) | ||||
| // Set the speech parameters from the parameter stack | // Set the speech parameters from the parameter stack | ||||
| int param; | int param; | ||||
| int ix; | int ix; | ||||
| int value; | |||||
| char buf[20]; | char buf[20]; | ||||
| int new_parameters[N_SPEECH_PARAM]; | int new_parameters[N_SPEECH_PARAM]; | ||||
| static const char cmd_letter[N_SPEECH_PARAM] = { 0, 'S', 'A', 'P', 'R', 0, 'C', 0, 0, 0, 0, 0, 'F' }; // embedded command letters | static const char cmd_letter[N_SPEECH_PARAM] = { 0, 'S', 'A', 'P', 'R', 0, 'C', 0, 0, 0, 0, 0, 'F' }; // embedded command letters | ||||
| } | } | ||||
| for (param = 0; param < N_SPEECH_PARAM; param++) { | for (param = 0; param < N_SPEECH_PARAM; param++) { | ||||
| int value; | |||||
| if ((value = new_parameters[param]) != speech_parameters[param]) { | if ((value = new_parameters[param]) != speech_parameters[param]) { | ||||
| buf[0] = 0; | buf[0] = 0; | ||||
| { NULL, 0 } | { NULL, 0 } | ||||
| }; | }; | ||||
| int ix; | |||||
| int letter; | int letter; | ||||
| char *p; | char *p; | ||||
| p = &outbuf[index]; | p = &outbuf[index]; | ||||
| if ((letter = LookupMnem(keynames, p)) != 0) { | if ((letter = LookupMnem(keynames, p)) != 0) { | ||||
| ix = utf8_out(letter, p); | |||||
| int ix; | |||||
| ix = utf8_out(letter, p); | |||||
| *outix = index + ix; | *outix = index + ix; | ||||
| return letter; | return letter; | ||||
| } | } | ||||
| static void SetProsodyParameter(int param_type, const wchar_t *attr1, PARAM_STACK *sp, PARAM_STACK *param_stack, int *speech_parameters) | static void SetProsodyParameter(int param_type, const wchar_t *attr1, PARAM_STACK *sp, PARAM_STACK *param_stack, int *speech_parameters) | ||||
| { | { | ||||
| int value; | int value; | ||||
| int sign; | |||||
| static const MNEM_TAB mnem_volume[] = { | static const MNEM_TAB mnem_volume[] = { | ||||
| { "default", 100 }, | { "default", 100 }, | ||||
| // mnemonic specifies a value as a percentage of the base pitch/range/rate/volume | // mnemonic specifies a value as a percentage of the base pitch/range/rate/volume | ||||
| sp->parameter[param_type] = (param_stack[0].parameter[param_type] * value)/100; | sp->parameter[param_type] = (param_stack[0].parameter[param_type] * value)/100; | ||||
| } else { | } else { | ||||
| sign = attr_prosody_value(param_type, attr1, &value); | |||||
| int sign = attr_prosody_value(param_type, attr1, &value); | |||||
| if (sign == 0) | if (sign == 0) | ||||
| sp->parameter[param_type] = value; // absolute value in Hz | sp->parameter[param_type] = value; // absolute value in Hz | ||||
| unsigned int ix; | unsigned int ix; | ||||
| int index; | int index; | ||||
| int c; | |||||
| int tag_type; | int tag_type; | ||||
| int value; | int value; | ||||
| int value2; | int value2; | ||||
| const wchar_t *attr2; | const wchar_t *attr2; | ||||
| const wchar_t *attr3; | const wchar_t *attr3; | ||||
| int terminator; | int terminator; | ||||
| char *uri; | |||||
| int param_type; | int param_type; | ||||
| char tag_name[40]; | char tag_name[40]; | ||||
| char buf[160]; | char buf[160]; | ||||
| }; | }; | ||||
| for (ix = 0; ix < (sizeof(tag_name)-1); ix++) { | for (ix = 0; ix < (sizeof(tag_name)-1); ix++) { | ||||
| int c; | |||||
| if (((c = xml_buf[ix]) == 0) || iswspace(c)) | if (((c = xml_buf[ix]) == 0) || iswspace(c)) | ||||
| break; | break; | ||||
| tag_name[ix] = tolower((char)c); | tag_name[ix] = tolower((char)c); | ||||
| sp = PushParamStack(tag_type, n_param_stack, (PARAM_STACK *)param_stack); | sp = PushParamStack(tag_type, n_param_stack, (PARAM_STACK *)param_stack); | ||||
| if ((attr1 = GetSsmlAttribute(px, "src")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "src")) != NULL) { | ||||
| char fname[256]; | |||||
| attrcopy_utf8(buf, attr1, sizeof(buf)); | attrcopy_utf8(buf, attr1, sizeof(buf)); | ||||
| if (uri_callback == NULL) { | if (uri_callback == NULL) { | ||||
| if ((xmlbase != NULL) && (buf[0] != '/')) { | if ((xmlbase != NULL) && (buf[0] != '/')) { | ||||
| char fname[256]; | |||||
| sprintf(fname, "%s/%s", xmlbase, buf); | sprintf(fname, "%s/%s", xmlbase, buf); | ||||
| index = LoadSoundFile2(fname); | index = LoadSoundFile2(fname); | ||||
| } else | } else | ||||
| } | } | ||||
| } else { | } else { | ||||
| if ((index = AddNameData(buf, 0)) >= 0) { | if ((index = AddNameData(buf, 0)) >= 0) { | ||||
| char *uri; | |||||
| uri = &namedata[index]; | uri = &namedata[index]; | ||||
| if (uri_callback(1, uri, xmlbase) == 0) { | if (uri_callback(1, uri, xmlbase) == 0) { | ||||
| sprintf(buf, "%c%dU", CTRL_EMBEDDED, index); | sprintf(buf, "%c%dU", CTRL_EMBEDDED, index); |