Play your music loud. When someone in the room talks to you, Mr. AutoDuck turns it down for you β and back up when they're done.
A tiny macOS menu-bar app. On-device, open source, and he falls asleep in your menu bar while the music rests.
You like your music loud. You also live with people. Every "hey, got a sec?" means scrambling for the volume keys, losing your thread, and the vibe is gone.
Mr. AutoDuck is cinematic audio ducking for real rooms: he listens through the Mac's microphone, ignores the music the Mac itself is playing, and when he hears a human voice he fades the system volume down to a level you can talk over. A few seconds of quiet later, the music swells back. You never touch a key.
- Ducks any player β Apple Music, Spotify, YouTube, games. It moves the Mac's volume, not the app's.
- Ignores its own music. Apple's voice-processing echo cancellation subtracts what the Mac is playing before detection, so vocals in a song don't count as "someone talking".
- Decides like a person would. Apple's on-device sound classifier has to say speech and the voice has to be loud enough to be in the room β for about a second β before it acts. Both are live meters in the popover, with markers, so you can see exactly why it ducked.
- Gets out of your way. Touch the volume keys while he's ducked and he hands control back until the conversation ends. Quit (or crash) and your volume is restored.
- Stays invisible. A menu-bar duck. No window, no dock icon, no notifications. β₯βL pauses it anywhere.
- Private by construction. Audio is analysed in memory and discarded. No recordings, no uploads, no analytics, no network code at all. This repo is the proof.
Pre-release β there is no notarized download yet. Building takes one command (Xcode 15+ / macOS 14+):
git clone https://github.com/Sanforing/MrAutoDuck.git && cd MrAutoDuck
Scripts/build-app.sh --run # β "build/Mr. AutoDuck.app", launched; look for the duck in the menu barGrant microphone access when asked (that's his whole job). Then play something loud and say hello from across the room.
Sign with your own identity to keep the permission across rebuilds:
SIGN_IDENTITY="Apple Development: β¦" Scripts/build-app.sh. Ad-hoc builds may needScripts/reset-permissions.shafter a rebuild.
Two detectors, switchable in the popover:
| Mode | How | When to use |
|---|---|---|
| Classifier + level (default) | Apple SoundAnalysis classifier on the echo-cancelled mic (0.75 s windows, 5Γ/s) and a post-echo level threshold; one Sensitivity slider moves both |
Shows its work; tune it with the meters |
| Apple voice detector | The talker detector inside the voice-processing unit (the one behind "you're muted" hints) | Fewer false alarms from vocals; may need you to speak up |
Measured on a MacBook Pro, macOS 26 β the findings that shaped the code:
AVAudioEngine+setVoiceProcessingEnabled(true): don't touchmainMixerNode. Connecting the mixer brings it up at 44.1 kHz while VPIO runs at 48 kHz βstart()fails with-10875. Input-only works.- The voice-processing input node advertises a 9-channel format whose channels are identical junk. Tap it as mono at the node's sample rate and you get the real echo-cancelled signal.
- Echo of the Mac's own playback: raw mic β24 dB β after cancellation β50 dB (β25 dB gone). But the residue still classifies as speech about half the time β the classifier alone is not enough. With AGC off, a real person in the room measured 8β15 dB above that residue, which is what the level gate uses.
- Muting the VPIO input mutes it for every engine in the process, and a raw engine created after a VPIO engine produces no buffers β so the two detectors are modes, not parallel signals.
- macOS ducks other apps' audio whenever a voice-processing unit runs β and not only the layer that
voiceProcessingOtherAudioDuckingConfigurationcontrols. At unit creation it applies a flat β15 dBAudioDeviceDuckto the output device that no public API removes: music sounds "behind a door" the whole time you listen. Duck state is per HAL client, so calling the same (private)AudioDeviceDuck(device, 1.0, β¦)from your own process lifts your duck and nobody else's (SystemDuck.swift). Keep the configurable layer onenableAdvancedDucking: trueso it only ducks while voice is actually heard. - On macOS 26,
AVAudioEngineConfigurationChangeoften fires ~35 ms after a voice-processing start without stopping the engine (the unit rebuilds its private aggregate device; near-guaranteed with any Bluetooth device connected). Restarting on every notification = an infinite restart loop that makes every other app's playback stutter. Checkengine.isRunningand restart only if it really stopped. - Never listen through a Bluetooth headset's mic: opening it drops the headset into the hands-free profile and everything it plays turns muffled and mono. VPIO keeps its input device on AU element 1 (element 0 is the output/echo reference) β re-point it at the built-in mic, and read the tap sample rate from the unit itself, because the node's cached formats go stale after the switch.
- Never
engine.prepare()beforeinstallTapβ an initialised unit refuses the format change andinstallTapthrows an uncatchable Objective-C exception (a crash loop, if the mic starts at launch).
The probes that produced those numbers are in Sources/MrAutoDuck/Probe.swift
(open "build/Mr. AutoDuck.app" --args --probe4 /path/to/song.mp3). Key files:
| File | Role |
|---|---|
Audio/MicMonitor.swift |
Voice-processing input, classifier, level statistics, Apple-VAD mode |
Audio/VoiceActivityGate.swift |
Debounce + hold β "someone is talking" |
Audio/Ducker.swift |
Volume state machine, user-override handling |
Audio/VolumeController.swift |
Core Audio get/set volume, device & volume listeners |
UI/MenuView.swift, UI/DuckIcon.swift |
The popover and the vector duck |
| Setting | Default | Meaning |
|---|---|---|
| Detector | Classifier + level | see above |
| Sensitivity | 45 % | Level β₯ β46 dBFS and speech β₯ 58 %. Higher = hears quieter / farther voices, more false alarms |
| Lower music to | 25 % | Ducked volume as a fraction of your current volume |
| Keep low for | 4 s | Silence needed before restoring |
| Fade down / up | 0.7 s / 3 s | Ramp times |
| Only duck when speech outscores music | off | Stricter classifier rule |
| Launch at login Β· β₯βL hotkey | off Β· on |
It won't bother ducking if your volume is already β€ 15 %.
- Calls: your own voice ducks the call audio. Pause with β₯βL. Auto-pause when another app uses the mic is next on the list.
- Bluetooth / AirPlay output: the extra latency hurts echo cancellation; expect more false triggers. Built-in or wired speakers are the target.
- Bluetooth headset mics are never used. Opening an AirPods-style mic drops the headset into its hands-free profile and everything it plays turns muffled and mono. If your default input is a Bluetooth headset, Mr. AutoDuck listens through the Mac's built-in mic instead (the popover says which).
- Very loud music distorts the speakers and leaves more echo residue β lower Sensitivity.
- TV or a podcast in the room is speech and will duck the music. By design, but worth knowing.
- It ducks even when nothing is playing (harmless; it restores). "Only when something is playing" is planned.
- Detection was tuned in one room on one Mac. Reports from your room are the most valuable contribution β see docs/TESTING.md for the protocol and CONTRIBUTING.md.
Next: real-room tuning on more Macs Β· auto-pause during calls Β· notarized .dmg with Sparkle updates Β·
EN + ηΉδΈ Β· "say something from the couch" calibration. The quality bar 1.0 has to pass is in
docs/TESTING.md.
/usr/bin/log stream --predicate 'subsystem == "com.mrautoduck.app"' --level info # zsh shadows `log`Small on purpose. Issues and PRs welcome β CONTRIBUTING.md. Ground rules: audio never touches disk or network; the UI stays calm; error messages say what happened and what to do.
Code: GPLv3. The Mr. AutoDuck name, duck mascot and icon are trademarks of Playwithspect β forks, please pick your own name and duck (TRADEMARK.md).
A notarized, auto-updating build will be sold for a small one-time price to keep the side quest funded; building from source is always free.
A side quest by Playwithspect β playful at heart, respectful in craft.
If Mr. AutoDuck saved your vibe, a β helps the next loud-music household find him.
