Lyra · User Guide
Lyra maps F10 / F11 / F12 to the monitor volume of a Universal Audio Apollo. This page covers all of it: setup, the menu, shortcuts, reference levels, pairing, widgets, troubleshooting. The full lyra:// URL scheme reference lives on a separate page.
That's the whole app. Everything below is detail.
Lyra intercepts F10 / F11 / F12 globally using a CGEventTap. This is the same mechanism macOS itself uses to handle media keys, and it requires Accessibility permission.
On first launch:
/Applications.Lyra polls the permission state in the background, so it will start the key handler the moment you grant access - no second relaunch required after the first.
If the system gets into a weird state (rare, but possible after reinstalls), clear the TCC entry:
tccutil reset Accessibility com.headroom.Lyra
Then relaunch Lyra to re-trigger the prompt.
Lyra only reads three keys (NX_KEYTYPE_MUTE, NX_KEYTYPE_SOUND_DOWN, NX_KEYTYPE_SOUND_UP) - the system-defined media-key events. It does not log, store, or forward anything. It also stops intercepting whenever your Apollo isn't reachable, so when the interface is unplugged your F-keys behave like normal volume keys again.
All shortcuts work globally and are intercepted before any other app sees them - but only when Mixer Engine is reachable. When it isn't, the F-keys fall through to whatever the system would otherwise do (usually nothing on a UA-only setup).
| Shortcut | Action |
|---|---|
| F12 | Volume up - one step |
| F11 | Volume down - one step |
| F10 | Mute / Unmute |
| ⇧F12 | Volume up - fine step (½) |
| ⇧F11 | Volume down - fine step (½) |
| ⇧F10 | DIM - toggle Apollo hardware DIM |
| ⌥F10 | Mono - toggle L+R sum to mono |
| ⌃F10 | Jump to Reference Level slot 1 |
| ⌃F11 | Jump to Reference Level slot 2 |
| ⌃F12 | Jump to Reference Level slot 3 |
| ⌃⌥F10 / F11 / F12 | Jump to ALT 1's slot 1 / 2 / 3 (switches to ALT 1) |
| ⌃⌥⇧F10 / F11 / F12 | Jump to ALT 2's slot 1 / 2 / 3 (switches to ALT 2) |
| ⌃⌥§ | Next speakers: Main, ALT 1, ALT 2 (the key left of 1; ⌃⌥` on US keyboards) |
| ⌃⌥1 / 2 / 3 | Main / ALT 1 / ALT 2 speakers |
The last four rows need ALT speakers turned on in UA Console. Without them, ⌃⌥ and ⌃⌥⇧ with F10 to F12 jump to the Main slots, and ⌃⌥ with § or a digit stays with whatever app you're in. Lyra claims those keys only while ALT is on and the Mixer Engine is connected.
Pass F-Keys to macOS in the menu lets the three keys reach the system output device again until you uncheck it. Lyra also steps aside automatically whenever UA Mixer Engine is not reachable.
Lyra uses a default step of 1/16 of full range (~6.25%). Shift halves it to ~3.125% for fine adjustments - the same pattern macOS uses for built-in volume keys.
Depending on your macOS keyboard settings, you may need to hold Fn to send F10/F11/F12 as F-keys (rather than the secondary brightness/expose actions printed on the keys). Change this in System Settings → Keyboard → Function Keys, or use Fn as a permanent modifier.
Ctrl+F-keys always do a Reference Level jump, even if Shift or Option are also held. This lets you hold Ctrl from a prior chord and the jump still works. With ALT speakers on, Option and Shift choose which speakers' slots.
Whenever the monitor level changes - from F-keys, the menu slider, the Apollo's hardware knob, UA Console, or a lyra:// URL - Lyra shows a small horizontal pill just below its menu bar icon.
Two styles (macOS 26 and later; Settings → General → HUD style):
Both styles tint the level bar amber while DIM is active and dim it while muted.
As of v1.6, the HUD has an in-app toggle in Settings → General → Show volume HUD overlay. Flip it off and the pill stops appearing immediately.
On v1.5 and earlier, set the showHUD UserDefault and restart Lyra:
defaults write com.headroom.Lyra showHUD -bool false
Set it back to true (or delete the key with defaults delete com.headroom.Lyra showHUD) to re-enable.
Lyra has three monitor presets, each stored as a tapered position (0.0-1.0) plus a user-renamable name. Defaults are Quiet (25%), Mix (50%), Loud (75%).
Three ways:
open lyra://reference/2 (slots are 1-indexed in URLs).Jumping is a one-shot - Lyra writes the stored tapered value straight to the Apollo's CRMonitorLevelTapered, the same parameter the hardware knob and Console's monitor section read. No ramping, no faders, no smoothing. The HUD pops up with the slot's name (or calibrated label) for ~2.5 seconds.
A checkmark appears on the jump item whenever the current live volume matches the slot's stored value (within ~0.5%). So if you turn the knob to exactly Mix, the menu shows Mix as checked.
Adjust the monitor to where you want it (knob, F-keys, slider - anything works), then Reference Levels → Save current as "<slot name>". The slot now stores that exact tapered position; the next Ctrl+F-key jump will land there.
Calibration data is cleared on overwrite. If the slot previously had a measured dB SPL value attached (from Audita - see below), manually saving over it clears the SPL value, because the prior measurement was tied to the old level and no longer applies. The menu and HUD revert to showing a percentage until you re-calibrate.
Reference Levels → Rename "<slot name>"… opens a small modal with a text field. Keep it short - names appear in the menu and the HUD pill. Common names: K-14, K-20, Mix, Quiet, Cinema, Late night, 79 dB.
lyra://reference/cycle advances to the next slot in order (1 → 2 → 3 → 1). Useful for a single Stream Deck button or a Shortcut that toggles between presets. With ALT speakers on, it cycles the slots of the speakers playing now.
Apollos with ALT monitor outputs can switch the monitor bus between your Main speakers and one or two alternate pairs: ALT 1 on the Twin family, ALT 1 and ALT 2 on the rack Apollos. Lyra reads how many your interface has, switches between them, and keeps a separate set of Reference Levels for each pair.
ALT outputs are off until you set them up in UA Console: Settings → Hardware → ALT Count. Lyra picks up the change while it runs. Until then the Speakers section of Lyra's menu reads ALT speakers off with the same hint.
lyra://alt/toggle, lyra://alt/set?speakers=1.Switching in UA Console, or with the Apollo's front-panel ALT button where it has one, shows up in Lyra too. Every switch pops the HUD with the device name and the pair, e.g. Apollo Twin X · ALT 1, and the menu bar icon carries a small 1 or 2 while an ALT pair is playing.
The monitor level, Mute, DIM and Mono follow whichever pair is playing, the same as the Apollo's own knob. Each ALT pair's trim (±30 dB) stays in UA Console.
Each pair has its own three slots:
| Keys | Slots |
|---|---|
| ⌃F10 / ⌃F11 / ⌃F12 | Main slots 1 / 2 / 3 |
| ⌃⌥F10 / ⌃⌥F11 / ⌃⌥F12 | ALT 1 slots 1 / 2 / 3 |
| ⌃⌥⇧F10 / ⌃⌥⇧F11 / ⌃⌥⇧F12 | ALT 2 slots 1 / 2 / 3 |
The HUD names an ALT slot with its pair, e.g. Quiet · ALT 1; Main slots show the slot name alone. Recalling another pair's slot switches to those speakers and sets the level in one step. When the new level is lower, Lyra lowers the level before switching; when it's higher, it switches first. No pair ever plays above its own starting or target level.
Save current as… and Rename… in the menu act on the pair playing now. Your existing slots become the Main slots. ALT slots start at Quiet / Mix / Loud.
Audita is the Headroom SPL meter for macOS. After running Audita's target-level calibration - speaker at known distance, pink noise at known level, measure with the meter - Audita knows what dB SPL your monitor system produces at any given monitor knob position.
Click "Send to Lyra…" in Audita to write that calibrated level into one of Lyra's three slots. Audita opens a sheet:
When you confirm, Audita fires lyra://reference/{n}/save?name=…&dBSPL=… and Lyra:
Mix - 85 dB SPL.From that point on, the slot displays as Mix - 85 dB SPL in:
Mix - 85 dB SPL ⌃F11)The dB SPL value is metadata - Lyra doesn't re-measure or verify it. It's the number you actually think in once your room is calibrated. If you change anything in the signal chain (different speaker, different distance, different room treatment), re-run Audita and re-send the slot.
On ALT speakers, a slot sent from Audita goes to the slots of the pair playing now, because that's the pair Audita measured. Calibrate each pair on its own.
Don't have Audita? The slot still works - it just shows a percentage instead of a measured dB SPL value. Audita is the calibration layer; Lyra is the recall layer.
lyra://) #Lyra registers a custom lyra:// URL scheme so any tool that can fire a URL can drive it - Stream Deck, Keyboard Maestro, Apple Shortcuts, BetterTouchTool, AppleScript, open from the shell, other apps (Audita).
Try it from Terminal:
open "lyra://reference/2"
open "lyra://volume/set?tapered=0.4"
open "lyra://mute/toggle"
Unknown URLs are logged to the console and silently ignored - they won't crash or interrupt anything.
| URL | What it does |
|---|---|
lyra://reference/1 | Jump to slot 1 |
lyra://reference/2 | Jump to slot 2 |
lyra://reference/3 | Jump to slot 3 |
lyra://reference/cycle | Advance to the next slot |
lyra://reference/{1|2|3}/save?name=Mix&dBSPL=85 | Write a slot. Lyra reads the live Apollo level for the tapered value. dBSPL optional. |
lyra://reference/{n}/save?name=Mix&dBSPL=85&tapered=0.5 | Same, but with an explicit tapered override. |
save is the URL Audita uses; you can use it from your own scripts too. If you omit name, the slot's existing name is kept. If you omit dBSPL, any existing calibration value on the slot is preserved (only an explicit value will replace it - URLs can't clear calibration).
ALT speakers. Without speakers, a jump or a save uses the slots of the pair playing now and never switches speakers. Add speakers=main, speakers=1 or speakers=2 to name the pair: lyra://reference/2?speakers=1 jumps to ALT 1's slot 2 and switches to ALT 1. A save with speakers writes that pair's slot without switching.
| URL | What it does |
|---|---|
lyra://alt/toggle | Next speakers: Main, ALT 1, ALT 2 (same as ⌃⌥§) |
lyra://alt/set?speakers=main | Main speakers. Also speakers=1 (ALT 1) and speakers=2 (ALT 2). |
Both reply with speakers and alt_available. If the interface has no ALT outputs, or the pair is off in UA Console, they fail with error_code=unsupported and a message saying where to turn it on.
| URL | What it does |
|---|---|
lyra://volume/set?tapered=0.5 | Set absolute level. tapered is 0.0-1.0 - same scale as CRMonitorLevelTapered. |
lyra://volume/up | Step up one full step (default 1/16). |
lyra://volume/up?fine=1 | Step up by half - Shift equivalent. |
lyra://volume/down | Step down one full step. |
lyra://volume/down?fine=1 | Step down by half. |
| URL | What it does |
|---|---|
lyra://mute/toggle | Toggle mute (same as F10) |
lyra://dim/toggle | Toggle DIM (same as Shift+F10) |
lyra://mono/toggle | Toggle Mono (same as Option+F10) |
All action URLs require Lyra to be running and your Apollo to be reachable (Mixer Engine connected). If the Mixer Engine isn't up, volume / toggle URLs are silently dropped - Lyra never queues or replays them. Pass x-error=… (see below) if you want a structured failure callback instead of a silent drop.
Three endpoints return live state via the x-success callback. They have no effect on their own - they only fire when the caller supplies an x-success URL.
| URL | Returns (appended to x-success) |
|---|---|
lyra://volume/get?x-success=… | tapered, db |
lyra://reference/current?x-success=… | slot (1-3), slot_name, slot_tapered, slot_dbspl if calibrated. Slot keys are absent when no slot matches the live volume. Also speakers (main, 1, 2) and alt_available; slots are those of the pair playing now. |
lyra://state?x-success=… | All of the above, plus muted, dim, mono, mixer_connected, device_connected, device_name, volume_step. |
db may be absent for a fraction of a second on first launch - Lyra waits for the first CRMonitorLevel push from the Apollo before it can answer. After that it stays in sync with the hardware knob.
Any endpoint - read or action - accepts two optional callback URLs so you can chain Lyra into a wider workflow (Shortcuts, Drafts, Stream Deck multi-actions, …):
| Param | Fires when |
|---|---|
x-success | The endpoint completed. Returned values are appended to this URL as query items. Action endpoints also append result=ok plus a small status object (e.g. muted=true). |
x-error | The endpoint failed. Lyra appends error_code and error_message. Common codes: mixer_disconnected, invalid_slot, invalid_argument, device_not_found, unknown_endpoint, unsupported (the interface lacks the feature, e.g. ALT speakers). |
Example - chain "set volume to 0.4 and then run a Raycast script":
lyra://volume/set?tapered=0.4&x-success=raycast://script/run?id=announce-mix
After Lyra finishes the set, it opens:
raycast://script/run?id=announce-mix&db=-12.34&result=ok&tapered=0.4000
(Lyra appends its return params to whatever was already in your x-success URL.)
Example - read the current state and feed it into a Shortcut:
lyra://state?x-success=shortcuts://run-shortcut?name=LogMonitor
The Shortcut receives the full state dictionary as URL query items - use Get value from URL for each key.
The full URL reference - every endpoint, every return field, worked examples for Shortcuts, Stream Deck, Keyboard Maestro and AppleScript - lives on the API reference page.
On macOS 13 (Ventura) and later, Lyra exposes an App Intents bundle: thirteen intents covering every action you can drive from the URL scheme, plus structured reads. They show up in the macOS Shortcuts app, in Spotlight (pre-wired App Shortcuts for the most-used ones), in Siri (via a named Shortcut), and in Focus Filters (e.g. switch to reference slot 2 when Mixing Focus engages).
On macOS 12 (Monterey), Lyra runs identically except this section is hidden. The Shortcuts integration requires macOS 13+ because App Intents itself does.
The full reference - all thirteen intents with parameters and return values, the App Shortcuts list, the Siri-via-named-Shortcut workflow, and the Focus Filter setup - lives in the Automation API reference.
Lyra ships four interactive widgets in the macOS widget gallery (v1.6+). Open Notification Centre (click the date/time, or swipe right with two fingers from the right edge of the trackpad), scroll to the bottom, click Edit Widgets, and search for Lyra.
Lyra's widgets on the desktop - the Control Panel (left), plus the Monitor Toggles and Volume widgets.
| Widget | Buttons | Sizes |
|---|---|---|
| Lyra - Control Panel | Volume, Mute / DIM / Mono (+ Speakers), Slots 1-3 (all in one) | Large |
| Lyra - Monitor Toggles | Mute, DIM, Mono (+ Speakers) | Medium |
| Lyra - Volume | Volume down, Volume up | Small or Medium |
| Lyra - Reference Levels | Slot 1, Slot 2, Slot 3 | Medium |
Every widget carries a small Lyra header - the menu-bar knob mark, the "Lyra" wordmark, and a live connection dot (green when the Mixer Engine is reachable, red when it isn't). The small Volume widget shows the dot alone to save space; the larger widgets add a "Connected" / "Offline" label.
Each tap fires the matching lyra:// URL, so the actual action runs in Lyra's main process. Lyra has to be running - it's a menu bar app, so just having it launched is enough, no window needed.
The widgets reflect live state: the Mute and Mono buttons fill with the accent colour when active, the Reference Levels widget highlights the slot you're currently on, and every button dims when Lyra isn't connected to the Mixer Engine. State updates a moment after each tap, once the Apollo echoes the change back to Lyra.
With ALT speakers on in UA Console, Monitor Toggles and Control Panel add a Speakers button that shows the pair playing now and steps to the next one. The slot buttons then recall the slots of the pair playing now.
Volume buttons step by Lyra's Volume step preference (set in Settings), the same as F11 / F12. Reference slot buttons honour your stored slot names and dB SPL calibrations exactly like the menu's Reference Levels submenu.
macOS 14+ required. The widgets use interactive buttons that aren't available on earlier macOS. On macOS 12 and 13, Lyra runs identically - the widget gallery entries are simply absent.
Lyra controls the interface through the background apps that come with UAD Console: UA Mixer Engine for Apollo interfaces and UA Mixer Helper for Volt interfaces. UAD Console's own window doesn't need to be open.
Lyra reads and changes the monitor section only: volume, mute, DIM, mono and the speaker set (ALT). Changes made elsewhere, such as the hardware knob or UAD Console, show up in Lyra's icon, menu and HUD within about 100 ms. Lyra doesn't change, patch or add files to UA software.
On Apollo models other than the Twin X, the monitor output sits elsewhere; Lyra finds it when it connects.
If the menu says the UA Mixer isn't running, click Start UA Mixer Engine. Lyra opens UA Mixer Engine without a window (UAD Console on older installs), and UA Mixer Helper when a Volt is connected. The menu then shows Connected with the interface's name.
If a background app stops (UAD Console quits, the Mac sleeps), Lyra retries the connection every 5 seconds and picks it up when the app returns. When an interface is unplugged, Lyra stops trying and waits; when it's back, the connection resumes. A Volt that is switched off and on is found again within a few seconds.
Two opt-in toggles in Settings tie the UA background apps to your interfaces:
Each automation has a paired Show a notification when this happens sub-toggle (on by default). The banner says what Lyra just did. macOS asks for notification permission the first time Lyra posts one.
Open with Cmd+, or Settings… in the menu. Three sections.
Settings persist across launches in the standard macOS preferences. Changing the volume step takes effect immediately - no relaunch needed.
Lyra is $9.99, one-time purchase, via Lemon Squeezy.
The first launch starts a 7-day free trial with full functionality - every feature, no nags, no watermarks. The trial start date persists across reinstalls. After 7 days Lyra shows a hard-lock window on launch and refuses to run until you activate a license.
The hard lock only fires at launch - if you're already running Lyra when the trial expires, nothing happens until your next restart.
As of v1.6, if your trial has ended and you're testing a build before committing to buy (a fix you reported, a feature against your gear), the hard-lock window offers a Test for 5 minutes button. Click it and Lyra runs normally for five minutes, then locks again. You get two sessions per day - the counter resets at local midnight. The limit is intentionally narrow: it's a verification tool, not a workaround.
Click Buy Lyra - $9.99 in the menu (or the Buy button on the website). Lemon Squeezy emails you the license key after checkout.
Menu → Enter License Key… opens the activation window. Paste your key and click Activate. Activation requires an internet connection. Once activated, Lyra works fully offline.
Each license can be active on up to two Macs. To free a slot, open Lyra on the machine you want to release, Menu → Manage License… → Deactivate, then activate on the new Mac.
Check the Lemon Squeezy confirmation email. If you can't find it, email hello@headroomstudio.dev with the address you used at checkout.
Lyra silently re-validates your license on each launch. If activation has been revoked (refund, deactivation, abuse), the local credentials are cleared and the app drops to trial / expired state. Network failures are silently ignored - the offline case is benefit-of-the-doubt.
Lyra ships with Sparkle (the standard macOS auto-update framework). The app checks headroomstudio.dev/lyra/appcast.xml every 24 hours; when a higher build number is found you'll see an update prompt at the next launch (or sooner if a check is in flight).
To check on demand: Menu → Check for Updates…
Updates are signed with EdDSA - Sparkle verifies the signature against the public key embedded in Lyra before installing. If the signature doesn't match the download is rejected.
Release notes: headroomstudio.dev/lyra/releases.html.
Menu → Launch at Login registers Lyra with SMAppService (macOS 13+). The checkmark always reflects the actual system state - if you flip the toggle in System Settings → General → Login Items, Lyra's menu follows.
On macOS 12 the menu item is hidden (SMAppService is 13+ only). Use the legacy Login Items pane in System Settings if you're on Monterey.
Quit and reopen System Settings. This is a known macOS bug - the new entry sometimes doesn't show until the prefpane is reloaded. If Lyra still doesn't appear, use the + button at the bottom to add it manually from /Applications/Lyra.app.
Lyra looks for any output device whose name contains "Universal Audio", "Apollo", or "UA ". Open Audio MIDI Setup and check that your Apollo appears in the device list. If it does but Lyra still doesn't see it, check the device name - older driver versions use slightly different strings. Lyra logs all detected devices to the system console on launch ([Lyra] === AUDIO DEVICES ===) - that's the fastest way to see exactly what names CoreAudio is reporting.
Click Start UA Mixer Engine in the menu. This launches the headless UA Mixer Engine.app if it's installed, falling back to UA Console. Either should make Lyra connect within a few seconds. If neither path works, opening UA Console manually always starts the daemon as a side-effect.
The default step is 1/16 of full range (~6.25%). Hold ⇧ with F11/F12 for half steps. As of v1.6 the step size is configurable in Settings → General → Volume step (range ~1.6% to 12.5%) - drag the slider to a step that suits your gain staging. Power users can still drive lyra://volume/set?tapered=… for any precision they want.
Make sure you haven't disabled it: defaults read com.headroom.Lyra showHUD should return 1 (or no value, which defaults to enabled). If you previously set it to false:
defaults delete com.headroom.Lyra showHUD
Then relaunch Lyra.
Reset Sparkle's "I already checked / I already skipped that version" state:
defaults delete com.headroom.Lyra
Relaunch, then Menu → Check for Updates… to force a fresh check. This also resets other preferences (HUD setting, saved target device, etc.) to factory defaults.
Wait 30 seconds and try again - Lemon Squeezy occasionally needs a moment to propagate. If it still fails, double-check that there's no leading/trailing whitespace in the key you pasted (the activation field trims, but it's worth a look). Otherwise email hello@headroomstudio.dev with the key and order number.
The trial start date persists across reinstalls, so reinstalling won't reset it. If you genuinely just installed Lyra for the first time and it's reading as expired, email hello@headroomstudio.dev.
Out of scope, in case any of these are dealbreakers:
lyra://volume/set?tapered=… - your launcher can hold any number of presets.lyra:// URLs from any tool of your choice.Email hello@headroomstudio.dev with what happened, what you expected, and ideally what's in the Console.app logs filtered by Lyra (Lyra prefixes every log line with [Lyra] or [AudioManager] so it's easy to grab the relevant slice).