Wiki
Everything worth knowing, in the order you will want it.
GETTING STARTED
Download a build for your platform, or compile it — a fresh clone needs no secrets and no configuration.
- Get the archive from the releases page.
- Verify it. This takes ten seconds and is the difference between running the software and running whatever arrived.
- Unpack it. There are two programs:
veilvoice(command line) andveilvoice-gui(desktop app).
Nothing installs a service, writes to a registry, or phones home. Delete the folder and it is gone.
THE DESKTOP APP
veilvoice-gui is the whole tool in a window. Five tabs, no menus, no settings file to find.
anonymise file
Choose a recording and press anonymise. Everything on this tab is a choice you can see:
| Control | What it does |
|---|---|
| intensity | How far pitch and formants are pushed from the original, 0.0–1.0. Default 1.0, which is full normalisation. |
| neutralise accent and intonation | On by default. Maps every speaker onto one canonical register and vocal tract. Turning it off is weaker de-identification — do it only if you know why. |
| seed roll (s) | How often the modulation stream ratchets forward. Default 2 s; 0 keeps one stream for the whole session. Inaudible by construction. |
| strip metadata from the result | On by default. Removes tags from the written file. |
| encrypt the result at rest | On by default — see below. |
At-rest encryption
The result is sealed as it is written, so a file you name clean.wav lands as clean.wav.veil. Two ways to seal it:
- passphrase — Argon2id at 256 MiB. Set it once and it is held for the session; the change button clears it. Locking the app clears it too.
- public key — X25519 + ML-KEM-768 hybrid, to a
.pubfile fromveilvoice keygen. No passphrase to type and nothing to forget; only the matching private key opens it.
The anonymise button stays disabled until there is something to encrypt with. That is deliberate: a tool that quietly wrote plaintext because you had not filled a field in yet would make the default worthless.
Unticking the box opens a dialogue that has to be answered before anything changes. The result is still a recording of every word that was said, and on flash storage deleting it afterwards is not a reliable fix — so the question is asked once, plainly, rather than hidden behind a preference.
live scramble
Pick an input and an output device and press start. A virtual audio cable is preselected as the output when one is installed, because routing there is what lets other applications hear the veiled voice at all; if none is found the page warns you rather than silently sending it to your speakers. Level meters, processing time per block, engine latency and a glitch counter are shown live.
monitor
Which applications are holding your microphone and camera, with a running log of starts and stops. The indicator rides the header on every tab, because a warning you have to go looking for is not doing its job.
On a platform that cannot see this — macOS exposes no public interface — the tab says so explicitly. An empty list from a blind monitor is a false reassurance, and is never presented as good news.
lock
Set, change or remove the app lock, and lock the app immediately. See the app lock below for what it is worth. The header also carries a lock button, which locks and clears the session passphrase in one action.
about
Version of every crate, the licence, the typeface actually in use, and two short paragraphs stating what VeilVoice protects and what it does not. The limits are in the app, not only in the documentation.
COMMAND LINE
veilvoice anonymise recording.mp3 -o clean.wav # writes clean.wav.veil, sealed
veilvoice live --output "CABLE Input (VB-Audio Virtual Cable)"
veilvoice devices
veilvoice clean photo.jpg
veilvoice encrypt secret.wav
veilvoice decrypt secret.wav.veil -o secret.wav
veilvoice keygen
veilvoice lock set
veilvoice info
Every command takes --help. Useful flags on anonymise and live:
| Flag | Effect |
|---|---|
--intensity 0.0–1.0 | How far pitch and formants move from the original. Default 1.0. |
--keep-accent | Leaves intonation, accent and vocal tract intact. Weaker de-identification; use only if you know why. |
--clean-metadata false | Keeps the tags on the written file. On by default. |
--encrypt false | Writes the recording in the clear. On by default; turning it off prints what you are giving up and waits for you to type UNENCRYPTED. |
--encrypt-to key.pub | Seals to a recipient's hybrid public key instead of a passphrase. |
Where did my WAV go? anonymise seals its result, so -o clean.wav produces clean.wav.veil. Open it with veilvoice decrypt clean.wav.veil -o clean.wav. The words survive de-identification on purpose, so an unencrypted result is still a recording of everything that was said — which is why this is the default rather than an option you have to find.
LIVE SCRAMBLING
Live mode reads a microphone, de-identifies in real time, and writes to an output device. Latency is about 21 ms of algorithmic delay plus your hardware buffers, and processing costs roughly 1 % of one core.
veilvoice devices # see what is available
veilvoice live # picks a virtual cable automatically if one exists
Point another application at the same cable as its microphone and it receives the veiled voice.
If you select your speakers as the output instead of a cable, you will hear yourself and so will nobody else. That is useful for testing and useless for a call.
VIRTUAL AUDIO CABLES
A virtual cable is a loopback device: what one program plays into it, another can record from. VeilVoice does not bundle one — they are separate projects with their own licences.
| Platform | Usual choice | Licence |
|---|---|---|
| Windows | VB-CABLE, from vb-audio.com | Proprietary donationware |
| macOS | BlackHole | GPL-3.0 |
| Linux | PipeWire or a PulseAudio null sink — already installed | Free software |
On Linux nothing extra is needed:
pactl load-module module-null-sink sink_name=veilvoice
VeilVoice detects a cable by name and offers it first. If the installer ever offers to fetch VB-CABLE for you, it is an opt-in tick box that you must actively agree to, because it is proprietary software from a third party.
RECORDING — USE AUDACITY
VeilVoice deliberately does not include a recording studio. Audacity already is one, it is free software, it is mature, and it is audited by far more people than this project will ever be. Writing a worse one would help nobody.
The workflow:
- Record and edit in Audacity. Export as WAV.
- Run it through VeilVoice:
veilvoice anonymise take.wav -o safe.wav. - Or record through VeilVoice live, by setting a virtual cable as Audacity's input.
The installer may offer to fetch the current Audacity for your platform. Like the cable, it is an opt-in tick box — VeilVoice will not install third-party software you did not ask for.
A licensing note for contributors. Audacity is GPL-2.0-or-later, which is not compatible with this project's GPL-3.0-or-later in the direction of copying code in. Recommend it, integrate with it, do not lift source from it.
PRIVATE TRANSCRIPTION
Speech-to-text needs the words. It does not need your voiceprint — but every cloud transcription service receives one anyway, and a voiceprint is as durable an identifier as a fingerprint.
Anonymise first, then upload:
veilvoice anonymise dictation.wav -o safe-to-upload.wav
The service gets speech it can transcribe and a voice belonging to nobody.
Two caveats. Accuracy drops somewhat, because recognisers are trained on natural speech and the output is synthetic. And the words still go to the provider — this protects your identity, not the content. If the content is sensitive, transcribe locally instead; whisper.cpp reads the WAV VeilVoice writes with no extra work.
ENCRYPTION
De-identification and secrecy are different problems. VeilVoice hides who spoke; encryption hides what was said.
veilvoice encrypt notes.wav # password, Argon2id
veilvoice keygen # hybrid post-quantum key pair
veilvoice encrypt notes.wav --to recipient.pub
veilvoice decrypt notes.wav.veil -o notes.wav --key veilvoice.key
Private keys generated by keygen are themselves stored encrypted, under a passphrase, in the same container format — a stolen key file is worth nothing without it.
Since anonymise now seals its own output, encrypt is for everything else: a file you already have, a note, a key you want to move.
THE APP LOCK
VeilVoice can sit behind a password of its own, so that someone who picks up your unlocked computer cannot open it, see which files you have processed, or start a live scramble.
veilvoice lock set # choose a password
veilvoice lock status # is one set, and is it rate limited right now?
veilvoice lock change
veilvoice lock remove
The desktop app has the same controls under its lock tab, and a lock button in the header that locks it immediately and clears the session passphrase with it.
Use a different password from the one you use for recordings. They are separate on purpose: opening the app should not be the same act as unsealing everything it has written. VeilVoice domain-separates the two derivations, so even typing the same string in both places does not produce two copies of one value — but it does mean one guess opens both, so do not.
This is not tamper-proof, and cannot be. A local application has nowhere to hide a secret from the machine it runs on. Anyone who can write to your files can delete the lock file; anyone holding the disk can edit the attempt counter, move the clock to defeat the wait, or attack the stored password hash offline.
What it does buy is real: it stops casual access. Three attempts are free, then the wait doubles — 5 s, 10 s, 20 s, up to fifteen minutes — and the count is written to disk, so killing the app does not reset it. Argon2id at 256 MiB makes each offline guess expensive, which helps a good passphrase and does not save a bad one.
If the threat is someone with your disk, the answers are full-volume encryption (LUKS, BitLocker, FileVault) and the at-rest encryption above. Not this.
SELF-DESTRUCT
For recordings that must not survive: a secure-erase that overwrites the file's contents before unlinking it, rather than just removing the directory entry.
This is irreversible and there is no undo. It is opt-in and gated behind an explicit confirmation for that reason.
Be aware of the honest limit: on an SSD, wear levelling means the drive may keep a copy of the old blocks where no software can reach them. Overwriting is effective on spinning disks and is best-effort everywhere else. Full-disk encryption is the real answer — if the volume is encrypted, destroying the key destroys everything on it at once.
VERIFYING A DOWNLOAD
Two independent checks ship with every release.
1. The hash — is this the file that was published?
sha256sum -c SHA256SUMS --ignore-missing
Or use the in-browser verifier, which hashes locally and uploads nothing.
2. The signature — was that list published by the maintainer?
gpg --import veilvoice-signing-key.asc
gpg --verify SHA256SUMS.asc SHA256SUMS
Check the fingerprint is exactly:
“Good signature” from an unexpected key means nothing. The fingerprint is the part that matters.
3. The strongest check — rebuild it yourself
Release binaries are reproducible: build the tagged commit and you get byte-identical output.
git checkout v0.1.1
export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
cargo build --release --locked
sha256sum target/release/veilvoice
HOW IT WORKS
Three mechanisms, each individually lossy. Undoing the output means defeating all three.
Phase is discarded, every frame
Each analysis frame keeps only its magnitude spectrum; the measured phase — which encodes the exact waveform and the speaker's micro-timing — is thrown away and a synthetic one generated. This is deletion, not obfuscation: infinitely many waveforms share any magnitude spectrogram.
Every speaker is collapsed onto one identity
Pitch register, vocal-tract length and long-term spectral tilt are each mapped to a single canonical value. These mappings are many-to-one: a whole population lands on the same output, so there is nothing to invert.
Every correction is drawn from a multi-second average, never the current frame — per-frame spectral shape is what distinguishes /i/ from /u/, and normalising that would erase the vowels along with the accent. The test suite asserts vowel contrast survives.
The remainder is CSPRNG-modulated
The residual transform changes every frame from a ChaCha20 stream whose seed comes from the OS CSPRNG, lives only in page-locked memory, and is zeroized on drop. There is no fixed transform to undo.
Full argument, including the threat model: the whitepaper.
WHAT IT WILL NOT DO
Read this part twice. Misunderstanding it is the only way this software gets someone hurt.
- It does not hide what you said. The words are preserved on purpose and can be transcribed.
- It does not fully remove a strong accent. The melody goes; which phonemes you produced cannot be changed by any filter.
- It does not sanitise the background — room acoustics, other voices, a passing siren.
- It does not hide your speaking rate or rhythm. A weak biometric, but a real one.
- It does not help against an attacker already running code on your machine.
- It does not clean the filename, the filesystem timestamps, or the channel you send it over.
- The app lock is not tamper-proof. It stops someone who sits down at your unlocked session. It does not stop someone holding the disk, who can delete the lock file or attack the stored hash offline.
BUILDING FROM SOURCE
git clone https://github.com/tilas01/veilvoice && cd veilvoice
cargo build --release
The toolchain is pinned by rust-toolchain.toml and rustup installs it automatically. On Debian or Ubuntu you will need the audio and windowing headers first:
sudo apt install libasound2-dev libudev-dev pkg-config \
libgtk-3-dev libxkbcommon-dev libwayland-dev
USING IT AS A LIBRARY
[dependencies]
veilvoice-core = { git = "https://github.com/tilas01/veilvoice" }
veilvoice-audio = { git = "https://github.com/tilas01/veilvoice" }
The engine allocates nothing in process() and is safe to call from inside an audio callback:
use veilvoice_core::{DeidConfig, Deidentifier};
let mut deid = Deidentifier::new(DeidConfig::default())?;
let mut out = vec![0.0; block.len()];
deid.process(&block, &mut out);
FAQ
Will it make me sound like a different specific person?
No, and that is deliberate. It maps you onto a canonical, deliberately synthetic voice that belongs to nobody. Impersonating a real person is a different tool with different ethics.
Why does it sound robotic?
Because pitch is held constant by design — that steadiness is the sound of your pitch information being gone. Some of the metallic quality is the harmonic-comb resynthesis, and the whitepaper explains what would improve it.
Can I get my original voice back?
No. That is the point. Keep your own copy of the original if you need one; nothing in the output can reconstruct it.
Does it work offline?
Only offline. There is no network code, and continuous integration fails the build if an HTTP client so much as enters the dependency graph.
Is it safe for a real source-protection situation?
The de-identification is strong and the reasoning is published so you can check it. But no external firm has audited this code, and the limits above are real. For a situation where being identified would cause serious harm, treat it as one layer among several, not the whole plan.
Why GPL and not something more permissive?
So that a version you are handed can always be inspected. Anyone may build a business on it; nobody may close it and hand users something they can no longer read.