ssml · Rust · no network · no credentials · XML only
ssml
ssml writes Speech Synthesis Markup Language, the XML that tells Azure Speech which voice to use and how to deliver a line. Text comes from an argument or stdin, delivery from flags, and one well-formed document goes to stdout. It makes no network calls and reads no credentials, and the same input always produces the same bytes.
ssml --model MAI-Voice-2.1 --voice en-US-Iris --emotion cheerful --degree 1.2 'Good morning.'
<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts' xml:lang='en-GB'><voice name='en-US-Iris:MAI-Voice-2.1'><lang xml:lang='en-GB'><mstts:express-as style='cheerful' styledegree='1.20'><prosody rate='+0.00%' pitch='+0.00%' volume='100.00'>Good morning.</prosody></mstts:express-as></lang></voice></speak>
Flags to markup
--style, --emotion and --express-as are aliases, as are --embedding and --speaker-profile-id.--embedding, the voice is a cloned profile rather than a named persona (the ID here is a placeholder).Escaping and validation
Text is text
Input is literal plain text, never SSML and never a prompt to a model. Everything is escaped:
ssml 'Fish & chips <3 "quoted"'
…<prosody rate='+0.00%' pitch='+0.00%' volume='100.00'>Fish & chips <3 "quoted"</prosody>…
Invalid is an error
A degree or a role only means something with a style, so asking for one without the other fails with exit code 2 rather than emitting markup a service would quietly ignore:
ssml --model MAI-Voice-2.1 --voice en-US-Iris --degree 1.2 'Role without style'
ssml: role/degree require style
| Speed | 0.5–3, a multiplier |
|---|---|
| Pitch | −50 to +50 percent |
| Volume | 0–100 |
| Style degree | 0.01–2 |
| Input | one argument, - or stdin, at most 1 MiB |
Defaults are MAI-Voice-2.1-Flash in British English at normal speed, with no embedding or emotion. Named MAI voices become name:model; already qualified voices are left alone; --model azure takes standard Azure voice names. Exit codes: 0 for success (a closed output pipe included), 1 for I/O, 2 for invalid arguments.
Whether a deployment accepts a combination is the service's business: syntactically valid SSML is not a promise that a model supports every style, role or prosody value.
Where it is used
The same document comes out of three tools. aztts links the Rust library to escape and wrap text before sending it to Azure. The Read Aloud Chrome extension builds SSML with its own JavaScript builder, and ssml --config speech.json accepts that extension's Speech settings object in place of flags, so the same settings object describes a voice in the browser and in a shell.