Skip to content
gradium-aiPublic

About

Phonon TTS inference using xn

Resources

Stars

17 stars

Watchers

0 watching

Forks

Repository files navigation

Phonon

Streaming speech, on your device.

Phonon brings natural text-to-speech to phones, laptops, browsers, and local services. It is built for offline assistants, accessibility tools, and interactive experiences that need speech without a cloud round trip. The runtime is written in Rust and needs no PyTorch.

Rust CI Python wheels Browser package Native packages Docker builds

Code license: MIT OR Apache-2.0 Discord

Published Rust version Published Python version Published npm version Native downloads Swift package Android QNN package

What you get · Choose an integration · Packages and downloads · Quickstart · Guides

Runtime preview available: Python, Rust, browser packages, and native downloads are published. See the runtime preview release for installation instructions. The unversioned registry commands below target the upcoming stable release and currently select older packages. Phonon model files are available separately from the runtime packages. Docker public access is being finalized.

The browser runs synthesis on your device; it downloads model files on first use.

What you get

  • Small enough to ship: Choose a 40M or 90M parameter model. Both can ship inside a mobile app or load in a browser tab.
  • Five languages in one model: Speak English, French, German, Spanish, and Portuguese, with more languages planned.
  • Fast across devices: A custom inference stack runs in browsers and on phones, laptops, and embedded hardware, with Core ML on Apple devices, a QNN preview for supported Snapdragon NPUs, and GPU support. Multiple backends deliver faster inference than Kokoro and llama.cpp-based runtimes on the same hardware.
  • Voices ready to use or make your own: Choose from ready-to-use voices, or explore voice design and cloning in Gradium Studio.
  • Control the delivery: Adjust speaking speed and start playing streamed audio before the full utterance is ready.

Performance

Choose an integration

You want to… Start here What you need
Generate a speech file Command line A desktop binary and a checkpoint. No Python or Rust required for a published binary.
Add speech to a script or backend Python A Python wheel and a checkpoint.
Run speech in a web app Browser phonon-tts and model files served with your app.
Add speech to an iPhone or Mac app Swift The ptts Swift package and a prepared Core ML bundle.
Add speech to an Android app Android A Kotlin AAR preview for supported Snapdragon NPUs, or the CPU native library. Source build and model files required.
Connect an existing app or self-host Docker and OpenAI-compatible API Docker and a local checkpoint or HF repo.
Embed the runtime in Rust Rust The ptts crate and a checkpoint folder.

Phonon is the product and model identity. The Rust, Python, Swift, and planned Android Maven packages are named ptts; the browser npm package is phonon-tts. This repository remains xn-ptts. Swift apps use import PhononTTS.

Packages and downloads

Packages and native downloads are available as a runtime preview. Follow the runtime preview release to install the preview. The unversioned commands below are the installation paths for the upcoming stable release.

Package Get it Details
Desktop ptts command GitHub Releases or Homebrew tap Linux x64/ARM64, Mac Apple silicon/Intel, and Windows x64 archives, with checksums. Download guide and Homebrew.
Python ptts PyPI Wheels for supported platforms; CPython 3.9+. Python guide.
Browser phonon-tts npm Worker, single-thread and threaded Wasm builds, and TypeScript declarations. Browser guide.
Swift ptts GitHub Releases ptts-swift-<version>.zip and its matching compiled framework. Swift guide.
Android ptts (QNN preview) QNN Android guide Kotlin API and AAR for supported Snapdragon NPUs. Not published to Maven Central yet.
Android CPU library Build guide libptts_ffi.so and a Kotlin wrapper, built from source with Rust and the Android NDK.
ptts-openai-server ghcr.io/gradium-ai/ptts-openai-server:<version> CPU image for amd64 and arm64; model weights downloaded or mounted separately. Server guide.
Rust ptts crates.io Library API; add the cli feature to install the command. Rust guide.

