Vocalizer: Run Local Text-to-Speech in PHP with No API Calls
Open Source PHP #text-to-speech #PHP extension #voice cloning #TTS #local AI #NativePHP

Vocalizer: Run Local Text-to-Speech in PHP with No API Calls

3 min read Mohamed Said Mohamed Said

What Is Vocalizer?

Vocalizer is a native PHP extension by Akram Zerarka that brings local text-to-speech (TTS) synthesis to PHP applications. It embeds two inference backends — sherpa-onnx (ONNX Runtime) and audio.cpp (ggml) — and ships as a prebuilt .so binary for Linux x86-64. There is nothing to compile and no external API to call.

Eight Model Families, One API

Engine::load() points at a model directory, auto-detects the backend from its contents, and exposes a single speak() call:

use Vocalizer\Engine;

$engine = Engine::load('/opt/voices/sherpa-onnx-supertonic-3-tts-int8-2026-05-11');

$res = $engine->speak('Votre commande est prête.', [
    'lang'       => 'fr',
    'voice'      => 0,
    'speed'      => 1.0,
    'timeout_ms' => 30_000,
]);

$res->save('/var/www/audio/notice.wav');
echo $res->seconds, " s in ", $res->generationMs, " ms\n";

The supported model families and their trade-offs:

| Goal | Model | Latency (CPU) | |---|---|---| | Best realism, voice cloning | Chatterbox | Slow (~20× real time) | | Fast multi-language (31 languages) | Supertonic 3 | Real-time | | Lightweight FR/EN cloning | Pocket TTS | Fast | | Fastest, one model per locale | Piper/VITS | Very fast |

Voice Cloning with Chatterbox

Chatterbox covers 23 languages with a single ~7.5 GB model and clones a voice from a 3–10 second reference WAV:

$engine = Engine::load('/opt/voices/chatterbox', [
    'threads' => 4,
    'opts'    => ['weight_type' => 'f16'],
]);

$res = $engine->speak('Bonjour, votre commande est prête.', [
    'lang'      => 'fr',
    'reference' => '/opt/voices/refs/fr.wav',
    'opts'      => [
        'temperature'        => 0.6,
        'repetition_penalty' => 1.2,
        'seed'               => 42,
    ],
    'timeout_ms' => 600_000,
]);

Because autoregressive TTS models can skip text, loop, or produce silence, Vocalizer includes an anti-hallucination guard. Every Chatterbox output is checked against text length and signal energy. Suspicious audio is re-synthesized with a new seed (two extra attempts by default). If all attempts fail, a Vocalizer\Exception is thrown, making a fallback to a faster model straightforward:

try {
    $res = $engine->speak($text, ['lang' => 'fr', 'reference' => $ref]);
} catch (\Vocalizer\Exception $e) {
    $res = Engine::load('/opt/voices/sherpa-onnx-supertonic-3-tts-int8-2026-05-11')
        ->speak($text, ['lang' => 'fr']);
}

Crash Isolation and Async Synthesis

Native inference engines can segfault. Vocalizer's default fork isolation mode runs synthesis in a child process, so a crash is caught, retried, and the model reloaded — surfacing as a Vocalizer\CrashException only when recovery fails. Chatterbox always runs in direct mode because its ggml thread pool is not fork-safe.

For longer texts, speakAsync() moves synthesis off the request path:

$job = $engine->speakAsync($paragraph);
$res = $job->wait(30_000) ?? throw new RuntimeException('still running');

Key php.ini directives: vocalizer.isolation, vocalizer.timeout_ms, vocalizer.max_models (LRU model cache per worker), and vocalizer.max_concurrency for the async pool.

Installation

Vocalizer requires Linux x86-64, glibc ≥ 2.28, and PHP 8.4 or 8.5 NTS. Alpine/musl, ARM, and ZTS builds are not supported.

curl -fsSL https://raw.githubusercontent.com/akramzerarka/vocalizer/main/install.sh | bash

Models are downloaded separately:

./scripts/download-model.sh chatterbox                                    # ~7.5 GB
./scripts/download-model.sh sherpa-onnx-supertonic-3-tts-int8-2026-05-11  # ~120 MB
./scripts/download-model.sh vits-piper-en_US-amy-low                      # ~65 MB

Key Takeaways

  • Runs entirely on-device — no API keys, no network calls, no runtime dependencies to compile.
  • Eight TTS model families auto-detected from a directory; one unified speak() API.
  • Voice cloning from a short WAV reference via Chatterbox (23 languages, ~7.5 GB model).
  • Anti-hallucination guard re-synthesizes suspicious output before throwing an exception.
  • Fork isolation protects PHP-FPM workers from native engine crashes.
  • speakAsync() keeps long synthesis jobs off the request path.
  • Requires Linux x86-64, glibc ≥ 2.28, PHP 8.4/8.5 NTS; MIT-licensed.

Source: Vocalizer: Local Text-to-Speech for PHP — Laravel News

Found this useful?

Frequently Asked Questions

3 questions
Q01 Does Vocalizer require an external API or internet connection to synthesize speech?
No. Vocalizer runs entirely on-device. It embeds the sherpa-onnx and audio.cpp inference backends directly in the PHP extension, so no API calls or network access are needed at synthesis time.
Q02 Which PHP versions and operating systems does Vocalizer support?
Vocalizer requires Linux x86-64 with glibc 2.28 or higher and PHP 8.4 or 8.5 NTS. Alpine/musl, ARM, and ZTS builds are not currently supported.
Q03 What happens if a native inference engine crashes during synthesis?
By default, Vocalizer runs synthesis in a forked child process. If the child crashes, it is retried and the model reloaded automatically. A Vocalizer\CrashException is only thrown if recovery fails after the configured maximum retries.

Continue reading

More Articles

View all