A fast, pure-Rust, CPU-only inference engine for Qwen3-ASR speech-to-text. It has no heavyweight runtime dependency—only libc—and is optimized for low-latency inference on Apple Silicon.
Supports the 0.6B and 1.7B models, offline and streaming transcription, live capture with VAD, subtitles, structured JSON, and forced alignment.
On an Apple M5 Pro, qwen-asr transcribes the 28.2-second benchmark clip in 613 ms—46× faster than realtime. In the same 10-run comparison, this CPU-only Rust implementation has the lowest median inference latency of all five implementations tested:
- 1.12× faster than
mlx-audioon the GPU - 2.31× faster than second-state MLX on the GPU
- 2.71× faster than the upstream pure-C implementation
- 2.77× faster than the first qwen-asr Rust port
| Implementation | Median inference | Realtime factor |
|---|---|---|
| qwen-asr (CPU, latest) | 613 ms | 46.00× |
| mlx-audio Python MLX (GPU) | 688 ms | 40.94× |
| second-state MLX (GPU) | 1,414 ms | 19.91× |
| pure C upstream (CPU) | 1,660 ms | 16.96× |
| qwen-asr first port (CPU) | 1,698 ms | 16.61× |
Apple M5 Pro, 15 cores, 48 GB RAM; same 0.6B model and 28.2 s audio; 10 standalone runs per implementation; median inference latency; each implementation uses its shipped default configuration. Results generated at
d141bca4inbench/compare-results/20260716T070644Z. See the methodology and full results.
# Install
cargo install qwen-asr-cli
# Download model
qwen-asr download qwen3-asr-0.6b
# Transcribe
qwen-asr -d qwen3-asr-0.6b -i audio.wavOr download a pre-built binary from GitHub Releases.
- Hand-tuned NEON, Accelerate, and AMX-aware kernels for Apple Silicon
- Quantized decode weights and batched decoding paths that reduce memory traffic
- Dynamic scheduling across performance and efficiency cores
- No tensor framework, Python runtime, GPU dispatch, or server process
See the optimization catalog for implementation details and the research log for measured experiments.
qwen-asr -d qwen3-asr-0.6b -i audio.wav # basic
qwen-asr -d qwen3-asr-0.6b -i audio.wav --silent # transcript only
cat audio.wav | qwen-asr -d qwen3-asr-0.6b --stdin # pipe from stdin
qwen-asr -d qwen3-asr-0.6b -i long.wav -S 30 # segmented
qwen-asr -d qwen3-asr-0.6b -i audio.wav --stream # streaming
qwen-asr -d qwen3-asr-0.6b -i audio.wav --srt # SRT subtitles
qwen-asr -d qwen3-asr-0.6b -i audio.wav --json out.json # structured JSON
qwen-asr -d qwen3-asr-0.6b -i audio.wav --aligner-dir qwen3-aligner-0.6b --srt out.srt --vtt out.vtt
qwen-asr -d qwen3-asr-0.6b --live --device "BlackHole 2ch" # live capture (macOS)
qwen-asr -d qwen3-asr-0.6b --live --vad --device "BlackHole 2ch" # VAD live
qwen-asr -d qwen3-aligner-0.6b -i audio.wav --align "Hello world" --align-language English # alignmentAll options
| Option | Description | Default |
|---|---|---|
-d <dir> |
Model directory (required) | — |
-i <file> |
Input WAV file | — |
--stdin |
Read audio from stdin (WAV or raw s16le 16kHz) | off |
--live |
Live capture from audio device (macOS) | off |
--device <name> |
Input device for live capture | system default |
--list-devices |
List audio input devices | — |
--vad |
VAD live mode | off |
-t <n> |
Thread count | performance cores |
-S <secs> |
Segment target seconds | 0 (full) |
--stream |
Streaming mode | off |
--stream-chunk-sec <s> |
Chunk size for streaming | 2.0 |
--language <lang> |
Force output language (en, zh, ja, ...) |
auto |
--srt [path] |
Write SRT subtitles | <input>.srt |
--vtt [path] |
Write WebVTT subtitles | <input>.vtt |
--json [path] |
Write structured JSON; stdout when path is omitted | off |
--aligner-dir <dir> |
ForcedAligner model for word timestamps and sentence-level subtitles | off |
--silent |
Transcript only, no status output | off |
--profile |
Print timing breakdown | off |
By default, qwen-asr prints plain text to stdout. Output flags are opt-in and can be combined; the audio is transcribed once and shared across requested outputs.
qwen-asr -d qwen3-asr-0.6b -i audio.wav --srt
qwen-asr -d qwen3-asr-0.6b -i audio.wav --vtt captions.vtt
qwen-asr -d qwen3-asr-0.6b -i audio.wav --json transcript.json
qwen-asr -d qwen3-asr-0.6b -i audio.wav --jsonSRT and VTT use segment-level timestamps unless an aligner model is supplied. For sentence-level subtitle cues and JSON word timestamps, pass a Qwen3-ForcedAligner model:
qwen-asr -d qwen3-asr-0.6b -i audio.wav \
--aligner-dir qwen3-aligner-0.6b \
--srt captions.srt --vtt captions.vtt --json transcript.jsonThe JSON output has this shape:
{
"transcription_info": {
"language": "en",
"duration": 123.456
},
"text": "Full transcript text",
"word_count": 42,
"segments": [
{
"start": 0.000,
"end": 8.750,
"text": "Segment transcript text",
"words": [
{ "word": "Shenyang,", "start": 1.120, "end": 1.440 }
],
"word_count": 3
}
],
"vtt": "WEBVTT\n\n1\n00:00:01.120 --> 00:00:08.750\nSegment transcript text\n\n"
}Always use release mode. Debug builds are 10–50× slower.
# macOS
RUSTFLAGS="-C target-cpu=native" cargo build --release
# Linux
sudo apt install libopenblas-dev # Debian/Ubuntu
RUSTFLAGS="-C target-cpu=native" cargo build --release
# Without BLAS
RUSTFLAGS="-C target-cpu=native" cargo build --release --no-default-features
# iOS (static library + C-FFI)
cargo build --release --target aarch64-apple-ios --features ios
# Android (shared library + JNI)
cargo ndk -t arm64-v8a build --release --features android| Feature | Description |
|---|---|
blas (default) |
BLAS linking (Accelerate on macOS, OpenBLAS on Linux) |
vdsp |
Accelerate vDSP/vForce for AMX (macOS) |
ios |
C-FFI API |
android |
JNI API |
# Speed benchmark
./bench/run.sh --label current --runs 10
# WER benchmark (100-file LibriSpeech offline)
python3 librispeech-wer-bench/librispeech_wer.py \
--dataset librispeech-wer-bench/dev-clean-2 \
--binary target/release/qwen-asr \
--model-dir qwen3-asr-0.6b \
--output-dir librispeech-wer-bench/results-100 \
--label current-offline-100 \
--limit 100 --mode offline
# Cross-implementation comparison (30–60 min)
./bench/benchmark-all.sh --runs 10See docs/benchmarks/ for full details.
- Benchmark methodology and results
- Optimization catalog
- Research and experiment history
- Automated release process
One-command install for OpenClaw users:
bash skills/qwen-asr/scripts/install.sh
bash skills/qwen-asr/scripts/transcribe.sh audio.wavRust port of antirez/qwen-asr, a pure C implementation of Qwen3-ASR inference by antirez.
Same license as antirez/qwen-asr.

