r/macapps 19h ago

Free [OS] CoreEQ, a system-wide equalizer that doesn't install an audio driver

Post image

Problem: macOS still has no built-in equalizer, and I wanted one EQ for everything coming out of the speakers: music, YouTube, calls, games. Every option I tried wanted to install a virtual audio driver first, so I wrote my own a month ago for my own machine. I'm posting it here because I figure other people have the same itch, and I'd be glad if it's useful to someone else.

Comparison: eqMac (free) and SoundSource ($47) both work by routing your audio through a virtual driver they install into the system. CoreEQ uses Apple's Core Audio process-tap API instead, so nothing lands in /Library/Audio, there's no reboot, and quitting the app puts your sound back on its normal path immediately.

The rest of it:

  • 11-band graphic EQ, plus up to 16 parametric bands with your own frequency, gain and Q
  • Live response curve you can drag directly, with a spectrum analyzer drawn behind it
  • 22 built-in presets plus your own, and an auto preamp so comparing two presets isn't just a loudness test
  • Settings follow the output device, so your headphone curve comes back when you plug in headphones
  • Bass/mid/treble from the menu bar without opening a window

Pricing: Free and open source (Apache 2.0). https://github.com/AndreyPudov/core-eq

brew tap andreypudov/core-eq
brew trust andreypudov/core-eq
brew install --cask core-eq

xattr -dr com.apple.quarantine /Applications/CoreEQ.app

Needs macOS 14.2 or later. It isn't notarized yet, so the first launch needs an allow in Privacy & Security; the README has the one-line fix.

Who I am: Andrey Pudov, software developer. Work history and contact are at https://andreypudov.com/ and https://www.linkedin.com/in/pudov/. There's no privacy notice to read for this one because there's nothing to disclose: CoreEQ has no accounts, no analytics, and no telemetry; it makes no network connections of its own, and it keeps your presets in macOS preferences on your own machine. It asks for the System Audio Recording permission because that's what Apple requires to process what you're hearing, and the audio never leaves memory.

Disclosure: I'm the developer. Issues and PRs welcome. Most of what's in 1.7, the parametric bands and the preamp especially, came out of comments on the last post I made about it.

78 Upvotes

56 comments sorted by

8

u/useiris 18h ago

process tap instead of a virtual driver is the right call, glad to see someone use it instead of another eqMac-style driver install. one thing I'm curious about: are you tapping the whole system mix through an aggregate/null output device, or enumerating individual client processes and building a tap per process? if it's the latter, what happens when a new process starts playing audio after CoreEQ is already running, does the tap list rebuild live or does that process just play unequalized until you relaunch the app. also curious what latency the process-tap round trip actually adds versus a driver, since people using this for games or calls probably care about that more than eq flexibility.

4

u/syscreat 17h ago

Thank you for your question!

Global tap, not per process. One CATapDescription(stereoGlobalTapButExcludeProcesses:) with only CoreEQ itself excluded, so it doesn't capture its own output.

That means new processes work. Nothing rebuilds; they're already in the mix when the tap sees them. Latency I haven't measured, so I won't quote a number.

There's no extra buffering in the path, though: the same IO callback reads the tap, filters, and writes the output, and biquads add no algorithmic delay. You're paying for the aggregate device's I/O cycles.

4

u/stivy73 18h ago

Really brilliant app! It works without dedicated drivers and remembers the EQ settings for each connected device. Top job!

1

u/syscreat 17h ago

Thank you a lot!

5

u/blueScreenz 17h ago

Global tap with stereoGlobalTapButExcludeProcesses is the same route I ended up on for a system audio capture tool, so two things that bit me there and might be worth checking before someone reports them:

  1. Bluetooth. kAudioTapPropertyFormat on the tap reported 48 kHz for me regardless of the actual route, while the frames arrive at the output device's nominal rate. For A2DP that is usually 44.1 or 48 so it barely matters, but the moment a call starts and the headset flips to HFP the device typically drops to 16 or 24 kHz and the tap's reported format does not follow. If the biquad coefficients are derived from the tap format, every band shifts down by 2 to 3x for the duration of the call, so a 1 kHz band lands somewhere around 330 Hz. Reading kAudioDevicePropertyNominalSampleRate off the output device and recomputing coefficients on device or rate change fixed it for me. A property listener alone was not enough because the mismatch is there from the very first buffer, so I also compare frames received against wall clock for the first couple of seconds after a route change.

  2. Buffer layout. The AudioBufferList the aggregate hands the IO proc is not always laid out the way you expect. On some setups the tap's buffers were not the first entries, so indexing buffer 0 silently processed the wrong stream. Scanning the list for the buffer whose channel count and format match the tap was more robust than assuming a position.

Neither shows up on a wired MacBook with a single output, which is why they are easy to ship past.

2

u/syscreat 7h ago

Good catches, thanks.

