Dictation
Marchyo can add push-to-talk voice dictation to the Hyprland desktop using
voxtype with OpenAI 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 (with a clipboard fallback).
It is off by default — it needs a microphone and downloads a Whisper model.
When enabled, the full desktop UI comes with it: a recording indicator on the top bar,
desktop notifications, start/stop sound cues, and a Super+Shift+H floating
status window. Each surface is on by default and individually opt-out.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
marchyo.dictation.enable |
bool |
false |
Enable voxtype dictation (hold F9 push-to-talk + a Super+Ctrl+X toggle bind) |
marchyo.dictation.pushToTalk.enable |
bool |
true |
Daemon evdev hold hotkey; adds dictation 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 voxtype record 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 (driven by voxtype status --follow) |
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 |
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
Section titled “How it works”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 runsvoxtype record 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.