1. Quick start #

  1. Connect your Apollo and make sure UA Console (or just UA Mixer Engine) is installed.
  2. Launch Lyra. Grant Accessibility permission when prompted - Lyra needs it to intercept F10 / F11 / F12 globally.
  3. Once the menu shows "Connected: <your Apollo>", press F12 / F11 / F10 to raise / lower / mute monitor volume.
  4. Add modifiers for more: for fine steps, ⇧F10 for DIM, ⌥F10 for Mono, ⌃F10/⌃F11/⌃F12 to jump to a saved Reference Level.

That's the whole app. Everything below is detail.


2. First launch & Accessibility permission #

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:

  1. Lyra shows the macOS system Accessibility dialog. Click Open System Settings.
  2. In System Settings → Privacy & Security → Accessibility, find Lyra in the list and toggle it on.
  3. If Lyra isn't in the list yet, click + at the bottom and add it from /Applications.
  4. Relaunch Lyra after enabling the toggle.

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.

Resetting Accessibility for testing

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.

What about all my keystrokes?

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.




5. Keyboard shortcuts #

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).

ShortcutAction
F12Volume up - one step
F11Volume down - one step
F10Mute / Unmute
⇧F12Volume up - fine step (½)
⇧F11Volume down - fine step (½)
⇧F10DIM - toggle Apollo hardware DIM
⌥F10Mono - toggle L+R sum to mono
⌃F10Jump to Reference Level slot 1
⌃F11Jump to Reference Level slot 2
⌃F12Jump to Reference Level slot 3

About the step size

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.

About the Fn key

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 wins

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.


6. Volume HUD #

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 modes:

The normal Volume HUD pill showing speaker icon, level bar, and percentage The labeled Volume HUD pill expanded to show the active Reference Level name and calibrated dB SPL value

On macOS 26+ the pill uses Liquid Glass - the system's translucent material - and inherits the colour of whatever is behind the menu bar.

Disabling the HUD

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 - no relaunch needed.

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.


7. Reference Levels #

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%).

Lyra's Reference Levels submenu with three named slots plus Save and Rename actions

Jumping to a slot

Three ways:

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.

Saving the current position to a slot

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.

Renaming a slot

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.

Cycling

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.


8. Audita pairing - calibrated dB SPL slots #

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:

  1. Slot picker - 1, 2, or 3 (Ctrl+F10 / F11 / F12 respectively).
  2. Name - defaults from Audita's K-System target (e.g. K-14 = 79 dBA → "K-14"). Edit freely.
  3. SPL readout - read-only, the value about to be stored.

When you confirm, Audita fires lyra://reference/{n}/save?name=…&dBSPL=… and Lyra:

  1. Reads the live Apollo monitor level (so the slot reflects exactly what Audita just measured against).
  2. Stores tapered + name + dBSPL together.
  3. Pops the labeled HUD as confirmation - Mix - 85 dB SPL.

From that point on, the slot displays as Mix - 85 dB SPL in:

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.

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.


