qwen3_tts_rs

App Listed

A Rust implementation of the Qwen3 Text-to-Speech (TTS) model inference.

Checked · Sources

Downloads
204
Dependents
Not applicable
Stars
237
Forks
40
Contributors
2
Commits
115
Latest release

About

From the project README ·

Qwen3 TTS - Rust CLI tools

A Rust implementation of the Qwen3 Text-to-Speech (TTS) model inference. Provides three cross-platform CLI tools suitable for agentic skills for AI agents and bots.

  • tts — generate speech from text with named speaker voices
  • voice_clone — clone a voice from reference audio
  • api_server — OpenAI-compatible HTTP API server

Supports two backends: libtorch (via the tch crate, cross-platform with optional CUDA) and MLX (Apple Silicon native via Metal GPU).

Learn more:

Quick Start

Install binaries, models, and reference audio for your platform:

curl -sSf https://raw.githubusercontent.com/second-state/qwen3_tts_rs/main/install.sh | bash
cd qwen3_tts_rs

The installer detects your OS, CPU, and NVIDIA GPU (if present), then sets up everything in ./qwen3_tts_rs/.

Text-to-Speech

Generate speech with a named speaker using the CustomVoice model:

Read the full README
./tts models/Qwen3-TTS-12Hz-0.6B-CustomVoice "Hello world, this is a test." Vivian english
# Output: output.wav (24 kHz)
Voice Cloning

Clone a voice from reference audio using the Base model (ICL mode):

./voice_clone models/Qwen3-TTS-12Hz-0.6B-Base reference_audio/trump.wav \
  "Hello, this is a voice cloning test." english \
  "Angered and appalled millions of Americans across the political spectrum"
# Output: output_voice_clone.wav (24 kHz)
API Server

Start the OpenAI-compatible API server with the CustomVoice model:

./api_server models/Qwen3-TTS-12Hz-0.6B-CustomVoice --port 8080

Then call the endpoint:

curl -X POST http://localhost:8080/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"input": "Hello world!", "voice": "alloy"}' \
  -o output.wav

Reference

tts — Text-to-Speech
tts <model_path> [text] [speaker] [language] [instruction]
ArgumentDefaultDescription
model_path(required)Path to model directory
text"Hello! This is a test..."Text to synthesize (max ~4096 chars)
speakerVivianSpeaker name (see below)
languageenglishLanguage: english, chinese, japanese, korean
instruction(empty)Voice style instruction (1.7B models only)

Output: output.wav (24 kHz, 16-bit PCM)

Available speakers (CustomVoice models): Vivian, Serena, Ryan, Aiden, Uncle_fu, Ono_anna, Sohee, Eric, Dylan

Instruction examples (1.7B CustomVoice only):

  • "Speak in an urgent and excited voice"
  • "Speak happily and joyfully"
  • "Speak slowly and calmly"
  • "Speak in a whisper"
voice_clone — Voice Cloning
voice_clone <model_path> <ref_audio> [text] [language] [ref_text]
ArgumentDefaultDescription
model_path(required)Path to model directory
ref_audio(required)Path to reference WAV file
text"Hello! This is a test..."Text to synthesize
languageenglishLanguage
ref_text(none)Transcript of reference audio (enables ICL mode, higher quality)

Output: output_voice_clone.wav (24 kHz, 16-bit PCM)

Preparing reference audio: Must be mono 24 kHz 16-bit WAV. Convert with ffmpeg:

ffmpeg -i input.m4a -ac 1 -ar 24000 -sample_fmt s16 reference.wav

Example:

./voice_clone models/Qwen3-TTS-12Hz-0.6B-Base reference_audio/trump.wav \
  "Hello, this is a voice cloning test." english \
  "Angered and appalled millions of Americans across the political spectrum"
api_server — OpenAI-Compatible API
api_server <model_path> [--host 127.0.0.1] [--port 8080]
OptionDefaultDescription
model_path(required)Path to model directory
--host127.0.0.1Bind address
--port8080Listen port

Endpoints:

