A 100% local speech-to-text app for macOS. Lives in the menu bar (no Dock icon) and transcribes your voice with OpenAI Whisper running entirely on your machine. No internet, no API keys, no data leaving your Mac.
Named after the lyrebird, the bird famous for mimicking any sound it hears.
- Menu bar app — a mic icon sits in the menu bar
- Tap the icon to start listening immediately — a floating "pill" appears, pinned on top of every app, with an animated waveform
- Global hotkey:
⇧⌘L(Cmd+Shift+L) starts/stops listening from anywhere, no matter which app is focused - Keep using your Mac while it records; the pill stays put until you finish it
- ✓ finishes (transcribe + auto-copy to clipboard); ✕ cancels
- Mixed English/Spanish: on auto-detect, the audio is split on pauses and each phrase is detected separately, so English stays English and Spanish stays Spanish (see "Bilingual speech" below)
- Right-click the icon for a menu: Language, History, Settings…, Transcribe file…, Quit
- Settings window: pick the Whisper model, language, microphone, and toggle auto-copy. Choices are saved and restored on the next launch.
- History: the last 5 transcriptions are kept; click one to re-copy it
- Transcribe a file (right-click → Transcribe file…): Opus/WhatsApp voice notes, MP3, WAV, M4A, MP4, OGG, FLAC, AMR, 3GP, and more
- Uses the Whisper
smallmodel by default (changeable in Settings)
- macOS 12+
- Python 3.9+
- ffmpeg (needed to decode uploaded MP3/M4A/MP4 files)
git clone https://github.com/painted-bird/lyrebird.git
cd lyrebird
# 1. ffmpeg (for file uploads)
brew install ffmpeg
# 2. Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3. Install dependencies (this installs PyTorch too; may take a few minutes)
pip install -r requirements.txtsource .venv/bin/activate
python app.pyA mic icon appears in the menu bar.
- Left-click the icon (or press
⇧⌘L) → the pill appears and recording starts right away. Speak, navigate around your Mac freely, then click ✓ to finish (the text lands on your clipboard) or ✕ to cancel. Left-clicking the icon again, or pressing⇧⌘Lagain, also finishes. - Right-click the icon → menu with Language, History, Settings…, Transcribe file…, and Quit.
The first run downloads the small model (~460 MB) into ~/.cache/whisper,
plus a tiny Silero VAD model. After that everything is offline.
To get a Lyrebird.app in ~/Applications so you can launch it from Spotlight:
./build_app.shThis builds an app bundle that points at your local checkout (re-run it if you
move the folder). Then search "Lyrebird" in Spotlight (⌘Space).
Whisper commits to a single language per recording, so a mixed clip normally collapses into one language (and may even translate the other parts). To handle code-switching, this app — when Language is set to Auto-detect — splits the audio on natural pauses and detects + transcribes each phrase on its own. A sentence in English comes out in English; the next one in Spanish comes out in Spanish.
Caveat: this works at pause boundaries. A switch in the middle of a sentence with no pause (e.g. "voy a comprar milk") still gets transcribed as that phrase's dominant language. Keep Language on Auto-detect for mixed speech; forcing a specific language disables the per-phrase splitting.
The first time you record, macOS asks for microphone access. Approve it, then record again. You can manage this later in System Settings → Privacy & Security → Microphone.
The global hotkey uses Carbon's RegisterEventHotKey, which needs no
Accessibility or Input Monitoring permission.
Right-click the menu bar icon → Settings… to configure:
- Model:
tiny,base,small(default),medium,large-v3. Changing it reloads in the background; a model you haven't used yet downloads on first selection. Bigger = more accurate but slower on CPU. - Language: Auto-detect (best for mixed English/Spanish) or a fixed language.
- Microphone: choose the input device, or leave on System default.
- Copy to clipboard automatically: on by default.
All settings and the last 5 transcriptions persist in
~/Library/Application Support/Lyrebird/config.json. Right-click →
History (last 5) to re-copy a recent transcription; Clear history wipes
it.
You can also set the starting model with the WHISPER_MODEL environment
variable (used until you change it in Settings):
WHISPER_MODEL=medium python app.pyapp.pyis a native AppKit/PyObjC app (no rumps, no Tkinter). It creates the menu barNSStatusItemand a borderless floatingNSPanel(the pill) in one Cocoa run loop. The pill is a non-activating panel pinned atNSStatusWindowlevel across all Spaces, so it floats over other apps and never steals focus. The waveform is a customNSViewdriven by the live mic level. The Whisper model loads once on a background thread; UI updates are marshaled back withAppHelper.callAfter.transcriber.pywraps Whisper model loading and transcription, including the Silero-VAD per-phrase splitting used for bilingual auto-detect.audio_recorder.pyrecords mic input at 16 kHz mono with sounddevice (and exposes a smoothed level for the waveform), saving a WAV copy with scipy.hotkey.pyregisters the global⇧⌘Lshortcut via Carbon.
Recording is transcribed directly from memory (no ffmpeg needed). Files are decoded by Whisper using ffmpeg, which is why ffmpeg is required for the Transcribe file… feature.
- No mic icon appears: run from a terminal and watch for errors. Make sure the virtualenv is active.
- File transcription fails / "ffmpeg not found":
brew install ffmpeg. - Microphone records silence: grant mic permission (see Permissions) and check the input device in System Settings → Sound.
- Mixed languages still collapse: make sure Language is on Auto-detect. Forcing a language disables per-phrase splitting.
MIT © 2026 Painted Bird.
The bundled Arimo font is licensed under the SIL Open Font License 1.1 — see fonts/LICENSE-Arimo.txt. Speech recognition by OpenAI Whisper (MIT) and Silero VAD (MIT).