Real-time voice changer for macOS, built in Rust. Captures mic input, processes it through a DSP pipeline (Rubber Band pitch/formant shift + effect chain), and routes output to a virtual audio device so any app (Zoom, Discord, etc.) can use it as a mic. Controlled live from a ratatui TUI.
graph TD
MIC[Mic / CoreAudio]
CAP[cpal input stream]
RB[Ring buffer]
GATE[Noise gate]
SHIFT[Rubber Band pitch/formant shift]
FX[Effect chain: EQ / ring mod / clip / reverb]
OUT[cpal output stream]
BH[BlackHole]
MIC --> CAP --> RB --> GATE --> SHIFT --> FX --> OUT --> BH
BH --> Zoom
BH --> Discord
BH --> Other[any app]
Code layout: src/lib.rs is the core library (audio device handling, dsp pipeline, effects, engine, presets); src/main.rs + src/ui.rs are the CLI/TUI binary.
Built-in: Woman, Villain, Robot, Kid, Radio.
User presets are read from ~/.config/hatsumi/presets.toml (or --presets FILE); a preset with a built-in's name replaces it. Example:
[[presets]]
name = "Ghost"
description = "Low haunted whisper"
semitones = -9.0
formant_scale = 0.9
[[presets.effects]]
reverb = { mix = 0.4, decay = 0.85 }
[[presets.effects]]
low_pass = { freq_hz = 4000.0 }Available effects: low_shelf / high_shelf (freq_hz, gain_db), high_pass / low_pass (freq_hz), ring_mod (freq_hz, mix), soft_clip (drive), reverb (mix, decay).
See ROADMAP.md for what's next.
- macOS (CoreAudio)
- Rust toolchain
- BlackHole virtual audio driver (create an aggregate/virtual device named "Hatsumi", or pass
--output)
make setup # register git hooksmake run # default preset (Woman), TUI
cargo run -- robot # start on a preset
cargo run -- --list-devices # show input/output devices
cargo run -- ghost --presets my.toml # custom preset file
cargo run -- --input realme --output blackhole| Key | Action |
|---|---|
↑/↓ or j/k, Enter |
select / apply preset |
1–9 |
apply preset directly |
+/- |
pitch ±0.5 semitone |
[/] |
formant scale ±0.05 |
g, ,/. |
toggle noise gate, threshold ±3 dB |
r |
reset tuning to preset defaults |
q/Esc |
quit |
The status panel shows live pitch/formant values, over/underrun counters, and a continuously measured latency estimate; the level meters show input and processed output in dBFS.