SSMD - Speech Synthesis Markdown

SSMD (Speech Synthesis Markdown) is a lightweight Python library that provides a human-friendly markdown-like syntax for creating SSML (Speech Synthesis Markup Language) documents. It’s designed to make TTS (Text-to-Speech) content more readable and maintainable. See SPECIFICATION.md in the repo for the canonical syntax rules.

PyPI Version Python Versions Code Coverage

Features

✨ Markdown-like syntax - More intuitive than raw SSML

🎯 Scoped SSML output - Generic, SSML 1.1, and provider-adapted targets with explicit loss policies 🔄 Bidirectional - Convert SSMD↔SSML or strip to plain text

📊 Parser API - Extract structured data for custom TTS pipelines

📝 TTS streaming - Iterate through sentences for real-time TTS

🛠️ TTS capabilities - Provider-aware rendering with explicit loss policies 🎨 Extensible - Custom extensions for platform-specific features

🧪 Type-safe - Full mypy type checking support

Canonical SSMD 0.9

New documents declare ssmd_version: "0.9" and use fenced directive blocks instead of raw XML:

---
ssmd_version: "0.9"
---
:::{voice="host"}
Hello *world*!
:::

SSML conversion covers explicit supported semantics. Use --target generic, --target ssml-1.1, or --target provider and choose a loss policy rather than assuming universal SSML support.

Structure-only downstream parsing

For downstream TTS pipelines that own written-to-spoken normalization and sentence segmentation, use ssmd.parse_structure() to obtain clean text, annotation ranges, zero-width break/mark/paragraph events, and YAML front matter without invoking sentence detection:

SSMD parse_structure()
    -> caller-owned text normalization
    -> caller-owned sentence segmentation
    -> caller-owned TTS/G2P

Annotations refer to ranges in clean_text; structural event positions refer to boundaries in that text. SSMD removes its markup and preserves metadata, but does not perform general written-to-spoken language normalization.

Quick Example

This quick API example uses body fragments for brevity; standalone files should use the versioned 0.9 document shown above.

import ssmd

# Convert SSMD to SSML
ssml = ssmd.to_ssml("Hello *world*!")
# → <speak>Hello <emphasis>world</emphasis>!</speak>

# Convert SSML back to SSMD
ssmd_text = ssmd.from_ssml('<speak><emphasis>Hello</emphasis></speak>')
# Complete SSMD 0.9 document, starting with a version header:
# ---
# ssmd_version: '0.9'
# ---
# *Hello*

# Strip markup for plain text
plain = ssmd.to_text("Hello *world* @marker!")
# → Hello world!

# Or use the Parser API for structured data
from ssmd import parse_paragraphs

for paragraph in parse_paragraphs("Hello *world*!"):
    for sentence in paragraph.sentences:
        for seg in sentence.segments:
            print(f"Text: {seg.text}, Emphasis: {seg.emphasis}")

Table of Contents

User Guide

Indices and tables