https://github.com/crazy-goat/piper-php
PHP text-to-speech library using Piper TTS via FFI — streaming audio, warm-up support, 40+ languages, zero dependencies
https://github.com/crazy-goat/piper-php
audio ffi machine-learning neural-tts no-dependencies onnx-runtime php php-library piper piper-tts speech-synthesis streaming-audio text-to-speech tts
Last synced: 2 months ago
JSON representation
PHP text-to-speech library using Piper TTS via FFI — streaming audio, warm-up support, 40+ languages, zero dependencies
- Host: GitHub
- URL: https://github.com/crazy-goat/piper-php
- Owner: crazy-goat
- Created: 2026-03-30T20:45:02.000Z (3 months ago)
- Default Branch: master
- Last Pushed: 2026-03-31T07:46:43.000Z (3 months ago)
- Last Synced: 2026-04-03T05:07:57.810Z (2 months ago)
- Topics: audio, ffi, machine-learning, neural-tts, no-dependencies, onnx-runtime, php, php-library, piper, piper-tts, speech-synthesis, streaming-audio, text-to-speech, tts
- Language: PHP
- Size: 1.05 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Piper PHP
Text-to-speech in PHP using [Piper](https://github.com/OHF-Voice/piper1-gpl) via FFI.
[](https://php.net/)
[](LICENSE)
Fast, local text-to-speech synthesis without external services. Piper runs entirely on your machine using ONNX Runtime.
## Features
- 🚀 **Fast** - Local synthesis, no network latency
- 🔊 **High quality** - Uses Piper neural TTS models
- 📦 **Easy installation** - Composer package with FFI
- 🎯 **Simple API** - Load model once, synthesize many times
- ⚡ **Warm-up support** - Avoid first-chunk delay in production
- 🔄 **Streaming** - Generate audio chunk by chunk for real-time playback
## Requirements
- PHP >= 8.2 with FFI extension enabled
- Piper library (libpiper.so) and ONNX Runtime
- Voice models (.onnx files)
## Installation
```bash
composer require crazy-goat/piper-php
# Download pre-built libraries
vendor/bin/piper-tts install-deps
```
This will download and extract to `vendor/crazy-goat/piper-php/libs/`:
- `libpiper.so` - Piper library
- `libonnxruntime.so` - ONNX Runtime
- `espeak-ng-data/` - Phoneme data
### Manual Download
If you prefer to download manually or need a specific version:
```bash
# Download individual libraries
wget https://github.com/crazy-goat/piper-php/releases/latest/download/libpiper-linux-x86_64.tar.gz
wget https://github.com/crazy-goat/piper-php/releases/latest/download/libonnxruntime-linux-x86_64.tar.gz
wget https://github.com/crazy-goat/piper-php/releases/latest/download/espeak-ng-data.tar.gz
# Extract
tar -xzf libpiper-linux-x86_64.tar.gz
tar -xzf libonnxruntime-linux-x86_64.tar.gz
tar -xzf espeak-ng-data.tar.gz
```
### Building from Source
If you prefer to build from source or need a different architecture:
```bash
# Clone with submodules
git clone --recursive https://github.com/crazy-goat/piper-php.git
cd piper-php
# Or initialize submodules if already cloned
git submodule update --init --recursive
# Build libpiper and copy to libs/ (like composer does)
make build-libs
# Or build everything including espeakbridge
make build-piper1
```
The build will create:
- `libs/libpiper.so` - Piper library (copied to project root)
- `libs/libonnxruntime.so` - ONNX Runtime (with all versioned files)
- `libs/espeak-ng-data/` - Phoneme data
### Running Examples Locally
If you're developing locally (not via composer), build libraries and run examples:
```bash
# Build libraries and copy to libs/ directory
make examples
# Download a voice model
./bin/piper-tts download en_US-lessac-medium ./models
# Run example
php examples/speak.php "Hello world"
```
This is equivalent to running `vendor/bin/piper-tts install-deps` for composer users.
### Downloading Voice Models
Use the included CLI tool to download voices from HuggingFace:
```bash
# List available voices
./bin/piper-tts list
# Filter by language
./bin/piper-tts list --language=pl
# Download a voice
./bin/piper-tts download en_US-lessac-medium ./models
# List installed voices
./bin/piper-tts installed ./models
```
Or download manually from [HuggingFace](https://huggingface.co/rhasspy/piper-voices/tree/main).
## Quick Start
```php
loadModel('en_US-lessac-medium', warmUp: true);
// Synthesize text to WAV
$wav = $model->speak('Hello! This is Piper text to speech in PHP.');
file_put_contents('output.wav', $wav);
```
### Custom Library Paths (Optional)
If you need to use custom library locations:
```php
$piper = new PiperTTS(
modelsPath: __DIR__ . '/models',
libpiperPath: '/custom/path/libpiper.so', // optional
onnxrtPath: '/custom/path/libonnxruntime.so', // optional
espeakDataPath: '/custom/path/espeak-ng-data', // optional
);
```
## API Reference
### PiperTTS
Main factory class for loading models.
```php
$piper = new PiperTTS(
modelsPath: '/path/to/models', // Directory with .onnx files
libpiperPath: '/path/to/libpiper.so', // Optional: auto-detected if null
onnxrtPath: '/path/to/libonnxruntime.so', // Optional: auto-detected if null
espeakDataPath: '/path/to/espeak-ng-data', // Optional: auto-detected if null
);
```
#### Methods
- `loadModel(string $voice, bool $warmUp = false): LoadedModel` - Load a voice model
- `voices(): VoiceInfo[]` - List available voices in models directory
### LoadedModel
Represents a loaded voice model. Reuse this instance for multiple synthesis calls.
#### Methods
- `speak(string $text, float $speed = 1.0, int $speakerId = 0): string` - Synthesize to WAV
- `speakStreaming(string $text, float $speed = 1.0, int $speakerId = 0): \Generator` - Stream chunks
- `warmUp(): int` - Warm up the model, returns time in milliseconds
- `free(): void` - Explicitly free resources (called automatically in destructor)
### Speed Control
Adjust speech speed with the `speed` parameter:
```php
// 2x faster
$fast = $model->speak('Hello world', speed: 2.0);
// 0.5x slower (half speed)
$slow = $model->speak('Hello world', speed: 0.5);
```
### Streaming
For real-time applications, use streaming to get audio chunks as they're generated:
```php
foreach ($model->speakStreaming('First sentence. Second sentence.') as $chunk) {
// $chunk->pcmData - Raw 16-bit PCM audio
// $chunk->sampleRate - Sample rate (e.g., 22050)
// $chunk->isLast - True if this is the final chunk
// Send to audio player, WebSocket, etc.
$player->play($chunk->pcmData);
}
```
## Production Tips
### Warm-up
The first inference in ONNX Runtime is slow (~900ms) due to initialization. Use warm-up to avoid this delay:
```php
// Option 1: Auto warm-up on load (recommended)
$model = $piper->loadModel('voice', warmUp: true);
// Option 2: Manual warm-up with timing
$model = $piper->loadModel('voice');
$ms = $model->warmUp();
echo "Warmed up in {$ms}ms";
```
### Reuse Models
Load the model once and reuse for multiple synthesis calls:
```php
// Good: Load once, use many times
$model = $piper->loadModel('en_US-lessac-medium', warmUp: true);
foreach ($texts as $text) {
$wav = $model->speak($text);
// ...
}
// Bad: Loading model on every request (slow!)
foreach ($texts as $text) {
$model = $piper->loadModel('en_US-lessac-medium'); // Don't do this
$wav = $model->speak($text);
}
```
### Long-Running Processes
For daemons or workers, load models at startup:
```php
// At application startup
$piper = new PiperTTS('/path/to/models');
$voiceCache = [];
function getVoice($piper, $voiceKey) {
global $voiceCache;
if (!isset($voiceCache[$voiceKey])) {
$voiceCache[$voiceKey] = $piper->loadModel($voiceKey, warmUp: true);
}
return $voiceCache[$voiceKey];
}
// In request handler
$model = getVoice($piper, 'en_US-lessac-medium');
$wav = $model->speak($userText);
```
## Examples
See the `examples/` directory:
- `speak.php` - Basic text-to-speech with timing
- `stream.php` - Streaming synthesis with per-chunk timing
- `warmup.php` - Manual warm-up demonstration
- `autowarmup.php` - Automatic warm-up on model load
Run examples:
```bash
php examples/speak.php "Hello world"
php examples/stream.php "First sentence. Second sentence."
php examples/autowarmup.php "Test text"
```
## Performance
Typical performance on modern CPU:
| Operation | Time |
|-----------|------|
| Model loading | ~900ms |
| Warm-up | ~70ms |
| Synthesis (after warm-up) | ~70-150ms per sentence |
| First chunk (without warm-up) | ~900ms |
| First chunk (with warm-up) | ~70ms |
## Troubleshooting
### FFI extension not found
Enable FFI in your `php.ini`:
```ini
extension=ffi
```
### Library not found errors
Specify full paths to libraries in the PiperTTS constructor:
```php
$piper = new PiperTTS(
modelsPath: '/full/path/to/models',
libpiperPath: '/full/path/to/libpiper.so',
onnxrtPath: '/full/path/to/libonnxruntime.so',
espeakDataPath: '/full/path/to/espeak-ng-data',
);
```
### ONNX Runtime errors
Make sure all library dependencies are available:
```bash
# Check library dependencies
ldd /path/to/libonnxruntime.so
ldd /path/to/libpiper.so
```
## License
MIT License - see [LICENSE](LICENSE) file.
## Credits
- [Piper](https://github.com/rhasspy/piper) - Fast, local neural text-to-speech
- [ONNX Runtime](https://onnxruntime.ai/) - Cross-platform ML inference
- [espeak-ng](https://github.com/espeak-ng/espeak-ng) - Text-to-phoneme conversion
## Contributing
Contributions welcome! Please submit issues and pull requests on GitHub.