Desktop downloads and Python wheels do not need a Rust compiler. Older x86 CPUs may need a source build: x86 wheels and desktop downloads target x86-64-v3. See the platform requirements in the CLI guide and Python guide.

Model setup

Every integration needs an explicitly selected checkpoint. No model is chosen automatically.

The local examples below use a q8 checkpoint folder supplied to you, for example:

model/
  config.json
  tokenizer.json
  model.q8.gguf
  default-voice.safetensors

Voice files may instead live in voices/ or embeddings/. Use the files and voice names your checkpoint supplies; do not substitute another model's tokenizer or config. The examples use q8 weights. For f32 weights, omit --quant q8 or quant="q8", use Quant::F32 in Rust, and set quant: 'f32' with weights: { f32: '/model/model.safetensors' } in the browser.

Already received a model from us? Extract it locally and use the matching integration below. You do not need a public Hugging Face repo or an HF token for local files. Runtime packages contain no model weights.

Files you received Use them with
A checkpoint with config.json, tokenizer.json, weights and voices Command line, Python, Rust, browser, servers or Android CPU. Use a runtime version compatible with your checkpoint.
A prepared Core ML bundle Swift. Add it to your app as Models, or host it for the Swift download API. A raw checkpoint needs exporting first.
A QNN bundle with metadata.json and compiled context binaries Android NPU. It must match the phone's SoC and the package's QNN runtime. Older bundles may need their target metadata updated; see the preview guide. A raw checkpoint needs exporting and compiling first.

For the shell examples below, set the folder once:

export MODEL_DIR=/absolute/path/to/model

The command line and Python can also acquire a checkpoint from Hugging Face. Use its repo ID and a fixed revision when you want a repeatable model version. Private repos require HF_TOKEN or a saved HF login. Local folders require no Hub access.

lang is required and selects text normalization, such as how numbers and symbols are spoken. Choose en, fr, de, es, pt, or none to pass text through unchanged. This setting does not establish which languages a checkpoint can speak.

Quickstart

These examples use the published runtime preview and a supplied checkpoint. Install the preview using the release instructions, or follow the source setup. The unversioned uvx and registry commands target the upcoming stable release.

Command line

Show command line quickstart

After the stable release, uv can run the Python command in an isolated environment. For the current preview, use the command in the release instructions:

uvx ptts --model "$MODEL_DIR" --lang en --quant q8 "Hello from Phonon." -o speech.wav

uvx manages the Python environment and dependencies.

On Mac or Linux, install the prebuilt desktop command from Gradium's Homebrew tap. It currently installs the 0.4.0-rc.1 runtime preview:

brew install gradium-ai/tap/ptts

You can also extract a desktop archive and put ptts on your PATH. Neither path needs Python or Rust. Generate a WAV with a supplied checkpoint:

ptts --dir "$MODEL_DIR" --lang en --quant q8 "Hello from Phonon." -o speech.wav

The output is a mono 24 kHz WAV. Open it in your audio player.

If you prefer Cargo, install the command with cargo install ptts --locked --features cli after the matching stable release is published.

To download a checkpoint instead, replace the example repo and revision with your own:

ptts --repo OWNER/MODEL --revision COMMIT_SHA --lang en --quant q8 \
  "Hello from Phonon." -o speech.wav

Use --voice NAME to choose a voice; omitting it uses the checkpoint's default selection. Run ptts --help for the remaining options. CLI guide →

Python

Show Python quickstart

For the stable release, install the Python package into your environment. Current preview users should follow the release instructions:

python -m pip install ptts

Then save speech in four lines:

import os
import ptts

tts = ptts.TTS(config=os.environ["MODEL_DIR"], lang="en", quant="q8")
tts.save("speech.wav", "Hello from Phonon.")

Reuse tts. tts.synth(text) returns a float32 NumPy array; tts.stream(text) yields audio chunks:

with tts.stream("Speech can play while the rest is being generated.") as audio:
    for pcm in audio:
        # Send each chunk to your player at audio.sample_rate.
        print(pcm.shape)

