Quick Start
This guide will help you get started with SSMD quickly.
Canonical SSMD 0.9 input
New standalone documents declare their dialect. Use canonical fenced directives and attribute names:
---
ssmd_version: "0.9"
---
:::{voice="host"}
Hello *world*!
:::
[Bonjour]{lang="fr"}
[urgent]{volume="loud" rate="fast" pitch="high"}
Unversioned files retain legacy compatibility behavior. Run ssmd migrate FILE --to 0.9
for an explicit semantic-equivalence-checked upgrade.
Basic Conversion
The convenience-function samples use short body fragments for clarity. Add the 0.9 front matter shown above when saving source as a standalone document. For machine-driven authoring, use the root-level JSON interface and check both the process exit status and command-specific result fields:
ssmd --json create draft.ssmd.md -o output.ssmd.md --fail-on-warn
ssmd --json lint output.ssmd.md --roundtrip --fail-on-warn
ssmd --json inspect output.ssmd.md --spans
ssmd --json to-ssml output.ssmd.md -o output.ssml
ssmd --json text output.ssmd.md
Creation is complete only when result.created == true, bytes_written is nonzero, and
the output exists; linting is complete only when result.passed == true.
The simplest way to use SSMD is with the convenience functions:
SSMD to SSML
import ssmd
# Convert SSMD markup to SSML
ssml = ssmd.to_ssml("Hello *world*!")
print(ssml)
# Output: <speak>Hello <emphasis>world</emphasis>!</speak>
# More complex example
ssml = ssmd.to_ssml("""
# Welcome
Hello *world*!
This is a ...500ms pause.
[Bonjour]{lang="fr"} everyone!
""")
Strip Markup
Remove all SSMD markup to get plain text:
import ssmd
plain = ssmd.to_text("Hello *world* @marker!")
print(plain)
# Output: Hello world!
SSML to SSMD
Convert SSML back to SSMD format:
import ssmd
ssml = '<speak><emphasis>Hello</emphasis> world</speak>'
ssmd_text = ssmd.from_ssml(ssml)
print(ssmd_text)
# Default output is a complete SSMD 0.9 document:
# ---
# ssmd_version: '0.9'
# ---
# *Hello* world
Using the Document API
For building and managing TTS content, use the Document class:
Sentence/list operations such as split(), sentences(), indexing, and len() are
legacy APIs for unversioned or SSMD 0.8 documents. SSMD 0.9 documents, including results
from Document.from_ssml(), use a structural model and reject those sentence-level
operations. Use ssmd.parse_structure() or ssmd.parse_spans() for 0.9 structure, and
supply explicit sentence spans to conversion when needed.
Creating Documents
from ssmd import Document
# Create an empty document
doc = Document()
# Create with initial content
doc = Document("Hello *world*!")
# Create with configuration
doc = Document(
config={'auto_sentence_tags': True},
capabilities='pyttsx3'
)
Building Documents
from ssmd import Document
# Build incrementally
doc = Document()
doc.add_sentence("Hello and *welcome*!")
doc.add_sentence("This is SSMD.")
doc.add_paragraph("Starting a new paragraph.")
# Method chaining
doc = Document() \
.add("Hello ") \
.add("*world*!") \
.add_sentence("Next sentence.")
Exporting Documents
from ssmd import Document
doc = Document("Hello *world*!")
# Export to different formats
ssml = doc.to_ssml() # SSML XML
markdown = doc.to_ssmd() # SSMD markdown
text = doc.to_text() # Plain text
# Access properties
print(doc.ssmd) # Raw SSMD content
print(len(doc)) # Number of sentences
print(len(list(doc.paragraphs()))) # Number of paragraphs
TTS Streaming
Iterate through unversioned or SSMD 0.8 documents sentence-by-sentence for TTS. SSMD 0.9 documents require structural parsing and explicit sentence spans instead:
from ssmd import Document
# Create document
doc = Document(config={'auto_sentence_tags': True})
# Build content
doc.add_paragraph("# Chapter 1")
doc.add_sentence("Welcome to SSMD!")
doc.add_sentence("This is the first sentence.")
doc.add_sentence("This is the second sentence.")
doc.add_paragraph("# Chapter 2")
doc.add_sentence("Here's another chapter.")
# Iterate through sentences
for i, sentence in enumerate(doc.sentences(), 1):
print(f"Sentence {i}: {sentence}")
# Your TTS engine here:
# tts_engine.speak(sentence)
# Access specific sentences
sentence_count = len(list(doc.sentences()))
print(f"Total sentences: {sentence_count}")
print(f"Total paragraphs: {len(list(doc.paragraphs()))}")
print(f"First: {doc[0]}")
print(f"Last: {doc[-1]}")
TTS pipeline integration
For an application that normalizes text before sentence splitting, parse SSMD structurally first:
import ssmd
parsed = ssmd.parse_spans(source)
prepared_text = normalize(parsed.clean_text, parsed.annotations)
sentence_spans = split_with_offsets(prepared_text)
ssml = ssmd.to_ssml(source, sentence_spans=sentence_spans)
External spans use offsets in the structural clean-text space after the caller has
remapped them through normalization. SSMD does not perform number normalization,
abbreviation expansion, language detection, or G2P. Explicit ph and ipa annotations
should be marked protected by the downstream normalizer.
Document Editing
Documents support sentence/list editing methods for unversioned or SSMD 0.8 content. These methods are not available on SSMD 0.9 documents.
from ssmd import Document
doc = Document("First. Second. Third.")
# Edit sentences
doc[0] = "Modified first sentence."
del doc[1] # Remove second sentence
# String operations
doc.replace("sentence", "line")
# Insert content
doc.insert(0, "New opening sentence.")
# Clear all content
doc.clear()
Advanced Document Operations
import ssmd
from ssmd import Document
# SSML import creates a complete 0.9 document.
doc09 = Document.from_ssml('<speak><emphasis>Hello</emphasis></speak>')
structure = ssmd.parse_structure(doc09.ssmd, dialect="0.9")
print(structure.clean_text)
# Use the structural parser for 0.9 documents, not sentence/list methods.
# Sentence-level operations remain available for unversioned legacy documents.
legacy_doc = Document("First sentence. Second sentence.")
sentences = legacy_doc.split()
for sent_doc in sentences:
ssml = sent_doc.to_ssml()
ssmd_text = sent_doc.to_ssmd()
Working with TTS Engines
Filter output based on engine capabilities:
Using Presets
from ssmd import Document
# Adapt output using the provider's declared capability profile
source = '---\nssmd_version: "0.9"\n---\n*Hello* [world]{lang="fr"}!'
doc = Document(source, capabilities='espeak')
ssml = doc.to_ssml(target="provider", loss_policy="warn")
diagnostics = doc.render_diagnostics # inspect any adaptations or losses
# A second provider preset applies its own capability profile
doc = Document(source, capabilities='google')
ssml = doc.to_ssml(target="provider", loss_policy="warn")
diagnostics = doc.render_diagnostics
Available presets:
minimal- Plain text onlypyttsx3- Limited prosody and paragraph supportespeak- Breaks, language, prosody, and phoneme supportpolly/amazon- Provider-specific feature profilegoogle/azure- Provider-specific capability adaptation; feature support variesfull- Enable all features implemented by SSMD; not a guarantee of universal SSML support
Custom Capabilities
from ssmd import Document, TTSCapabilities
# Define exactly what your TTS engine supports
caps = TTSCapabilities(
emphasis=True,
break_tags=True,
prosody=False, # No prosody support
language=True
)
doc = Document("*Hello* world!", capabilities=caps)
Common Patterns
Emphasis and Stress
ssmd.to_ssml("This is *important*!")
ssmd.to_ssml("This is **very important**!")
Pauses and Breaks
# Specific duration (required - bare ... is not a break)
ssmd.to_ssml("Hello ...500ms world")
ssmd.to_ssml("Hello ...2s world")
ssmd.to_ssml("Hello ...1s world") # 1 second
# Strength-based
ssmd.to_ssml("Hello ...c world") # comma
ssmd.to_ssml("Hello ...s world") # sentence
ssmd.to_ssml("Hello ...p world") # paragraph
ssmd.to_ssml("Hello ...n world") # none/no break
Voice Control
# Volume
ssmd.to_ssml('[loud]{volume="loud"}')
ssmd.to_ssml('[very loud]{volume="x-loud"}')
ssmd.to_ssml('[soft]{volume="soft"}')
# Speed
ssmd.to_ssml('[fast]{rate="fast"}')
ssmd.to_ssml('[very fast]{rate="x-fast"}')
ssmd.to_ssml('[slow]{rate="slow"}')
# Pitch
ssmd.to_ssml('[high]{pitch="high"}')
ssmd.to_ssml('[very high]{pitch="x-high"}')
ssmd.to_ssml('[low]{pitch="low"}')
Language Switching
ssmd.to_ssml('[Bonjour]{lang="fr"} everyone!')
ssmd.to_ssml('[Hola]{lang="es-MX"} amigos!')
ssmd.to_ssml('[Hello]{lang="en-GB"} there!')
Phonetic Pronunciation
ssmd.to_ssml('[tomato]{ph="təˈmeɪtoʊ"}')
ssmd.to_ssml('[hello]{ipa="həˈloʊ"}')
Next Steps
Read the complete SSMD Syntax Reference reference
Learn about TTS Engine Capabilities filtering
Explore Examples for real-world use cases
Check the API Reference documentation for advanced usage