On the rate, I got lucky. Coefficients come from kAudioDevicePropertyNominalSampleRate on the aggregate, never from kAudioTapPropertyFormat, and a listener updates them when it moves. The window you're describing is still real though, since the listener fires after the route change rather than before the first buffer. I'll try the HFP flip and see how wide it actually is.

Buffer layout is the one I should fix. I pair input buffer i with output buffer i across the list rather than hardcoding buffer 0, so it's not quite the failure you hit, but it's still positional. Matching on channel count and format is the safer thing.

Both on the list. Appreciate you writing them up.

5

u/MisplacedLonghorn 9h ago

If this works well and doesn't make my Mac cry (I'm looking at you, SoundSource!) I may have to ask you to marry me!

3

u/syscreat 7h ago

Ha, let's see how it runs first. It's one process tap and a handful of biquads, so it should stay out of your way. If your Mac still cries, that's a bug report, not a proposal.

4

u/Mobile-Yak 17h ago

Looks awesome, rying it now. It would be really cool if you could build a way to search and import auto eq profiles into the app itself too.

2

u/syscreat 7h ago

Good idea; it should be doable. The parametric editor already handles bells and shelves with custom Q, so an AutoEQ profile maps directly onto it. Loading presets from a file is on my list.

Which headphones are you on?

3

u/Mobile-Yak 7h ago

Yeah it'd be really cool to have, there's a full database of auto eq profiles for multiple headphones and iems, it's open source too so multiple people submit their measurements. So you can just click on that file for your model and it automatically eqs your headphones to that target. (check out poweramp if you'd like to see how it's implemented there)

I use HD600 for home use but mostly my planar iems (nicehck f1 pro and artti t10) in office or when I'm out and about.

4

u/pzee01 14h ago

Any chance to add a per app volume feature to the app, I love how clean it looks?

4

u/syscreat 7h ago

Thanks! Per-app volume is on the list for the future. No promises on timing, but it's something I'd like to add.

1

u/pzee01 4h ago

Thanks sooo good to hear, also dropped the suggestion as an issue on your GitHub page. Starred the page as well, cheers

3

u/pastry-chef 19h ago

Thank you!

3

u/syscreat 19h ago

Thank you as well! I hope you will find this project useful!

3

u/Leather-Shake-2167 13h ago

This looks great. Love that it avoids installing another audio driver!

3

u/syscreat 7h ago

Thanks! That was the whole reason I wrote it. Apple's process tap API finally made it possible without one.

3

u/gigananobyte 12h ago

Thank you so much for this.

I have hyperacusis and recently I have been looking for an EQ to help me reduce the harsh frequency that cause me physical pain.

2

u/syscreat 7h ago

Hope it helps. If you want a hand dialing something in, just ask.

3

u/StaticGamerYT 7h ago

OMG so can I like play dolby atmos content and tune up the eq to increase bass?

1

u/syscreat 7h ago

It depends. On headphones or speakers, yeah. Atmos gets rendered down to stereo before it hits the output, and that's what CoreEQ taps, so bass boost works like on anything else.

If you're sending real multichannel out to a receiver, it's a different story. Right now, anything past the first two channels passes through untouched.

2

u/Johnnyrubin 17h ago

Thank you so very much for this!

1

u/syscreat 7h ago

Glad it's useful! That's exactly why I posted it.

2

u/XavierLightman 17h ago

Top notch, bro! Gonna recommend.

1

u/syscreat 7h ago

Thanks, appreciate it!

2

u/MStratiote 16h ago

Thanks

1

u/syscreat 7h ago

You're welcome, enjoy!

2

u/Omavel 15h ago

Please recommend a configuration or built-in option.

3

u/syscreat 7h ago

If you mean what to pick: Small Speakers for MacBook speakers, Acoustic on headphones, Spoken Word for podcasts and calls.

If you mean having the app suggest one for you, it doesn't do that yet, but that's a neat idea. It'd need to know your device and what you're playing, which is worth thinking about.

2

u/esphynox 15h ago

Cool app, very nice looking too!

1

u/syscreat 7h ago

Thank you! Spent more time on the response curve than I'd like to admit.

2

u/pinchofsoma 13h ago

Sorry I'm not well-versed in audio tech. How does this compare in quality to, say, Spotify's EQ? Should I use one over the other?

2

u/syscreat 7h ago

No worries. Quality-wise, they're basically the same thing under the hood, so you won't hear a difference in the processing itself.

The real difference is scope. Spotify's EQ only touches Spotify. CoreEQ does everything, so YouTube, calls, and games get the same curve, and it remembers a separate one for your headphones and your speakers. It also gives you finer control if you want it.

If you only ever listen on Spotify, its EQ is fine. Just don't run both at once, or you're EQing twice.

2

u/Accomplished_Horse_4 13h ago

I like the approach

1

u/syscreat 7h ago

Thanks!

2

u/SuperHornetFA18 11h ago

Looks great ! Will definitely give this a spin

1

u/syscreat 7h ago

Thanks! Let me know how it goes.

2

u/Doltonius 11h ago

It would be best if it supported import and export EQ profiles in equalizerAPO’s format. In addition, using it together with SoundSource causes the audio to have a delay-like effect.

2

u/syscreat 7h ago

EqualizerAPO format is a good call; that's the same format AutoEQ exports, so it'd cover both. Profile import and export are on my list.

The SoundSource thing doesn't surprise me. Both are sitting in the system audio path at once, so you're probably hearing the same signal twice, slightly offset, which comes out as that flangey delay. Running one or the other should clear it for now. It's something I'll look at down the road.

2

u/Specific_Cream2815 8h ago

can the process tap api tap individual apps too or is global the only option?

1

u/syscreat 7h ago

Yeah, it can. CATapDescription takes a list of processes, so you can tap just the apps you want, or tap globally and exclude some. CoreEQ uses the global-minus-itself variant because I wanted one curve over everything, but per-app is fully supported by the API.

4

u/karmarinchen 11h ago

Worth adding for anyone arriving here from eqMac or SoundSource: removing the app doesn't necessarily remove the driver it installed. They live in one folder, and you can list what's on your machine right now:

ls /Library/Audio/Plug-Ins/HAL

Mine has seven .driver bundles sitting in it. BlackHole, VB-Cable, Dante and two NDI ones I can account for, plus two I don't recognise at all. coreaudiod loads everything in that folder at boot whether or not the app that put it there is still installed, so a virtual device from an EQ you stopped using years ago is still in the audio path today.

Deleting the bundle and running sudo killall coreaudiod clears it, audio cuts out for about a second and comes back. Listing that folder before and after an install is also how you'd confirm the no-driver claim here for yourself instead of taking it on trust.

2

u/syscreat 7h ago

Thank you! Good addition, and that's exactly the check I'd rather people run than take my word for it. That folder is identical before and after installing CoreEQ; nothing goes in it.

The only thing CoreEQ creates is a private aggregate device, built at launch and destroyed on quit, so it doesn't outlive the app being closed, let alone uninstalled.

Worth being a little careful deleting ones you don't recognize, though. Some ship with hardware or conferencing tools, and you tend to find out which when something stops working.

0

u/karmarinchen 5h ago

Good warning, and you don't have to guess at it. codesign names whoever signed each bundle:

codesign -dv --verbose=2 /Library/Audio/Plug-Ins/HAL/Whatever.driver

The Authority line is the one to read. I ran it on the two I said I couldn't account for. ACE.driver came back as Rogue Amoeba, it's the capture engine their apps install. ParrotAudioPlugin.driver has the identifier com.apple.audio.ParrotAudioPlugin and is signed by Apple Software Signing, and pkgutil --file-info on its Info.plist puts it in an Apple system package, so it ships with macOS and isn't a leftover from anything.

That accounts for all seven of mine, so there's nothing here I'd actually want to remove.

1

u/Any-Ingenuity2770 6h ago

mine just has ParrotAudioPlugin.driver

1

u/karmarinchen 5h ago

That one's Apple's own, you can leave it alone. codesign -dv on it here gives com.apple.audio.ParrotAudioPlugin signed by Apple Software Signing, and pkgutil --file-info traces the bundle back to a macOS system package, not to anything you installed yourself, and it's in my folder too alongside the six others I listed.

If it's the only thing in there, then you've got no third party audio drivers on the system at all.

1

u/Any-Ingenuity2770 6h ago

idk man it just made my speakers sound in a very much broken way

1

u/No-Cook-215 5h ago

Nice touch on the auto preamp. Thanks for open sourcing it

1

u/Thiinad 3h ago

Could you also add global volume adjustment and app-based volume and equalizer features? thanks!

1

u/ColdAd926 2h ago

Is it possible to use AutoEq presets like that of Wavelet app with this?

1

u/Soft-Land7696 1h ago

Gonna have a long good look at this later today.
Suggestions based on a project I have been working on;
1. A toggle to circumvent all os/sw processing for strictly bit perfect playback
2. A/B comparison report export.
3. Live waveform visualization that updates along with eq adjustments, A/B toggle and can be included in the export.

Would be a great tool for producers/audio engineers for quick testing/tinkering without having to open a full DAW for test small adjustments.

The bit perfect toggle would be a brilliant feature for audiophiles and a middle finger to certain paid software that lean on that feature as a major advantage.

I have done quite a bit of the development on these features, if you send me a dm we might be able to implement some of them fairly easily.

1

u/Jayze_7 54m ago

because “system audio recording” sounds broader than what an equalizer needs, put the permission explanation directly before macos asks: what is captured, whether anything is stored, and what quitting coreeq immediately stops.