jk
Writing

The Rust TTS crate that didn't exist

23 April 2026

After speech recognition, tebis needed a voice to answer with. The plan, PLAN-VOICE.md, chose any-tts as “the only actively-maintained path with a permissive license AND zero espeak-ng system dep”. A second plan, PLAN-KOKORO-TTS.md, estimated “~560 LoC, ~6 hours”.

The survey behind it was built from READMEs, and it fell apart at the first build. The commit on 22 April says “Phase 4b blocked: Rust Kokoro ecosystem has no viable crate”:

  • kokoroxide pins ort versions that have all been yanked.
  • kokoro-tiny won’t build without a feature that pulls in rodio, which is MPL-2.0.
  • tts-rs targets an old ort API.
  • any-tts pulls in aws-lc-rs, which tebis bans so it stays on one crypto stack.

Lifting the ban, forking a crate and shelling out to Python were each considered and rejected.

The same day I ported the Kokoro-FastAPI pipeline to Rust. It loads ort dynamically, calls espeak-ng for phonemes, and adds a 30-rule IPA fixup and number normalization. Encoding at Kokoro’s native 24 kHz removed aliasing on the sibilants. The work also found a bug where “* 48 should have been * 48_000”.

It brought back the espeak-ng dependency the plan had tried to avoid. The crate that came out of it, tebis-tts-kokoro, is 1,370 lines, more than twice the 560 the plan expected.