Dictation
Marchyo can add voice dictation to the Hyprland desktop with voxtype (open
source, Whisper). Hold F9 to dictate (push-to-talk) or press
Super+Ctrl+X to toggle recording on and off; the transcribed text is typed at
the cursor.
It is off by default: it needs a microphone. When enabled, a recording
indicator joins the top bar, with desktop notifications, sound cues and a
Super+Shift+H status window.
marchyo dictation start|stop|toggle|status [--json] drives the backend; the
binds call it. The daemon’s evdev hotkey holds F9.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
marchyo.dictation.enable |
bool |
false |
Enable dictation (hold F9 push-to-talk + a Super+Ctrl+X toggle bind) |
marchyo.dictation.backend |
enum |
"voxtype" |
The dictation engine; "voxtype" is the only one |
marchyo.dictation.pushToTalk.enable |
bool |
true |
Hold-to-talk on F9: the daemon’s evdev hotkey (adds users to the input group) |
marchyo.dictation.pushToTalk.key |
str |
"F9" |
evdev key held to record (e.g. "SCROLLLOCK", "PAUSE", "F13") |
marchyo.dictation.pushToTalk.mode |
str |
"push_to_talk" |
"push_to_talk" (hold) or "toggle" (press to start/stop) |
marchyo.dictation.toggleKey |
str |
"SUPER + CTRL + X" |
Hyprland bind for marchyo dictation toggle; null to unbind |
marchyo.dictation.gpu |
bool |
true |
Use the Vulkan GPU build (voxtype-vulkan); false for the CPU-only build |
marchyo.dictation.model |
str |
"large-v3-turbo" |
Whisper model voxtype loads |
marchyo.dictation.language |
str |
"auto" |
Spoken language ("auto" detects per utterance; pin with an ISO code like "en") |
marchyo.dictation.preloadModel |
bool |
false |
Pre-download the model at activation instead of on first recording |
marchyo.dictation.onDemandModel |
bool |
false |
Load the model on record start and unload after transcription (frees VRAM) |
marchyo.dictation.gpuIsolation |
bool |
false |
GPU memory isolation so a discrete GPU can sleep between recordings |
marchyo.dictation.spokenPunctuation |
bool |
false |
Convert spoken punctuation words to symbols (say “period” → .) |
marchyo.dictation.replacements |
attrs |
{} |
Case-insensitive transcript substitutions (spoken form → typed text) |
marchyo.dictation.silenceGate.enable |
bool |
true |
Drop recordings with no detected speech before transcription (voxtype [vad]) |
marchyo.dictation.silenceGate.backend |
str |
"energy" |
"energy" (RMS, no model) or "whisper" (Silero model, needs voxtype setup vad) |
marchyo.dictation.silenceGate.threshold |
float |
0.5 |
Detection threshold 0.0-1.0; higher needs louder speech |
marchyo.dictation.silenceGate.minSpeechMs |
int |
100 |
Minimum detected speech (ms) for a recording to be transcribed |
marchyo.dictation.indicator |
bool |
true |
Show a recording-state segment on the top bar (voxtype status stream, or marchyo dictation status polled every 2 s) |
marchyo.dictation.notify |
bool |
true |
Desktop notifications on record start/stop and transcription |
marchyo.dictation.audioFeedback |
bool |
true |
Start/stop sound cues |
marchyo.dictation.statusWindow |
bool |
true |
voxtype only: bind Super+Shift+H to a floating status window |
marchyo.dictation = { enable = true; # model = "large-v3-turbo"; # multilingual + fast (default) # language = "auto"; # detect per utterance # preloadModel = true; # fetch the model at activation time # indicator = false; # drop the top-bar segment # notify = false; # silence desktop notifications # audioFeedback = false; # silence start/stop cues # statusWindow = false; # drop the Super+Shift+H window # onDemandModel = true; # unload the model between dictations (frees VRAM) # gpuIsolation = true; # let a discrete GPU sleep between recordings # spokenPunctuation = true; # say "period" to get "." # replacements = { "vox type" = "voxtype"; }; # fix domain jargon # silenceGate.threshold = 0.3; # keep quieter speech the gate drops};Silence gate
Section titled “Silence gate”Whisper invents text when it is fed silence (a stray “Thank you.” or “you”).
The silence gate runs voxtype’s voice activity detection on every recording and
discards one with no speech before it reaches Whisper: nothing is typed and the
cancel cue plays. It is on by default with the energy backend, which needs no
model download.
If quiet speech is being dropped, lower silenceGate.threshold (or
minSpeechMs); if background noise still produces text, raise it or switch to
backend = "whisper", the Silero model. That backend needs
ggml-silero-vad.bin in voxtype’s models directory, fetched with
voxtype setup vad. Without it the daemon logs a warning and transcribes every
recording ungated. Set silenceGate.enable = false to send every recording to
Whisper.
How it works (voxtype)
Section titled “How it works (voxtype)”With backend = "voxtype", enabling the option wires the upstream Home Manager services.voxtype module:
- Writes
~/.config/voxtype/config.tomland runs thevoxtypeuser service.wayland.displayis set so the daemon getsWAYLAND_DISPLAYpluswtype/wl-clipboardon its PATH for typing into Wayland windows. - Recording is driven two ways: the daemon’s evdev push-to-talk hotkey (hold
F9by default) and a Hyprland bind (marchyo.dictation.toggleKey, defaultSuper+Ctrl+X) that runsmarchyo dictation toggle. The evdev hotkey needs/dev/inputaccess, so dictation users are added to theinputgroup whilepushToTalk.enableis set (a real privilege — set itfalseto rely only on the compositor toggle). - Output mode is
type(types at the cursor) with clipboard fallback. - The top-bar indicator streams
voxtype status --follow(JSON) and recolors by state; notifications and sound cues use voxtype’s built-in[output.notification]/[audio.feedback];Super+Shift+Hopens a floating terminal runningvoxtype status --follow.
Check the daemon with systemctl --user status voxtype.