9. URL scheme (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.

Reference Levels

URLWhat it does
lyra://reference/1Jump to slot 1
lyra://reference/2Jump to slot 2
lyra://reference/3Jump to slot 3
lyra://reference/cycleAdvance to the next slot
lyra://reference/{1|2|3}/save?name=Mix&dBSPL=85Write a slot. Lyra reads the live Apollo level for the tapered value. dBSPL optional.
lyra://reference/{n}/save?name=Mix&dBSPL=85&tapered=0.5Same, 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).

Volume

URLWhat it does
lyra://volume/set?tapered=0.5Set absolute level. tapered is 0.0-1.0 - same scale as CRMonitorLevelTapered.
lyra://volume/upStep up one full step (default 1/16).
lyra://volume/up?fine=1Step up by half - Shift equivalent.
lyra://volume/downStep down one full step.
lyra://volume/down?fine=1Step down by half.

Toggles

URLWhat it does
lyra://mute/toggleToggle mute (same as F10)
lyra://dim/toggleToggle DIM (same as Shift+F10)
lyra://mono/toggleToggle 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.

Reads (v1.5)

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.

URLReturns (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.
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.

x-callback-url (v1.5)

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, …):

ParamFires when
x-successThe 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-errorThe endpoint failed. Lyra appends error_code and error_message. Common codes: mixer_disconnected, invalid_slot, invalid_argument, device_not_found, unknown_endpoint.

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.


10. Shortcuts, Siri & Focus Filters (App Intents) #

On macOS 13 (Ventura) and later, Lyra exposes an App Intents bundle: eleven 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 Shortcuts app: a built 'Mix Setup' Shortcut chaining several Lyra intents on the left, and the full Lyra action library searched on the right

The full reference - all eleven 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.


11. Widgets #

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 macOS desktop - the large Control Panel (volume, Mute/DIM/Mono, reference slots 1-3), the Monitor Toggles widget, and the Volume widget, each under a Lyra header with a green connection dot

Lyra's widgets on the desktop - the Control Panel (left), plus the Monitor Toggles and Volume widgets.

WidgetButtonsSizes
Lyra - Control PanelVolume, Mute / DIM / Mono, Slots 1-3 (all in one)Large
Lyra - Monitor TogglesMute, DIM, MonoMedium
Lyra - VolumeVolume down, Volume upSmall or Medium
Lyra - Reference LevelsSlot 1, Slot 2, Slot 3Medium

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.

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.


12. UA Mixer Engine #

Lyra talks to UA Mixer Engine - the local daemon that backs UA Console. It connects over TCP to localhost:4710 and uses UA's NULL-terminated text protocol (get /path\0, set /path value\0, subscribe /path\0 → JSON responses).

The monitor parameters Lyra reads/writes:

ParameterPathWhat it controls
Volume (tapered)/devices/0/outputs/4/CRMonitorLevelTaperedFloat 0.0-1.0 - the Monitor knob
Mute/devices/0/outputs/4/MuteBool
DIM/devices/0/outputs/4/DimOnBool - Apollo applies the attenuation set in Console
Mix-to-Mono/devices/0/outputs/4/MixToMonoBool

The paths above show outputs/4 because that's the Monitor output on Apollo Twin X. As of v1.6, the output index is discovered at connect, not pinned - Lyra asks the Mixer Engine which output is the Monitor and uses whichever index your hardware reports. Twin X reports 4; other Apollo models report different indices. If discovery doesn't return a usable answer, Lyra falls back to 4 so existing Twin X setups are unaffected.

Lyra subscribes to all four properties, so any change made elsewhere - turning the hardware knob, clicking Console's mute, automating Mixer parameters from a script - is reflected in Lyra's icon, menu, and HUD within ~100 ms. This works both ways: Lyra is a peer to Console, not a layer on top of it.

Starting the Mixer Engine

If the menu shows "<device> - UA Mixer not running", click Start UA Mixer Engine. Lyra prefers the headless engine:

  1. First, the standalone UA Mixer Engine.app at /Library/Application Support/Universal Audio/Apollo/UA Mixer Engine.app - installed by recent UA drivers, runs the TCP daemon with no GUI window.
  2. If that's missing, UA Console - opens the full Console app, which always starts the daemon as a side-effect. Used on older driver installs.

Once the daemon is up, Lyra's TCP client auto-connects and the menu flips to "Connected: <device>".

Reconnection

If the daemon drops (Console crashes, you quit it, the machine sleeps) Lyra retries the connection every 5 seconds in the background. You don't need to relaunch - leave Lyra running and it will pick the connection back up when the daemon returns. Same on Apollo unplug/replug: when CoreAudio reports the device gone, Lyra stops trying and waits; when it's back, the connection resumes.

Lifecycle automation (opt-in, v1.6+)

Two opt-in toggles in Settings tie Lyra to the Apollo's presence:

Each automation has a paired Show a notification when this happens sub-toggle (on by default). The banner explains what Lyra just did. Once you trust the automation you can turn the notification off and let it run silently. macOS asks for notification permission the first time Lyra tries to post.

Both parent toggles default to off. Lyra has no opinion about your UA workflow until you ask for one.


13. Settings #

Open with Cmd+, or Settings… in the menu. New in v1.6. Two sections.

Lyra's Settings window in its default appearance: an Automation section with auto-start and auto-quit toggles (both off) plus their paired notification sub-toggles, and a General section with the volume HUD toggle and volume step slider

Automation

General

Settings persist across launches in the standard macOS preferences. Changing the volume step takes effect immediately - no relaunch needed.


14. Trial & licensing #

Lyra is $9.99, one-time purchase, via Lemon Squeezy.

Trial

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.

After your trial: short test sessions

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.

Buying

Click Buy Lyra - $9.99 in the menu (or the Buy button on the website). Lemon Squeezy emails you the license key after checkout.

Activating

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.

Two-machine limit

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.

Lost your key?

Check the Lemon Squeezy confirmation email. If you can't find it, email hello@headroomstudio.dev with the address you used at checkout.

Validation

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.


15. Updates #

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.


16. Launch at login #

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.


17. Troubleshooting #

F-keys do nothing

  1. Accessibility permission. Open System Settings → Privacy & Security → Accessibility and verify Lyra is in the list and toggled on. The toggle changing colour isn't enough - make sure the row says "On".
  2. Mixer Engine connected. Open Lyra's menu. If it says "<device> - UA Mixer not running", click Start UA Mixer Engine. Lyra doesn't intercept F-keys while the daemon isn't reachable, so the keys behave normally until it connects.
  3. Fn key requirement. If your keyboard is set to "F1, F2, etc. keys as standard function keys" → off, you need to hold Fn for F10-F12 to act as F-keys at all. Either toggle the setting in System Settings → Keyboard → Function Keys, or hold Fn when pressing.

Lyra doesn't appear in the Accessibility list

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.

"No compatible interface detected"

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.

"UA Mixer not running"

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.

Volume jumps in big steps

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.

HUD doesn't appear

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.

Sparkle won't show an update prompt

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.

License says invalid even though I just bought it

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.

Trial says expired but I just installed

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.


18. What Lyra doesn't do #

Out of scope, in case any of these are dealbreakers:


19. Reporting bugs & feedback #

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).

↑ Back to top