eqtune 0.3.0

A lightweight, system-wide audio equalizer for macOS, built on Core Audio process taps.
docs.rs failed to build eqtune-0.3.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

eqtune

A lightweight, system-wide audio equalizer for macOS.

Why

Mac speakers and headphone outputs are tuned conservatively out of the box — often mid-heavy and a bit flat, so music can sound closed-in. macOS has no built-in system-wide EQ, and the existing tools tend to be heavyweight: they install loopback/kernel drivers and replace your default output device, which breaks macOS's normal "switch to the headphones when I plug them in" behaviour.

eqtune taps the system audio mix with Apple's modern Core Audio process-tap API (macOS 14.2+, no driver, no kernel extension, no code signing), applies a parametric EQ, and plays the result back to your current output device. Because it never hijacks the default device, plugging in EarPods or Bluetooth keeps working normally. It ships a few curated presets and lets you tweak any frequency yourself.

Requirements

  • macOS 14.2 or later (the process-tap API)
  • Xcode Command Line Tools — xcode-select --install (clang + CoreAudio)
  • Rust — https://rustup.rs

Install

From crates.io:

cargo install eqtune
eqtune install
eqtune on

Or from a clone:

cd eqtune
make install             
eqtune on

On the first eqtune on, macOS asks for audio-capture permission. (Rebuilding changes the binary's ad-hoc signature, so macOS may re-ask. That's expected.)

Usage

eqtune on | off | status              # start / stop / inspect
eqtune presets | preset <name>        # list / switch preset (short: ls / p <name>)
eqtune preset-save <name>             # save active tuning as a preset
eqtune preset-clone <src> <name>      # clone a preset and switch to the clone
eqtune preset-rename <old> <new>      # rename a preset
eqtune preset-rm <name> [name...]     # delete one or more presets
eqtune preset-export <name> [file]    # write a shareable preset TOML file
eqtune preset-import <file> [name]    # import a preset, optionally renaming it
eqtune band <freq_hz> <gain_db> [q]   # add or update a band (negative gains OK)
eqtune band-rm <freq_hz>              # remove the band nearest a frequency
eqtune preamp <db>                    # overall make-up gain
eqtune lowpower on | off              # auto-off in macOS Low Power Mode (default on)
eqtune idle on | off                  # auto-off while no media is active (default on)
eqtune reset [preset]                 # restore all shipped presets, or one preset
eqtune install | uninstall            # manage the launchd daemon
  • eqtune on and every edit (preset/band/band-rm/preamp/reset) print the resulting curve — the active preset, preamp, and each band — with the band you just changed flagged. eqtune off confirms the native Apple audio path is restored.
  • Tuning edits apply live (no audio restart). On eqtune off, eqtune asks whether to save the latest tuning as a new preset, overwrite the active preset name, or discard the session changes.
  • For the no-eqtune native Apple sound, use eqtune off.
  • To save battery, eqtune auto-disables while no media is active and resumes when playback starts again. It also auto-disables while macOS Low Power Mode is on and resumes when it turns off. An explicit eqtune on overrides Low Power Mode; turn these behaviours off with eqtune idle off or eqtune lowpower off.

Presets

Preset Character
bright (default) brighter, more presence
mellow warmer
pro crisp and detailed

Switch with eqtune preset <name> (or just eqtune p <name>), then fine-tune live with eqtune band / eqtune preamp. You can temporarily tune any preset, including bright, mellow, and pro; when you turn eqtune off, choose whether to save the result as a new preset, overwrite that preset name on your device, or discard it. When saving by name, entering bright, mellow, or pro overwrites that shipped preset on your device; entering any unused name creates your own preset. If you later regret overwriting a shipped preset, run eqtune reset bright (or mellow / pro) to restore the original shipped tuning; eqtune reset restores all three shipped presets while keeping your custom presets. If a reset would replace a modified local shipped preset, eqtune warns first and can save that local version under a new custom preset name before restoring the original. New custom preset names use ASCII letters, digits, -, _, or ., and never overwrite an existing custom preset. Share presets with eqtune preset-export my-bright, which writes my-bright.toml in the current directory, or pass an explicit path. Import them with eqtune preset-import my-bright.toml or eqtune preset-import my-bright.toml other-name.

Tweak your own

The EQ is fully editable. eqtune band adds or updates a peaking filter at any frequency on the active preset:

eqtune band 2000 -6        # cut 2 kHz by 6 dB (default Q 1.41)
eqtune band 8000 3 2.0     # boost 8 kHz by 3 dB with a narrower Q
eqtune band-rm 2000        # remove the 2 kHz band
eqtune preamp 4            # set the preamp to +4 dB

Editable values are validated before they reach the audio engine: band frequencies must be 20-20000 Hz, band gains -24 to +24 dB, Q 0.1-10, and preamp -60 to +12 dB.

Battery & energy

eqtune is an always-on background daemon that taps all system audio and re-processes every block in real time. That continuous work costs CPU, and on battery it adds up fast — stream music for a couple of hours and you'll see the charge drop noticeably quicker than with Apple's native audio path.

FYI: running a system-wide EQ increases battery drain, sometimes dramatically. A continuously-running real-time audio pipeline simply uses more power than native playback. If battery life matters to you, leave the Low Power Mode auto-off enabled (the default) and run eqtune off when you don't need the EQ.

Idle auto-off. When captured system audio stays silent, eqtune tears the audio engine down automatically and brings it back when the default output device reports active I/O again. Disable this behaviour with eqtune idle off.

Low Power Mode auto-off. When macOS switches on Low Power Mode, eqtune tears the audio engine down automatically (the single biggest saving) and brings it back when Low Power Mode turns off. An explicit eqtune on still overrides and runs even under Low Power Mode; disable the behaviour entirely with eqtune lowpower off.

Lighter real-time processing. Recent versions cut the per-block cost of the EQ so a long listening session draws less power:

  • No redundant rebuilds — filter coefficients are recomputed only when you actually change the EQ, not on every audio block.
  • No-op bands dropped — bands sitting at 0 dB are mathematical "do nothing" filters; they're removed from the live processing chain (the pro preset alone sheds ~5 of 28).
  • Idle suspension and silence skipping — when nothing is playing, eqtune can suspend the engine entirely; before suspension, sustained silence also skips per-sample work.

These trim the overhead but can't remove it — system-wide real-time audio always costs some power while the engine is active. See ARCHITECTURE.md for how the engine and signal path work.

How it works

system audio ─▶ global process tap (excludes eqtune; muted-when-tapped)
             ─▶ private aggregate device (output device + tap, one shared clock)
             ─▶ IOProc: capture → biquad EQ + preamp + soft limiter → replay
             ─▶ your current default output device

A launchd LaunchAgent runs the daemon; a Unix-socket CLI controls it. Putting the tap and the output device in a single aggregate device means they share one clock, so there's no resampling/drift to fight. A lightweight poll makes the engine follow default-device changes (plug in headphones and audio follows).

For a deeper dive — the daemon/CLI split, the lock-free real-time DSP, the Objective-C Core Audio shim, and why it's built this way — see ARCHITECTURE.md.

Uninstall

make uninstall      # or: eqtune uninstall

License

Licensed under either of MIT or Apache-2.0 at your option.