MethodPathDescription
POST/v1/audio/speechGenerate speech (OpenAI-compatible)
GET/v1/modelsList available models
GET/healthHealth check
API Request: POST /v1/audio/speech
{
  "input": "Text to synthesize",
  "voice": "alloy",
  "model": "qwen3-tts",
  "response_format": "wav",
  "speed": 1.0,
  "stream": false,
  "language": "english",
  "instructions": "Speak urgently",
  "audio_sample": "<base64-encoded WAV>",
  "audio_sample_text": "Transcript of the reference audio"
}
FieldTypeDefaultDescription
inputstring(required)Text to synthesize (max 4096 chars)
voicestring"alloy"OpenAI name or Qwen3 speaker name (see mapping below)
modelstring—Accepted for compatibility, ignored
response_formatstring"wav""wav", "pcm", "mp3", "flac", "ogg", or "opus"
speedfloat1.0Speed multiplier (0.25–4.0)
streamboolfalseEnable SSE streaming (requires "pcm")
languagestring"english"english, chinese, japanese, korean, auto
instructionsstring—Voice style instruction (1.7B models only)
audio_samplestring—Base64-encoded reference WAV for voice cloning
audio_sample_textstring—Transcript of reference audio (required with audio_sample)

Voice name mapping (OpenAI → Qwen3):

OpenAIQwen3
alloyserena
echoryan
fablevivian
onyxeric
novaono_anna
shimmersohee

You can also pass Qwen3 speaker names directly (e.g., "voice": "vivian").

Streaming: When stream: true and response_format: "pcm", the server returns Server-Sent Events with base64-encoded PCM chunks:

data: {"type":"speech.audio.delta","delta":"<base64 PCM>"}
data: {"type":"speech.audio.done"}

Voice cloning via API:

# Encode reference audio as base64
REF_B64=$(base64 < reference.wav)

curl -X POST http://localhost:8080/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d "{
    \"input\": \"Hello from a cloned voice.\",
    \"voice\": \"alloy\",
    \"audio_sample\": \"$REF_B64\",
    \"audio_sample_text\": \"Transcript of the reference audio\"
  }" -o cloned.wav

Build from Source

macOS (MLX backend)

Requires Apple Silicon Mac, Xcode, and CMake.

brew install cmake
git clone https://github.com/second-state/qwen3_tts_rs.git
cd qwen3_tts_rs
git submodule update --init --recursive
cargo build --release --no-default-features --features mlx
Linux (libtorch backend)

1. Download libtorch from libtorch-releases:

# Linux x86_64 (CPU)
curl -LO https://github.com/second-state/libtorch-releases/releases/download/v2.7.1/libtorch-cxx11-abi-x86_64-2.7.1.tar.gz
tar xzf libtorch-cxx11-abi-x86_64-2.7.1.tar.gz

# Linux x86_64 (CUDA 12.6)
curl -LO https://github.com/second-state/libtorch-releases/releases/download/v2.7.1/libtorch-cxx11-abi-x86_64-cuda12.6-2.7.1.tar.gz
tar xzf libtorch-cxx11-abi-x86_64-cuda12.6-2.7.1.tar.gz

# Linux ARM64 (CPU)
curl -LO https://github.com/second-state/libtorch-releases/releases/download/v2.7.1/libtorch-cxx11-abi-aarch64-2.7.1.tar.gz
tar xzf libtorch-cxx11-abi-aarch64-2.7.1.tar.gz

# Linux ARM64 (CUDA 12.6 / Jetson)
curl -LO https://github.com/second-state/libtorch-releases/releases/download/v2.7.1/libtorch-cxx11-abi-aarch64-cuda12.6-2.7.1.tar.gz
tar xzf libtorch-cxx11-abi-aarch64-cuda12.6-2.7.1.tar.gz

2. Set environment and build:

export LIBTORCH=$(pwd)/libtorch
export LIBTORCH_BYPASS_VERSION_CHECK=1

git clone https://github.com/second-state/qwen3_tts_rs.git
cd qwen3_tts_rs
cargo build --release

Alternatively, use pip-installed PyTorch instead of downloading libtorch:

pip install torch==2.7.1
export LIBTORCH_USE_PYTORCH=1
export LD_LIBRARY_PATH=$(python3 -c "import torch; print(torch.__path__[0])")/lib:$LD_LIBRARY_PATH
Download models and generate tokenizer

After building, download models and generate tokenizer.json for each:

pip install huggingface_hub transformers

huggingface-cli download Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice --local-dir models/Qwen3-TTS-12Hz-0.6B-CustomVoice

python3 -c "
from transformers import AutoTokenizer
for model in ['Qwen3-TTS-12Hz-0.6B-CustomVoice', 'Qwen3-TTS-12Hz-0.6B-Base', 'Qwen3-TTS-12Hz-1.7B-CustomVoice']:
    path = f'models/{model}'
    try:
        tok = AutoTokenizer.from_pretrained(path, trust_remote_code=True)
        tok.backend_tokenizer.save(f'{path}/tokenizer.json')
        print(f'Saved {path}/tokenizer.json')
    except Exception as e:
        print(f'Skipped {model}: {e}')
"

Binaries are in target/release/: tts, voice_clone, api_server.

Rust library usage

Add to your Cargo.toml:

[dependencies]
qwen3-tts-rs = "0.2"
# Or for MLX backend:
# qwen3-tts-rs = { version = "0.2", default-features = false, features = ["mlx"] }

See the API documentation on docs.rs for library usage examples.

Performance (Apple M4 Mac, MLX backend)

Test sentences: ~15–20 words in English ("The quick brown fox..." / "Scientists have discovered...") and Chinese. RTF = Real-Time Factor (wall time / audio duration). Lower is better; < 1.0 means faster than real-time.

0.6B CustomVoice
CLI (tts / voice_clone)
TestSpeakerLanguageAudioWall TimeRTF
Preset voiceVivianEnglish5.92s10.93s1.85x
Preset voiceRyanEnglish8.16s14.15s1.73x
Preset voiceVivianChinese6.64s11.26s1.70x
Voice clone (ICL)ref audioEnglish7.04s16.77s2.38x
API server (after warmup)
TestVoiceModeAudioWall TimeRTF
Non-streaming WAValloy (serena)full6.40s9.90s1.55x
Non-streaming WAVecho (ryan)full8.00s12.70s1.59x
Streaming PCMalloy (serena)stream~6.4s10.22s~1.60x
Voice clone WAValloy + reffull9.04s20.11s2.22x
1.7B CustomVoice
CLI (tts)
TestSpeakerLanguageAudioWall TimeRTF
Preset voiceVivianEnglish6.24s18.92s3.03x
Preset voiceRyanEnglish8.64s27.50s3.18x
Preset voiceVivianChinese6.24s18.31s2.93x
Preset + instructionVivianEnglish8.80s29.97s3.41x
API server (after warmup)
TestVoiceModeAudioWall TimeRTF
Non-streaming WAValloy (serena)full5.52s15.14s2.74x
Non-streaming WAVecho (ryan)full8.64s26.31s3.05x
Streaming PCMalloy (serena)stream8.16s19.79s2.43x
0.6B vs 1.7B comparison
Metric0.6B avg RTF1.7B avg RTFSlowdown
CLI preset voice1.76x3.05x~1.7x
API non-streaming1.57x2.90x~1.8x

Architecture

Text → Tokenizer → Dual-stream Embeddings → TalkerModel (28-layer Transformer)
                                                    ↓
                                              codec_head → Code 0
                                                    ↓
                                        CodePredictor (5-layer Transformer) → Codes 1-15
                                                    ↓
                                              Vocoder → 24kHz Waveform

License

Apache-2.0

Credits

Based on the original Python implementation by the Alibaba Qwen team.

License
None stated
Crate facts
Not measured
  • Runs on, Native code and Python bindings read crates on crates.io. This entry lists no crate.

Compare with similar projects

Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.

qwen3_tts_rs beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
qwen3_tts_rs This page App Listed

A Rust implementation of the Qwen3 Text-to-Speech (TTS) model inference.

204 binary downloads per release Not applicable 237 Not measured Not measured None stated
sherpa-onnx Featured

Safe Rust wrapper for sherpa-onnx speech recognition toolkit

Also in Run and serve models.

259,599 downloads over 30 days 28 15,834 2.0.1 GPU support unknown Binds native code: sherpa-onnx, sherpa-onnx-sys Apache-2.0
silero Listed

Production-oriented Rust wrapper for the Silero VAD ONNX model.

Also in Run and serve models.

1,888 downloads over 30 days 3 6 0.7.0 CUDA, ROCm Binds native code: ort-sys (feature coreml) Apache-2.0 OR MIT

