From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 4 ++-- dlls/sapi/xml.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 86b484b268e..4f75aa88cac 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -1123,7 +1123,7 @@ static void test_spvoice_ssml(void) reset_engine_params(&test_engine);
hr = ISpVoice_Speak(voice, text8, SPF_IS_XML | SPF_PARSE_SSML, NULL); - todo_wine ok(hr == S_OK, "got %#lx.\n", hr); + ok(hr == S_OK, "got %#lx.\n", hr);
if (hr == S_OK) { ok(test_engine.frag_count == 9, "got %Iu.\n", test_engine.frag_count); @@ -1147,7 +1147,7 @@ static void test_spvoice_ssml(void) reset_engine_params(&test_engine);
hr = ISpVoice_Speak(voice, text9, SPF_IS_XML | SPF_PARSE_SSML, NULL); - todo_wine ok(hr == S_OK || broken(hr == SPERR_UNSUPPORTED_FORMAT) /* win7 */, "got %#lx.\n", hr); + ok(hr == S_OK || broken(hr == SPERR_UNSUPPORTED_FORMAT) /* win7 */, "got %#lx.\n", hr);
if (hr == S_OK) { ok(test_engine.frag_count == 7, "got %Iu.\n", test_engine.frag_count); diff --git a/dlls/sapi/xml.c b/dlls/sapi/xml.c index d6faa45277a..d54df1ef88f 100644 --- a/dlls/sapi/xml.c +++ b/dlls/sapi/xml.c @@ -496,6 +496,13 @@ static HRESULT parse_double_value(const xmlstr_t *value, double *res, size_t *re return S_OK; }
+static inline long lclamp(long value, long value_min, long value_max) +{ + if (value < value_min) return value_min; + if (value > value_max) return value_max; + return value; +} + static HRESULT parse_ssml_elems(struct xml_parser *parser, const SPVSTATE *state, const struct xml_elem *parent);
static HRESULT parse_ssml_prosody_elem(struct xml_parser *parser, SPVSTATE state, const struct xml_elem *parent) @@ -509,6 +516,16 @@ static HRESULT parse_ssml_prosody_elem(struct xml_parser *parser, SPVSTATE state { L"x-fast", 9 }, };
+ static const struct string_value volume_values[] = + { + { L"silent", 0 }, + { L"x-soft", 20 }, + { L"soft", 40 }, + { L"medium", 60 }, + { L"loud", 80 }, + { L"x-loud", 100 }, + }; + struct xml_attr attr; BOOL end = FALSE; size_t read_len; @@ -542,6 +559,29 @@ static HRESULT parse_ssml_prosody_elem(struct xml_parser *parser, SPVSTATE state else state.RateAdj = lround(log(rate) * (10 / log(3))); } + else if (xml_attr_eq(&attr, L"volume")) + { + double volume; + + if (lookup_string_value(volume_values, ARRAY_SIZE(volume_values), &attr.value, (LONG *)&state.Volume)) + continue; + + if (FAILED(hr = parse_double_value(&attr.value, &volume, &read_len))) + return hr; + if (read_len < attr.value.len - 1 || + (read_len == attr.value.len - 1 && attr.value.ptr[read_len] != '%')) + { + ERR("Invalid value %s for the volume attribute in <prosody>.\n", debugstr_xmlstr(&attr.value)); + return SPERR_UNSUPPORTED_FORMAT; + } + + if (attr.value.ptr[attr.value.len - 1] == '%') + volume = state.Volume * (1 + volume / 100); + else if (attr.value.ptr[0] == '+' || attr.value.ptr[0] == '-') + volume = state.Volume + volume; + + state.Volume = lclamp(lround(volume), 0, 100); + } else { FIXME("Unknown <prosody> attribute %s.\n", debugstr_xmlstr(&attr.name));