Skip to main content

PiperSynth

PiperSynth is a standalone synthesis engine for Piper-compatible ONNX voices. Callers provide prepared, speakable text; PiperG2P owns phonemization and Piper ID generation, OnnxVoice handles model inference, and PiperSynth applies engine-local acoustic and audio policy. Document parsing, SSMD, written-to-spoken preparation, semantic pauses, markers, timeline composition, and final mastering belong to other layers.

Install

Install PiperSynth with the CPU runtime:

pip install "pipersynth[cpu]"

For GPU inference, install pipersynth[gpu]. OnnxVoice manages catalog lookup, model downloads, caching, provider selection, and ONNX Runtime sessions.

Synthesize prepared text

from pipersynth import PiperVoice

with PiperVoice.from_pretrained("en_US-lessac-medium") as voice:
    result = voice.synthesize_text(
        "Hello, this text is already prepared for speech.",
        language="en-us",
    )
    result.save_wav("hello.wav")

prepared_text is ordinary speakable text, not phoneme IDs. PiperSynth does not expand numbers, dates, abbreviations, or other written forms. Perform that semantic preparation before calling the engine.

Atomic prepared requests

PiperSynth never chooses a new text boundary. Readio or another caller prepares and splits text before sending each atomic request. PiperVoice.synthesize() and synthesize_text() pass the exact request text to PiperG2P and perform at most one acoustic inference. Frontend sentence groups are joined as phoneme IDs for that single inference; PiperSynth does not call Phrasplit or split on punctuation.

from pipersynth import PiperVoice, SynthesisRequest

prepared_text = (
    "The first already-prepared sentence. "
    "The next sentence remains part of this same atomic request."
)

request = SynthesisRequest(
    id="paragraph-001",
    text=prepared_text,
    language="en-us",
)

with PiperVoice.from_pretrained("en_US-lessac-medium") as voice:
    result = voice.synthesize(request)
    result.save_wav("paragraph.wav")

If the complete request exceeds a capacity reported by the model or frontend, PiperSynth raises SynthesisInputTooLongError. It does not retry with smaller pieces. Readio decides the next boundary. For repeated requests, reuse one voice:

from pipersynth import PiperVoice, SynthesisConfig

with PiperVoice.from_pretrained("en_US-lessac-medium", offline=True) as voice:
    result = voice.synthesize_text(
        "A second prepared request.",
        language="en-us",
        config=SynthesisConfig(length_scale=0.9, output_gain=0.8),
    )

Use PiperVoice.from_local("voice.onnx") to open a local model. By default, PiperSynth reads its config from voice.onnx.json.

Typed requests and linguistic context

Use SynthesisRequest for a request with an explicit identity, speaker, pronunciation override, or linguistic token context. Token offsets refer to the exact prepared string, and all supplied token fields, including morph, are forwarded to PiperG2P.

from pipersynth import (
    LinguisticToken,
    PiperVoice,
    PronunciationOverride,
    SynthesisRequest,
)

request = SynthesisRequest(
    id="line-001",
    text="I read the book yesterday.",
    language="en-us",
    pronunciation_overrides=(PronunciationOverride(2, 6, phonemes="ɹɛd"),),
    tokens=(
        LinguisticToken(
            start=2,
            end=6,
            text="read",
            pos="VERB",
            lemma="read",
            morph="Tense=Past",
        ),
    ),
)

with PiperVoice.from_pretrained("en_US-lessac-medium") as voice:
    result = voice.synthesize(request)

SynthesisSegment remains accepted as a compatibility request type. Its annotations become SynthesisRequest.tokens; it follows the same atomic behavior. synthesize_text() is also strict. None of these APIs accepts chunking.

Piper frontend and low-level IDs

PiperG2P may represent one atomic request as several frontend sentence groups. PiperSynth joins their phoneme IDs and performs one model inference for the complete request. It does not expose those groups as independently rendered chunks.

PiperVoice.synthesize_ids() remains available for callers that already have Piper phoneme IDs. ID validation, speaker selection, acoustic controls, voice calibration, and waveform postprocessing still apply.

Audio and calibration

Results contain mono finite float32 audio at the model's native sample rate. SynthesisResult.save_wav() writes mono 16-bit PCM. Conversion clips to the supported PCM range.

SynthesisConfig contains Piper controls (length_scale, noise_scale, and noise_w_scale), optional peak normalization, explicit engine-local output_gain, and static voice_level calibration. PiperSynth does not perform final LUFS or true-peak mastering. Use AudioCompose or another output layer when producing a document, chapter, or mixed timeline.

Voice discovery and providers

from pipersynth import VoiceAssetManager, list_voices

for item in list_voices(language="en", quality="medium"):
    print(item.id, item.name)

manager = VoiceAssetManager(offline=True)
print(manager.get_voice_metadata("en_US-lessac-medium"))

The default inference provider is CPUExecutionProvider. Pass providers and provider_options to PiperVoice.from_pretrained() or PiperVoice.from_local() to select runtime providers. See provider configuration.

Examples and development

Runnable examples are under examples/. They synthesize prepared text with PiperVoice; generated files are written below example-artefacts/ by default.

Run validation with:

python -m pytest
python -m ruff check pipersynth tests examples benchmarks
python -m mypy pipersynth tests/typecheck/engine_api.py

Release files for pipersynth 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pipersynth 0.2.0
File Size Uploaded
pipersynth-0.2.0.tar.gz 173.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pipersynth 0.2.0
File Interpreter ABI Platform
pipersynth-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 310.9 kB

Release files / pipersynth-0.2.0.tar.gz

Download URL pipersynth-0.2.0.tar.gz
Size 173.3 kB
Tags Source
SHA-256 checksum
How to use checksums
f97f5fefaae641f97daeb3709ceb2d41c8d984fb3d8b86b4cce9a4d8df832fc0
BLAKE2b-256 checksum
How to use checksums
0b4ae58f747416382edd6b2f2b55619585dd4a665aeab40abf4f688c9690909a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release files / pipersynth-0.2.0-py3-none-any.whl

Download URL pipersynth-0.2.0-py3-none-any.whl
Size 137.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1476ef94a605e6ba9d1af91cfcf6d75813d8919c4570257c0ee83f286ed364ee
BLAKE2b-256 checksum
How to use checksums
d401b6ef4b077bd1b5f7abe7c44df212c195fa3e48b2eca6ce151c6435ec97d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page