Leaving the with block stops generation and releases its workers. For Hub loading, use config="OWNER/MODEL" and revision="COMMIT_SHA".

The wheel also provides a command:

python -m ptts --model "$MODEL_DIR" --lang en --quant q8 \
  "Hello from Phonon." -o speech.wav

Rust and Python both install a command named ptts, with different flags. python -m ptts explicitly selects Python. Python guide →

Browser

Show browser quickstart

For the stable release, install the browser package into your web app. Current preview users should follow the release instructions:

npm install phonon-tts

Serve the checkpoint's files under /model/, then generate a WAV:

import { PhononTTS } from 'phonon-tts';

const tts = await PhononTTS.load({
  lang: 'en',
  model: {
    config: '/model/config.json',
    tokenizer: '/model/tokenizer.json',
    weights: { q8: '/model/model.q8.gguf' },
    voices: { default: '/model/default-voice.safetensors' },
  },
});

const wav = await tts.synthWav('Hello from Phonon.'); // WAV Blob

Use the returned Blob for a download link or your audio player. tts.stream(text) yields mono Float32Array chunks for streaming playback; the browser guide includes a complete Web Audio example. Call tts.dispose() when finished with the model.

The first load downloads and caches the files. onProgress reports download progress. Serve over HTTPS or localhost for caching, and use a browser with WebAssembly SIMD. CPU is the default. Threading and WebGPU setup are covered in the browser guide →.

Swift

Show Swift quickstart

Extract ptts-swift-<version>.zip, add the folder to Xcode as a local package, and select the ptts library product. Swift Package Manager downloads the matching compiled framework. This path needs no Rust build.

Add the prepared Core ML model bundle to your app as a folder reference named Models:

import Foundation
import PhononTTS

guard let bundled = Bundle.main.url(forResource: "Models", withExtension: nil) else {
    throw PhononError(description: "Add the model folder to your app as Models.")
}
let models = try PhononModels.install(bundled: bundled)
let tts = try await Phonon.load(models: models, language: .english)
let player = try PhononPlayer()
try await player.play(tts.stream("Hello from Phonon."))

Keep tts and player in your app's state while audio plays. You can also download models on first run. Requires iOS 18+ or macOS 15+ on Apple silicon. The public Core ML model bundle is still being prepared. Swift guide and Stop example →

Android

Show Android integration options

Snapdragon NPU: The QNN Android preview provides a Kotlin API and an AAR around the optimized QNN engine. It requires Android 12+, ARM64, working QNN HTP support and a model bundle compiled for the phone's SoC. Build the AAR from this repository using its build guide. The planned Maven package is ai.gradium:ptts; it is not published yet.

Load a supplied compiled model folder on a worker thread and stream audio to your player:

import ai.gradium.phonon.PhononTTS

val tts = PhononTTS.load(context, modelDirectory, lang = "en")
val sampleRate = tts.sampleRate
tts.speak("Hello from Phonon.") { pcm ->
    audioSink.write(pcm) // Mono float PCM at sampleRate.
    true // Return false to stop; tts.stop() also works from another thread.
}
// Reuse tts. Stop and wait for speech to finish before calling tts.close().

The preview guide covers native library extraction, model bundles and the runnable Speak/Stop example.

CPU: The existing Android guide provides a Kotlin wrapper and C API. From the repository root:

cargo install cargo-ndk
export ANDROID_NDK_HOME=/path/to/ndk
./android/build.sh

Copy android/jniLibs into your app's src/main/, then add the Kotlin wrapper and JNA dependency as described in the guide. Supply a checkpoint with its own config, tokenizer, weights and voices. Load PhononTTS(modelDir, "en") on a worker thread and reuse it. The guide includes AudioTrack playback, CPU requirements and callback cancellation.

Docker and OpenAI-compatible API

Show Docker and API quickstart

