Skip to content

Architecture

darius.codes edited this page Apr 13, 2026 · 1 revision

Architecture

iQualize captures and processes system audio entirely in-process — no virtual audio driver, no kernel extension, no background daemon.

Core Audio Taps

The foundation is CATap (Core Audio Taps), introduced in macOS 14.2. Unlike virtual audio devices (BlackHole, eqMac's driver approach), CATap intercepts audio directly from the HAL output stream. You keep system volume control, don't break DRM-protected audio, and avoid the latency of a secondary audio path.

iQualize creates a process tap that captures all system audio except its own output (preventing feedback loops), writes samples into a ring buffer, and feeds them into AVAudioEngine for processing.

Audio Pipeline

macOS Audio Server
│
├── App Audio ──┬── Output Device (muted by tap)
│               │
│               └── CATap ──► iQualize IOProc
│                              │
│                              ▼
│                         Ring Buffer
│                              │
│                              ▼
│                     AVAudioSourceNode
│                              │
│                              ▼
│                      AVAudioUnitEQ
│                      (parametric EQ)
│                              │
│                              ▼
│                      Output Gain Node
│                              │
│                              ▼
│                      AUPeakLimiter
│                              │
│                              ▼
│                      Output Device

The ring buffer decouples the real-time IOProc callback (fixed hardware timing) from AVAudioEngine's pull model (variable render timing). Parameter changes are written atomically — no locks on the audio thread, no glitches on slider drags.

EQ Modes

iQualize supports two EQ modes:

  • Linked mode — uses a single AVAudioUnitEQ for both channels. Simple and efficient.
  • Split-channel mode — bypasses AVAudioUnitEQ and runs independent biquad filter chains per channel in the render callback, allowing separate L/R EQ curves.

Spectrum Analysis

Real-time spectrum visualization uses Accelerate.framework's vDSP for SIMD-accelerated FFT:

  • 2048-point FFT with Hann windowing
  • 1024 FFT bins mapped to 128 log-frequency display bins (20 Hz – 20 kHz)
  • Instant-attack, exponential-decay smoothing per bin
  • Peak hold lines with ~2 second hold time
  • Dual analyzers: pre-EQ (raw input) and post-EQ (processed output)

Lock-free Audio-to-UI Transfer

The spectrum data uses a double-buffered lock-free design:

  • Two alternating Float arrays (magnitudes + peaks)
  • Audio thread writes to the inactive buffer, then atomically flips an index (guaranteed atomic on ARM64)
  • UI thread reads from the active buffer at 60 fps
  • Worst case: one stale frame (imperceptible)
  • Zero locks, zero allocation, zero contention on the audio thread

Frequency Response

The biquad frequency response curve is computed using Audio EQ Cookbook formulas — standard IIR coefficient calculations for parametric, shelf, high/low pass, band pass, and notch filters. The transfer function H(z) is evaluated at each display frequency to plot the expected magnitude response before it hits the audio engine.

Key Frameworks

Framework Usage
Core Audio CATap, aggregate devices, IOProc callbacks
AVFAudio AVAudioEngine pipeline, AVAudioUnitEQ, AUPeakLimiter
Accelerate vDSP FFT, vectorized spectrum processing
AppKit Menu bar UI, NSWindow, NSView-based EQ interface
ServiceManagement Start at Login (SMAppService)

Clone this wiki locally