Text-to-Speech (Supertonic)
Supertonic is a fully local text-to-speech engine that converts any text into studio-quality 44.1kHz WAV audio. It runs entirely on CPU via ONNX Runtime — no GPU, no cloud API, no network needed after the initial ~404 MB model download. It synthesizes audio 3-4x faster than real-time on a typical server CPU.
System Requirements
- Python 3.8+
- ~500 MB RAM for model loading
- ~404 MB disk for model files (auto-downloaded on first use)
- No GPU required
Installation
pip install supertonic
On Ubuntu 24.04+ (PEP 668):
pip install supertonic --break-system-packages
Models auto-download from Hugging Face on first synthesis. Cached at ~/.cache/supertonic3/.
Quick Start — Python API
from supertonic import TTS
import soundfile as sf
tts = TTS() # loads supertonic-3 (31 languages)
style = tts.get_voice_style("M1") # male voice
audio, duration = tts.synthesize("Hello, world!", voice_style=style)
sf.write("output.wav", audio.squeeze(), tts.sample_rate)
The bundled script at scripts/synthesize.py wraps this into a one-liner:
python scripts/synthesize.py --text "Hello, world!" --output output.wav
API Reference
Initialization
tts = TTS(
model="supertonic-3", # "supertonic" (en), "supertonic-2" (5 langs), "supertonic-3" (31 langs)
model_dir=None, # override model cache directory
auto_download=True, # auto-download missing models
intra_op_num_threads=None, # ONNX thread count (None = auto)
inter_op_num_threads=None, # ONNX thread count (None = auto)
)
Synthesis
audio, duration = tts.synthesize(
text, # text string (up to 100,000 chars)
voice_style=style, # Style object from get_voice_style()
total_steps=8, # quality: 5=fast, 8=balanced, 12=high
speed=1.05, # speech speed: 0.7 (slow) to 2.0 (fast)
max_chunk_length=None, # chars per chunk (default: 300, Korean: 120)
silence_duration=0.3, # seconds of silence between chunks
lang=None, # language code or None for auto
verbose=False, # print progress
)
# audio: numpy array shape (1, num_samples), float32
# duration: numpy array with total seconds
Voice Styles
10 built-in voices:
- Male: M1 (default), M2, M3, M4, M5
- Female: F1, F2, F3, F4, F5
style = tts.get_voice_style("M1") # by name
style = tts.get_voice_style_from_path("custom.json") # custom voice file
Saving Audio
tts.save_audio(audio, "output.wav") # uses the built-in method
# OR manually with soundfile:
import soundfile as sf
sf.write("output.wav", audio.squeeze(), tts.sample_rate)
Supported Languages (supertonic-3)
en, ko, ja, ar, bg, cs, da, de, el, es, et, fi, fr, hi, hr, hu, id, it, lt, lv, nl, pl, pt, ro, ru, sk, sl, sv, tr, uk, vi
Special code na = unknown language fallback (model tries its best without language-specific tokens).
CLI
supertonic tts "Hello!" -o hello.wav # save to file
supertonic say "Hello!" # play directly (needs sounddevice)
supertonic tts "Bonjour!" -o fr.wav --lang fr --voice F1
supertonic tts "Long text..." -o out.wav --steps 12 --speed 1.2
supertonic list-voices # show available voices
supertonic info # show model info
Common Patterns
Generate audio for a video voiceover
from supertonic import TTS
import soundfile as sf
tts = TTS()
style = tts.get_voice_style("F1")
script = Path("voiceover.txt").read_text()
audio, dur = tts.synthesize(script, voice_style=style, speed=1.0, steps=10)
sf.write("voiceover.wav", audio.squeeze(), tts.sample_rate)
print(f"Generated {dur[0]:.1f}s of audio")
Batch synthesis — multiple files
from supertonic import TTS
import soundfile as sf
tts = TTS()
style = tts.get_voice_style("M2")
segments = [
("intro", "Welcome to our presentation."),
("middle", "Let's dive into the data."),
("outro", "Thank you for listening."),
]
for name, text in segments:
audio, _ = tts.synthesize(text, voice_style=style)
sf.write(f"{name}.wav", audio.squeeze(), tts.sample_rate)
Using the bundled script
# Simple
python scripts/synthesize.py --text "Hello world" --output /tmp/hello.wav
# From file
python scripts/synthesize.py --input script.txt --output narration.wav --voice F2 --steps 10
# With JSON output for programmatic use
python scripts/synthesize.py --text "Test" --output /tmp/test.wav --json
# Piped input
echo "Hello from stdin" | python scripts/synthesize.py --stdin --output /tmp/piped.wav
Convert to MP3 (if ffmpeg available)
ffmpeg -i output.wav -codec:a libmp3lame -qscale:a 2 output.mp3
Performance Tuning
- total_steps: The main quality/speed knob. Default 8 is a good balance. Use 5 for draft/preview, 12 for final output. Diminishing returns above 12.
- speed: 1.05 is the natural default. 1.3-1.5 for informational content, 0.8-0.9 for dramatic effect.
- Threading: Set
SUPERTONIC_INTRA_OP_THREADSandSUPERTONIC_INTER_OP_THREADSenv vars to control ONNX parallelism. Default (None) lets ONNX auto-detect, which is usually optimal. - Long text: Text is auto-chunked at 300 chars (120 for Korean). Adjust
max_chunk_lengthif needed.
Integration Notes
- The
synthesize()return is(audio_array, duration_array)— both are numpy arrays. Useaudio.squeeze()for writing. save_audio()accepts the audio array directly (not the tuple). Passaudionot(audio, duration).- Reuse the
TTS()instance across calls — model loading takes ~1s and should happen once. - For web apps: the package also has JavaScript/browser examples in its GitHub repo using
onnxruntime-web. - License: MIT (code), OpenRAIL-M (model weights) — permissive for commercial use.