Pure Rust implementation of Qwen3 ASR (Automatic Speech Recognition) with libtorch and MLX backends

Also in Speech and audio.

21 downloads over 30 days 0 254 0.2.0 CUDA Binds native code: torch-sys (feature tch-backend). Build uses a native toolchain: cmake Apache-2.0

Rust port of KittenTTS — ultra-lightweight ONNX-based text-to-speech

Also in Run and serve models.

3 downloads over 30 days 0 314 0.2.2 CUDA Binds native code: audiopus_sys, mp3lame-sys, ort-sys Apache-2.0

Rust implementation for the CohereLabs/cohere-transcribe-03-2026 speech-to-text model. Includes a CLI and an OpenAI-compatible API server.

Also in Speech and audio.

0 downloads over 30 days 0 101 0.1.1 CUDA Binds native code: torch-sys (feature tch-backend). Build uses a native toolchain: cmake Apache-2.0
voxr New

Audio and speech on boostr: compressed-audio decode, resampling, DSP and grapheme to phoneme, with speech synthesis (Kokoro, VITS), voice cloning (VoxCPM2), transcription with word timings (Whisper), voice activity (Silero) and audio-text scoring (CLAP), on CPU or CUDA.

Also in Speech and audio.

642 downloads over 30 days 2 2 0.9.1 CUDA No native code found Apache-2.0
Why ListedNo archive, New or Featured rule places it, so it is Listed.

What it lacks for Featured

  • The check holds no value for Homebrew installs on request over 365 days, Repology repository families, Docker pull growth over 90 days. A gate that lacks its signal does not pass.

What else the check found

  • The last activity is on 19 May 2026, 174 days ago. The rules expect an update within 365 days. Dormancy rule

Not measured: First release, Homebrew installs on request over 365 days, Repology repository families, Docker pull growth over 90 days.

Exact rules: Listed, Featured app. The check on applied thresholds version 9.

Every rule outcome, as the check records it
  • expected-interval: app: E = 365 days
  • dormancy: last activity 2026-05-19, 174 days ago, E = 365: active
  • featured: not featured: unknown homebrew_on_request_365d, repology_families, docker_pull_growth_90d
  • listed: listed: no archive, new or featured rule applies

Measurements and sources

Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.

Sources4 sources
Adoption204 binary downloads per release4 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependentsNot measuredYes
New dependents (365 days)Not measuredYes
Peak active dependentsNot measuredYes
Active dependents as a share of the peakNot measuredYes
Binary downloads per release204GitHub releasesYes
MaintenanceLatest human commit: 5 months ago7 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2026-05-19GitHub repositoryYes
Latest release2026-03-29GitHub releasesYes
First releaseNot measuredYes
Latest versionNot measuredYes
Days the oldest outside issue waits for a reply252GitHub repositoryYes
Maintainer replies over 365 days0GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repoNot measuredYes
Published docsNot measuredYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityNot measured
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windowNot measuredYes
RustSec unmaintained advisoryNot measuredYes
Deprecation noticeNot measuredYes
Deprecated requirementNot measuredYes
Distribution612 binary downloads over the last 3 releases10 not measured
Distribution measurements
SignalValueSourceFetchedCounts
ReleasesNot measuredYes
Downloads over 30 daysNot measuredYes
Binary downloads over the last 3 releases612GitHub releasesYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleaseNot measuredYes
Every version 0.0.xNot measuredYes
Every version yankedNot measuredYes
Crate deleted from crates.ioNot measuredYes
Repository237 stars, 40 forks, 2 contributors, 115 commits. Stars alone never qualify a project.1 not measured
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars237GitHub repositoryYes — one part of the repository route
GitHub forks40GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account2GitHub contributorsYes — one part of the repository route
Commits on the default branch115GitHub repositoryNo
Repository's main crate left out of the entryNot measuredYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseNone statedGitHub repositoryNo
Runs on, from listed crates and their direct dependenciesNot measuredNo
What shows each backendNot measuredNo
Native code, from listed crates and their dependenciesNot measuredNo
Python bindings, from direct dependencies of listed cratesNot measuredNo
Crates that depend on a listed crate directlyNot measuredNo

Corrections and review history

Report a correction

No correction applies to this entry.

Judgments

A judgment enters only through an approved issue and a merged pull request.

No judgment applies to this entry.