This is the documentation of the unity package distributed here: Piper-TTS Unity Package
PiperTTS is a fully offline, cross-platform Text-To-Speech system for Unity.
It uses Piper VITS neural voices (from Rhasspy) and runs locally using Sherpa-ONNX inference.
Features
- ✅ No internet required
- ✅ High-quality neural voices
- ✅ Works on mobile + desktop
- ✅ Threaded, cancelable, non-blocking synthesis
| Platform | Status | Notes |
|---|---|---|
| Windows (x86_64) | ✅ | Uses .dll native libs |
| Android (ARM64) | ✅ | Uses .so libs + streaming asset extraction |
| iOS | ✅ | Uses .xcframework + tts_bridge.mm, built during Xcode export |
| macOS (Intel + Apple Silicon) | ✅ | Universal .dylib included |
Assets/
PiperTTS/
StreamingAssets/
tts/
espeak-ng-data/
voices/
<voice-id>/
<model or voice-id>.onnx
tokens.txt
index.json
You can browse the voices available here https://rhasspy.github.io/piper-samples/
Then, download the desired voice from here https://github.com/k2-fsa/sherpa-onnx/releases/tag/tts-models
Extract like this (note espeak-ng-data is the same for all voices):
Assets/StreamingAssets/tts/espeak-ng-data/...
Assets/StreamingAssets/tts/voices/<voice-id>/model.onnx
Assets/StreamingAssets/tts/voices/<voice-id>/tokens.txt
Unity Menu:
TTS → Build Index.json
This scans Assets/StreamingAssets/tts/** and generates:
Assets/StreamingAssets/index.json
using PiperTTS;
TtsController.instance.Speak("Hello world.");Stop audio:
TtsController.instance.StopAudio();Cancel synthesis:
TtsController.instance.CancelSpeak();Select your TtsController component.
A dropdown will list all voices under Assets/StreamingAssets/tts/voices/.
- If no voices are found, a warning appears with a shortcut to open StreamingAssets.
- When in Play Mode, changing the dropdown will immediately reload the selected voice.
- Note the index.json must have been reinitialized (TTS> Build index.json) after a new model was placed in the StreamingAssets
You can still set it manually:
TtsController.instance.SetVoice("en_US-amy-medium");_tts.Initialize(
persistentTtsRoot,
voiceId: "en_US-amy-medium",
sampleRate: 22050,
threads: 2
);Make sure the folder exists:
StreamingAssets/tts/voices/en_US-amy-medium/
You can avoid shipping voice files directly inside your app.
To enable remote delivery:
- In the TtsController component, set Delivery Mode =
RemoteDownload. - Host your
index.jsonand/tts/...folders online (e.g.,https://example.com/tts/index.json). - Set Remote Index URL to the URL of your hosted
index.json. - On first run, the plugin downloads all listed voice/model files into
Application.persistentDataPath/tts/.
Switch back to StreamingAssets mode to include voices inside the build.
| Platform | Files | Folder |
|---|---|---|
| Windows | onnxruntime.dll, sherpa-onnx-c-api.dll, tts_bridge.dll |
Assets/Plugins/x86_64/ |
| Android | *.so |
Assets/Plugins/Android/arm64-v8a/ |
| iOS | tts_bridge.mm, sherpa-onnx.xcframework, onnxruntime.xcframework |
Assets/Plugins/iOS/ |
| macOS | *.dylib |
Assets/Plugins/macOS/ |
- Plugin is compiled during Xcode build
- No manual linking required
- Post-build script automatically adds XCFrameworks and settings
For App Store distribution:
codesign --force --sign "Developer ID Application: YourTeamID" --timestamp --options runtime <file.dylib>Create:
Assets/PiperTTS/THIRD-PARTY-NOTICES.md
PiperTTS includes components under the following licenses:
Sherpa-ONNX (Apache 2.0)
https://github.com/k2-fsa/sherpa-onnx
ONNX Runtime (MIT)
https://github.com/microsoft/onnxruntime
Piper VITS models (various open voice licenses)
See: https://github.com/rhasspy/piper
and individual voice folders for license files.
No voices in the dropdown
- Make sure your voices are under
Assets/StreamingAssets/tts/voices/<voice-id>/. - Run TTS > Build Index.json after adding or removing voice folders.
- If still empty, click Refresh Voices in the Inspector.
"Missing dir: espeak-ng-data" or "tts_create failed"
- Ensure
Assets/StreamingAssets/tts/espeak-ng-data/exists (required by Piper). - Re-run TTS > Build Index.json.
Voice won’t switch at runtime
- When in Play Mode, changing the Inspector dropdown hot-swaps the model immediately.
- If you add a brand-new voice folder while Unity is already running, build a fresh
index.jsonand use Refresh Voices.
Remote download never starts
- Set Delivery Mode =
RemoteDownload. - Remote Index URL must point to the hosted
index.json. - The hosted site must serve all
/tts/...files listed in that index.