Qwen3-TTS SSML and SSML-H processor profile
The normative SSML-H 1.0 specification
is maintained in ssml-h-spec.
This document describes this processor’s supported subset. SSML-H is a Hangry
Labs extension to W3C SSML 1.1, not a W3C standard or a claim of full conformance.
The implementation uses ssml-h-tools==0.3.1.
Choose input_type="ssml" or "ssml-h" explicitly on native API routes. Text
mode and OpenAI input never auto-detect markup. Compile with /tts/plan or
inspect /tts/ssml/capabilities without loading a model.
Standard subset
Require one <speak> root, optionally using namespace
http://www.w3.org/2001/10/synthesis and version 1.0 or 1.1. Supported elements:
metadata, p, s, token, w, voice, lang, break, prosody, sub,
say-as. Unknown elements, attributes, namespaces, DTDs, entities and external
references fail before inference. <audio>, <phoneme> and lexicons are rejected.
Qwen consumes text tokens and does not expose a direct IPA input contract.
<voice name="Ryan"> selects a native speaker or saved unique name/id. A voice
switch uses that voice’s language unless an enclosing explicit xml:lang
overrides it. <lang xml:lang="de-DE"> changes the language while retaining
the voice. Supported languages are Chinese, English, Japanese, Korean, German,
French, Russian, Portuguese, Spanish and Italian; corresponding language codes
and regional BCP-47 tags are accepted. Voice identity and language are distinct.
<prosody rate="125%" pitch="+2st" volume="soft"> applies FFmpeg time stretch,
pitch shift and gain to that unit. Standard named presets and bounded numeric
forms are accepted by the shared parser. Nested rates/volumes multiply, pitches
add, and request speed multiplies the effective rate. Effective rate must be
0.25 to 4; shared bounds also enforce pitch and volume. Large transformations
can introduce artifacts. Complete-recording loudness normalization runs once
after assembly, never independently per turn.
<break time="350ms"/> and seconds are supported, as are standard strengths.
Only internal model padding is compacted. Adjacent speech gets a 120 ms handoff.
An explicit break replaces that gap, including 0ms; outer recording edges
are preserved. Consecutive explicit breaks add. <sub alias="spoken words">
substitutes text; say-as supports characters, digits, cardinal and English
ordinal forms. Element tails retain their parent voice/language/prosody.
SSML-H voices and direction
<speak version="1.1" xmlns="http://www.w3.org/2001/10/synthesis"
xmlns:h="https://hangrylabs.app/ns/ssml-h/1.0" xml:lang="en-US">
<metadata>
<h:extensions version="1.0">
<h:voice-definition name="Mara" scope="request" seed="1234">
<h:description>A warm adult woman with a clear, gentle voice.</h:description>
<h:sample xml:lang="en-US">Hello. My name is Mara. I enjoy telling stories.</h:sample>
</h:voice-definition>
</h:extensions>
</metadata>
<voice name="Mara" h:direction="Quietly, with cautious optimism.">We are ready.</voice>
<break time="350ms"/>
<voice name="Mara">Let us begin.</voice>
</speak>
VoiceDesign 1.7B creates each bootstrap reference. Base 0.6B clones that same
reference and exact known transcript for every matching turn. The reference is
request-owned; no ASR or network audio fetch is needed. Supported design
descriptors are gender, age, pitch, style, languages, accent, dialect and a
bounded free-form description. These become a voice description, with
probabilistic instruction following rather than guaranteed speaker traits.
Unsupported languages are rejected. If h:sample is omitted, use the deterministic
English passage advertised by the capabilities endpoint.
scope="request" keeps the voice in memory only. scope="profile" stages an
audio-backed profile and publishes it atomically with the other new profiles
after successful synthesis and encoding. A failed/cancelled stream publishes
none. replace="true" is required for an existing saved name; request definitions
cannot shadow saved or native voices. A single-turn Magic preview does not
commit document profiles. The explicit UI Save voice action saves the selected
generated take as a new clone reference.
h:direction works on <voice> and <s>, up to 240 characters. It directs
that turn without changing the reference identity. Base supports experimental
delivery instructions. Native directions require 1.7B CustomVoice; explicit
0.6B CustomVoice requests with direction fail before inference. Turn pitch
effects are separate from a definition’s pitch descriptor.
Limits and streaming
Source: 50000 characters, 300 elements, nesting 12, 200 semantic units, 12 voice definitions, 500 bootstrap/description characters each, 10 seconds per break, 60 seconds of breaks total. The Qwen processor further limits requests to 64 compiled speech units, 6000 spoken characters and 300 seconds of output. Automatic splitting uses at most 400 characters per call; disabling long-audio protection raises the unit limit to 1000 without silently truncating text.
Full output, progressive audio, native SSE, Magic and plan inspection use the same validation, routing and boundary rules. Markup streams codec audio within speech units, with bounded internal-edge buffering and per-unit prosody filters. Optional normalization processes the assembled stream once. One request-owned FIFO lease serializes inference across models. System controls which defaults remain resident; request-only weights release after the complete document. Crossing between native speakers and clones loads any missing checkpoints; design references are prepared together and reused across all matching turns. See API.