Skip to content

Latest commit

Β 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Mr. AutoDuck icon: a yellow duck quacking soundwaves at a volume-down symbol

Mr. AutoDuck

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.

macOS 14+ Swift License GPLv3 Status

Mr. AutoDuck popover while ducked: speech 91%, music 22%, level βˆ’31 dB, volume lowered to 19%


The problem it solves

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.

Menu-bar duck: awake while listening, asleep with a z while the music is ducked, faded when paused

What it does

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

Install

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 bar

Grant 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 need Scripts/reset-permissions.sh after a rebuild.

How it hears you

speakers β†’ room β†’ echo cancellation β†’ is that a person? β†’ debounce + hold β†’ fade the volume

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

What we learned building it (the part HN will want)

Measured on a MacBook Pro, macOS 26 β€” the findings that shaped the code:

  • AVAudioEngine + setVoiceProcessingEnabled(true): don't touch mainMixerNode. 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 voiceProcessingOtherAudioDuckingConfiguration controls. At unit creation it applies a flat βˆ’15 dB AudioDeviceDuck to 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 on enableAdvancedDucking: true so it only ducks while voice is actually heard.
  • On macOS 26, AVAudioEngineConfigurationChange often 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. Check engine.isRunning and 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() before installTap β€” an initialised unit refuses the format change and installTap throws 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

Settings

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

Honest limitations

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

Roadmap

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.

Logs & diagnostics

/usr/bin/log stream --predicate 'subsystem == "com.mrautoduck.app"' --level info   # zsh shadows `log`

Contributing

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.

License

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.


Playwithspect β€” Game Studio

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.

About

Play your music loud. Mr. AutoDuck lowers your Mac's volume when someone in the room talks to you, then brings it back. On-device, open source β€” and he falls asleep in your menu bar while the music rests. πŸ¦†

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages