Skip to content

Rebindable hotkey, explicit language, and two audio-path failures - #18

Open
vipergsm wants to merge 2 commits into
digimata:masterfrom
vipergsm:feat/hotkey-language-and-audio-fixes
Open

Rebindable hotkey, explicit language, and two audio-path failures#18
vipergsm wants to merge 2 commits into
digimata:masterfrom
vipergsm:feat/hotkey-language-and-audio-fixes

Conversation

@vipergsm

Copy link
Copy Markdown

Follow-up to #17, from getting parrot running on a Mac mini with a non-Apple keyboard. Independent of that branch — this one is cut from master and touches different files. Four separate issues, each of which blocked the next.

The tap crash is the one I would take first. installTap was handed input.outputFormat(forBus: 0) read before engine.start(). When that disagrees with the format the node actually runs at, AVAudioEngine raises an Objective-C exception Swift cannot catch and the process dies on the very first key press. format: nil avoids the guess; the converter is built lazily from the first buffer and cached per input format so the realtime callback stays allocation-free.

Microphone access was never requested. An unauthorized input node reports 0 ch / 0 Hz and engine.start() fails with a bare CoreAudio -10868, which points at nothing the user can act on. Now asked at startup, with a message naming System Settings.

--hotkeyfn is not reachable on every keyboard. A Logitech MX Keys S handles it in firmware, so maskSecondaryFn never reaches macOS: parrot starts, prints "listening", and does nothing forever. The named choices are side-specific, because CGEventFlags carries device-dependent low bits and contains(mask) requires all of them — 0x100010 matches right ⌘ only, leaving ⌘C/⌘V untouched. Since keyboards and remappers vary, a raw value copied out of --debug-hotkey is accepted too. The doctor's 🌐-key check is skipped when the hotkey is rebound off fn, and the menu bar names the real key.

--language — no DecodingOptions were passed, so Whisper auto-detected. Fine on long audio, poor on the ~2 s clips dictation produces: Serbian consistently came back as Spanish. Omitting the flag keeps today's behaviour.

Verified on an M-series Mac mini, macOS 26, whisper-large-v3-turbo: 2.19 s of audio → text in 1.20 s, diacritics correct.

Happy to split any of these out if you would rather review them separately — the audio commit stands alone.

vipergsm added 2 commits July 31, 2026 11:17
Two failures that both surface as something unrelated to their cause.

`installTap(format:)` was passed `input.outputFormat(forBus: 0)`, read
before `engine.start()`. That value can disagree with the format the node
ends up running at, and AVAudioEngine then raises an Objective-C exception
("Failed to create tap due to format mismatch") that Swift cannot catch —
the whole process dies on the first key press. `format: nil` means
"whatever the node is actually running at"; the converter is now built
lazily from the first buffer we really see, and cached per input format so
the realtime tap callback does not allocate per buffer.

Separately, nothing ever requested microphone access. An unauthorized
input node reports a 0 ch / 0 Hz format and `engine.start()` fails with a
bare CoreAudio -10868 ("format not supported"), which tells the user
nothing they can act on. `requestAccess()` asks up front and `start()`
guards on it.
--hotkey: fn is not reachable on every keyboard. Non-Apple keyboards
(tested on a Logitech MX Keys S) handle fn in firmware, so
maskSecondaryFn never reaches macOS and parrot appears to start fine and
then do nothing. The named choices are side-specific — CGEventFlags
carries device-dependent low bits, and since `flags.contains(mask)`
requires all bits of the mask, a value like 0x100010 matches right command
only and leaves ⌘C/⌘V alone. Keyboards and remappers vary enough that no
fixed list covers everyone, so a raw flags value copied out of
--debug-hotkey is also accepted. The doctor's 🌐-key check is skipped when
the hotkey has been rebound off fn, and the menu bar now names the actual
key instead of hardcoding "fn".

--language: no DecodingOptions were passed at all, so Whisper guessed the
language from the audio. That is reliable on long recordings and much less
so on the two-second clips dictation produces — Serbian came back decoded
as Spanish. Passing an ISO 639-1 code pins it; omitting the flag keeps the
previous auto-detect behaviour.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant