From: Shaun Ren sren@codeweavers.com
--- dlls/sapi/tests/tts.c | 4 ++-- dlls/sapi/xml.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 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 97305df344c..1446b045de8 100644 --- a/dlls/sapi/xml.c +++ b/dlls/sapi/xml.c @@ -475,6 +475,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) @@ -522,6 +529,41 @@ static HRESULT parse_ssml_prosody_elem(struct xml_parser *parser, SPVSTATE state state.RateAdj = lround(log(rate) * (10 / log(3))); } } + else if (xml_attr_eq(&attr, L"volume")) + { + if (xmlstr_eq(&attr.value, L"silent")) + state.Volume = 0; + else if (xmlstr_eq(&attr.value, L"x-soft")) + state.Volume = 20; + else if (xmlstr_eq(&attr.value, L"soft")) + state.Volume = 40; + else if (xmlstr_eq(&attr.value, L"medium")) + state.Volume = 60; + else if (xmlstr_eq(&attr.value, L"loud")) + state.Volume = 80; + else if (xmlstr_eq(&attr.value, L"x-loud")) + state.Volume = 100; + else + { + double volume; + + 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));