Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Generate speech

Use the system voice when you want text read aloud without downloading a model. Use Kokoro when your application needs audio samples for its own player or file writer. Start with the example that matches the output you need. Both examples use the synthesis dependencies.

System voice

Enable the system feature of aria-tts, as shown in setup. On macOS, this uses say. On Linux, install espeak-ng or espeak at its standard /usr/bin location.

Replace src/main.rs with:

use aria_tts::{prelude::*, system::SystemVoice};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let voice = SystemVoice::new()?;
    voice.speak(
        &SpeechText::new("Hello from Aria.")?,
        None,
        SpeakingRate::standard(),
        &CancelToken::never(),
    )?;
    Ok(())
}

Run cargo run --release. You should hear the sentence through the system voice. The call returns after playback finishes or fails. None selects the platform’s default voice; SpeakingRate::standard() speaks at 175 words per minute. CancelToken::never() lets this example run without a cancellation signal.

The system voice runs in a child process. It needs no playback feature and provides no raw audio samples (PCM), so it cannot generate an audio file.

Kokoro audio

Enable kokoro instead of system in the aria-tts dependency. Download the model and voices from Kokoro’s model-files release:

curl -fLO https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx
curl -fLO https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/voices-v1.0.bin

The voices file is a NumPy archive despite its .bin extension.

This example collects generated samples and prints their count. Replace src/main.rs with the following, using the absolute paths to your two files:

use aria_tts::{kokoro::Kokoro, prelude::*};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let engine = Kokoro::load(
        "/absolute/path/kokoro-v1.0.onnx",
        "/absolute/path/voices-v1.0.bin",
    )?;
    let speech = Synthesis::new(engine);
    let mut session = speech.start(&SpeechText::new("Hello from Aria.")?)?;
    let sample_rate = session.sample_rate();
    let mut samples = Vec::new();
    let mut buffer = [0.0; 1024];

    loop {
        let count = session.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        samples.extend_from_slice(&buffer[..count]);
    }

    println!("Generated {} samples at {sample_rate} Hz", samples.len());
    Ok(())
}

Run cargo run --release. This prints the sample count and sample rate; it does not play the audio. Kokoro supplies mono f32 PCM at 24 kHz and uses US English text processing. Its standard voices archive includes the default af_heart voice.

read() waits for samples, completion, or an error. A zero count means successful completion; an error means generation failed. Consume only buffer[..count]. To avoid storing the whole utterance, send each block to your player or file writer.

Dropping the session requests cancellation and waits for its thread to stop. The engine may take time to stop, so keep that cleanup off the UI thread.

Kokoro playback

Run cargo add aria-kit --features playback. It adds aria-kit, or enables the feature on an existing entry. Keep the Kokoro-loading and Synthesis::new lines from the previous example. Replace the sample-reading code, from let mut session through println!, with:

use aria_tts::{kokoro::Kokoro, prelude::*};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let engine = Kokoro::load("/absolute/path/kokoro-v1.0.onnx", "/absolute/path/voices-v1.0.bin")?;
let speech = Synthesis::new(engine);
speech.speak(&SpeechText::new("Hello from Aria.")?)?;
Ok(())
}

This plays through the default output device and returns when the utterance finishes. Linux playback also needs ALSA headers and pkg-config at build time.

Text and voices

SpeechText::new trims input and rejects empty text or text over 8 KiB. Voice::new validates a name’s form; whether it exists depends on the engine. SpeakingRate::new accepts a finite multiplier from 0.25 to 4.0.

For Kokoro, start_with lets you choose a voice and speaking rate and supply a cancellation token. Use names from your voices archive. Keep model loading separate from each utterance, as explained in Engines and sessions.