Local speech-to-text at GPU speed
wavo turns speech into text locally, on the GPU, in pure Rust. Give it a recording of any
length, a voice note or a two-hour meeting, and get the text with timestamps. It runs the open ASR
models that transcribe.cpp publishes with
practically the same output and comparable or better speed. Use it as a command-line tool with an
ollama-like model manager, or as a library that builds with a plain cargo build.
🌟 Features
- 📏 Audio of any length: long recordings are split at pauses and joined back, no chunking on your side
- 🎧 Any common format: wav, mp3, m4a, flac, ogg (Vorbis), resampled for you
- 🦀 Pure Rust library: no CMake, C++ toolchain, Python or ONNX Runtime to install
- ⚡ Runs on the GPU: Metal on Apple Silicon, Vulkan on Linux
- 🏎️ As fast as transcribe.cpp or faster on the same model files, and loads in 0.1–0.2 s
- 🎯 Same text, tokens and timestamps as transcribe.cpp on its test clips
- 📦
pull/list/rmmodels, shared with the Hugging Face cache thathfuses - 📝 Plain text, JSON with a start time for every token, or SRT subtitles
- 🌍 English, Russian, 25 European languages, and 100 with Whisper
🧠 Models
| Name | Size | Languages | Output |
|---|---|---|---|
parakeet-v3 (default) |
0.74 GB | 25 European languages | cased, punctuated |
parakeet-v2 |
0.73 GB | English | cased, punctuated |
gigaam-v3 |
0.27 GB | Russian | cased, punctuated |
gigaam-v3-e2e-ctc |
0.27 GB | Russian | cased, punctuated |
gigaam-v3-rnnt |
0.27 GB | Russian | lowercase, no punctuation |
gigaam-v3-ctc |
0.27 GB | Russian | lowercase, no punctuation |
whisper-turbo |
0.89 GB | 100 languages | cased, punctuated |
whisper-tiny |
0.05 GB | 99 languages | cased, punctuated |
whisper-base |
0.08 GB | 99 languages | cased, punctuated |
whisper-small |
0.27 GB | 99 languages | cased, punctuated |
whisper-medium |
0.83 GB | 99 languages | cased, punctuated |
whisper-large-v3 |
1.67 GB | 100 languages | cased, punctuated |
whisper-tiny.en |
0.05 GB | English | cased, punctuated |
whisper-base.en |
0.08 GB | English | cased, punctuated |
whisper-small.en |
0.27 GB | English | cased, punctuated |
whisper-medium.en |
0.83 GB | English | cased, punctuated |
whisper-large |
1.67 GB | 99 languages | cased, punctuated |
whisper-large-v2 |
1.67 GB | 99 languages | cased, punctuated |
breeze-asr-25 |
1.67 GB | Taiwanese Mandarin and English | cased, punctuated |
moonshine-tiny |
0.04 GB | English | cased, punctuated |
moonshine-base |
0.08 GB | English | cased, punctuated |
Parakeet is NVIDIA's Parakeet TDT 0.6B,
GigaAM is Sber's GigaAM v3, Whisper is OpenAI's
Whisper, Breeze-ASR-25 is MediaTek
Research's Whisper large-v2 fine-tune
and Moonshine is Useful Sensors' Moonshine,
small and fast. Moonshine has no timestamps: its tokens all start at 0, and --srt gives one cue
per piece of the split audio.
Short names stand for the published ones: parakeet-v3 is parakeet-tdt-0.6b-v3, parakeet-v2
is parakeet-tdt-0.6b-v2, gigaam-v3 is gigaam-v3-e2e-rnnt, whisper-turbo is
whisper-large-v3-turbo and breeze-asr-25 is Breeze-ASR-25; full names and a path to a
.gguf work too.
📥 Installation
Download the binary for macOS (Apple Silicon), Linux or Windows from the
latest release and put wavo (wavo.exe)
into a folder on your PATH, such as ~/.local/bin. Or build it with Rust, which takes a few
minutes:
wavo runs through Vulkan, so it needs a Vulkan driver and access to the GPU:
GPUs other than Apple's use simpler kernels for now: an Intel N100 transcribes 11 s of audio in 2.1–3.6 s.
Rust on Windows needs Microsoft's C++ build tools for its linker. In PowerShell:
winget install Rustlang.Rustup
winget install Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
wavo uses the GPU through its Vulkan driver (NVIDIA, AMD and Intel ship one); on a laptop with
two GPUs it takes the discrete one. GPUs other than Apple's use simpler kernels for now, apart
from matrix multiplication on NVIDIA's tensor cores: an RTX 4060 laptop transcribes 11 s of
audio in 42 ms (gigaam-v3), 79 ms (parakeet-v3) or 0.65 s (whisper-turbo).
Newest version
This readme follows main, which may be ahead of the latest release. Binaries of main are in the dev release, or build it with Rust:
🚀 Usage
When the model isn't downloaded yet, wavo run asks before downloading it, in a terminal; -y
downloads without asking, for scripts. Without a terminal and -y it fails with the wavo pull
command to run, and wavo bench never downloads. Long recordings are split at their quietest
moments and transcribed piece by piece, so an hour of audio works as well as a minute;
--segment SECS sets the piece length, --segment 0 runs one pass. Models are stored in the
Hugging Face cache (~/.cache/huggingface/hub), so a model fetched with hf download is found by
wavo and the other way round.
⚡ Speed
Apple M2, the same Q8_0 model file, wavo against transcribe.cpp on Metal, an 11 s clip:
| Model | Transcribe, ms | Load, ms | Memory, MiB |
|---|---|---|---|
gigaam-v3 |
96 / 100 | 44 / 104 | 302 / 325 |
parakeet-v2 |
143 / 199 | 81 / 245 | 740 / 820 |
parakeet-v3 |
154 / 215 | 89 / 245 | 763 / 884 |
whisper-turbo |
1240 / 1390 | 105 / 298 | 1018 / 1055 |
For dictation, where a model is loaded for each recording, the whole run (start, load, transcribe) is about a quarter to a third shorter. More numbers in docs/perf.md.
📚 Library usage
use ControlFlow;
use Hub;
let hub = new; // the Hugging Face cache, shared with `hf` and `wavo pull`
let path = match hub.find ;
let model = load?;
let transcript = model.transcribe?; // pcm: 16 kHz mono f32 in [-1, 1]
println!;
for token in &transcript.tokens
The hub feature downloads models by name (it adds an HTTP client); leave it out to load .gguf
files you fetch yourself, with a pure Rust build. Decoding and resampling audio and splitting long
recordings are up to you: model.max_audio_ms() tells how long a piece the model was trained on
(25 s for GigaAM, 30 s for Whisper and Moonshine). The API docs have the details,
including downloading on a thread with progress and cancel, as
examples/hub.rs does.
🤝 Contributing
wavo is written by AI coding agents. A person set the direction; the agents wrote the code and the GPU kernels, matched the reference output and searched for the fastest solutions themselves. Pull requests are welcome, and so are your agents: point them at agents.md and let them make it better.
In an administrator PowerShell: OpenSSH server, Git (its bash becomes the SSH shell), CMake and
make, and the Rust toolchain with Microsoft's build tools, as in Installation → Windows. sshd
reads an administrator's key from C:\ProgramData\ssh, not from ~\.ssh.
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd; Set-Service sshd -StartupType Automatic
winget install Git.Git Kitware.CMake ezwinports.make
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Program Files\Git\bin\bash.exe" -PropertyType String -Force
Add-Content C:\ProgramData\ssh\administrators_authorized_keys "ssh-ed25519 AAAA... you@host"
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
ssh user@host then opens Git Bash, where make check and make test work as on macOS (rustup
fetches the nightly toolchain for cargo +nightly fmt on first use), and make reference builds
transcribe.cpp for the CPU with Visual Studio's compiler; for its GPU build run winget install KhronosGroup.VulkanSDK (in PowerShell) and add -DTRANSCRIBE_VULKAN=ON to the cmake configure
step. ssh user@host wsl opens the default WSL distribution instead, a separate Linux with its own
toolchain.
For a headless machine, Remote Desktop (built into Windows Pro) works without a monitor. Allow it
and SSH only from the local network (here 192.168.8.0/23; LocalSubnet would leave out a client
in the neighbouring subnet). A Windows update can switch the network to Public, which blocks the
default SSH rule, so allow both rules on every profile:
Set-NetFirewallRule -DisplayGroup 'Remote Desktop' -Profile Any -RemoteAddress 192.168.8.0/23
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -Profile Any -RemoteAddress 192.168.8.0/23
Enable-NetFirewallRule -DisplayGroup 'Remote Desktop'
Set-ItemProperty 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -Value 0
Set-NetConnectionProfile -InterfaceAlias '<adapter>' -NetworkCategory Private
On a Mac, connect with Windows App (App Store), signing in with the account's password, not its
PIN. It needs Local Network access in System Settings, and an outbound firewall such as LuLu must
allow it to reach the machine on TCP 3389. Error 0x4 is a generic connection failure: when
nc -z <host> 3389 works from the Terminal, the block is on the Mac.
📝 License
Distributed under the MIT License.
🔍 See also
- handy-computer/transcribe.cpp – The reference wavo follows: C++ on ggml, many model families.
- ggml-org/whisper.cpp – Whisper in C++ on ggml.
- k2-fsa/sherpa-onnx – Many models on ONNX Runtime, streaming included.
- senstella/parakeet-mlx – Parakeet in Python on MLX, Apple Silicon only.