Choose an image version from GitHub Releases and replace <release-version> below, without the leading v. Public GHCR access is being finalized; until then use an image you can access or the source setup. The Docker commands below use Bash or another POSIX shell. Mount your model folder and start the speech server:

PTTS_IMAGE="ghcr.io/gradium-ai/ptts-openai-server:<release-version>"
docker run --rm -p 127.0.0.1:8880:8880 -v "$MODEL_DIR:/models:ro" \
  -e PTTS_CONFIG=/models -e PTTS_LANG=en -e PTTS_QUANT=q8 \
  "$PTTS_IMAGE"

In a second terminal:

curl http://localhost:8880/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"input":"Hello from Phonon.","voice":"default","response_format":"wav"}' \
  -o speech.wav

For applications with an OpenAI-compatible TTS setting, use http://localhost:8880/v1 as the base URL and a voice your checkpoint supports. The server guide includes client setup recipes, supported formats, and limits.

For HF acquisition and a cache that survives container replacement, use the Hub Compose file. Supply the repo, revision, and normalization language explicitly. The image contains no model weights. Deployment and access controls are in the server guide →.

Rust

Show Rust quickstart

Add ptts with tokenizer support to your Rust project. This command targets the upcoming stable release; preview installation is in the release instructions, and source development can use a path dependency:

cargo add ptts --features hf
use ptts::checkpoint::{Checkpoint, ResolveOptions};
use ptts::preprocess::Lang;
use ptts::synth::{DeviceKind, Quant};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let checkpoint = Checkpoint::resolve(
        std::env::var("MODEL_DIR")?,
        ResolveOptions { quant: Quant::Q80, weights: None },
    )?;
    let mut tts = checkpoint.builder(Lang::En).device(DeviceKind::Cpu).build()?;
    checkpoint.register_voices(&mut tts);
    let pcm = tts.say("Hello from Phonon.")?;
    ptts::wav::write_wav_file("speech.wav", &pcm, tts.sample_rate())?;
    Ok(())
}

Build with --release and reuse the model. tts.stream(text)? yields audio chunks for your own playback. The library reads local files; Hub acquisition belongs to the caller. Rust API and small example →

Guides

Topic Guide
Desktop downloads, Homebrew, CPU requirements, CLI flags Command line
Python installation, voices, streaming, and wheels Python
Browser playback, download progress, caching, threads, and WebGPU Browser
Apple installation, model bundles, playback, and cancellation Swift
Android CPU library, Kotlin, NDK, and playback Android
Android Snapdragon NPU AAR, Kotlin API, and compiled bundles QNN Android
Docker, OpenAI-compatible clients, and deployment HTTP server
Streaming text and audio over one connection WebSocket server
Rust library and the say example Rust
Build packages, run the local demo, and develop from source Development

Platform notes

Native desktop packages cover the targets listed in the CLI guide. Apple apps use Core ML. Android apps can use the CPU library or the QNN AAR preview on supported Snapdragon NPUs. QNN requires a matching compiled bundle and has no automatic CPU fallback. Browser apps use Wasm on CPU by default. Browser WebGPU is opt in. The npm package targets browsers, not native Node.js inference.

Performance and memory use depend on the checkpoint and device.

Questions and feedback

Report bugs or request integrations through GitHub Issues. Include your runtime version, device/OS, model revision, weight format, normalization language, and a small reproduction.

Acknowledgements

Phonon builds on Pocket TTS, developed by Kyutai, and uses the xn Rust tensor runtime. Gradium's Phonon checkpoints are the primary target. Compatible Pocket TTS checkpoints use the same explicit loading interface when they supply their own config, tokenizer JSON, weights, and voices.

License

The code is MIT OR Apache-2.0, at your option: MIT · Apache-2.0.

Model weights and voices are distributed separately and have their own licenses. Check the model license before redistribution.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this repository is dual licensed as above, without additional terms or conditions.

About

Phonon TTS inference using xn

Resources

Stars

17 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages