Skip to content

Solvely-Colin/OpenFader

Repository files navigation

OpenFader

Platform Swift License Status

OpenFader is a native macOS app for per-app audio control: music, browsers, games, calls, streams, and anything else producing output.

It is built around public Core Audio process taps, a SwiftUI/AppKit desktop UI, and a local-first settings model. The goal is simple: give macOS the source mixer it should already have, without requiring a cloud account, browser extension, or proprietary audio stack.

OpenFader mixer in demo mode

Why OpenFader?

macOS gives you one system volume slider. Real work rarely sounds like one thing.

OpenFader lets you tune each active audio source independently:

  • lower a browser while music stays full
  • push call audio forward without crushing everything else
  • tame loud games, streams, alerts, or video playback
  • save per-app profiles so your mix follows the source
  • build reusable templates for night listening, voice clarity, music, cinema, gaming, and custom workflows

OpenFader is also a serious Core Audio project. It does not pretend macOS has a magic public API for another app's volume. It discovers active process audio, creates process taps, routes tapped audio through a guarded render engine, and applies gain, balance, EQ, limiting, solo, mute, and meters in the open.

Screenshots

Mixer Templates Routing
Mixer view with demo sources Template library with a custom demo template selected Routing view with live route demo state

Highlights

  • Per-source mixer: control active app audio from the menu bar or full app window.
  • Live gain path: route process tap audio through a Core Audio render loop for per-source gain, balance, EQ, limiting, mute, solo, and meters.
  • Templates: quick-load built-ins such as Voice, Music, Cinema, Night, Detail, Warm, and Gaming Focus, plus user-authored custom templates.
  • Auto-apply rules: load the right preset when a matching source appears, using stable source keys, bundle IDs, or display-name fallbacks.
  • Saved profiles: keep source-specific gain, balance, mute, EQ, limiter, loudness target, and active preset state.
  • Loudness tools: processed peak/RMS meters and explicit one-click RMS target matching.
  • Routing diagnostics: copy live route state, render health, buffer layout, route phase, tap IDs, aggregate IDs, and source settings for debugging.
  • Demo mode: launch a deterministic in-memory environment for screenshots, demos, and UI review without touching your real settings file.

Project Status

OpenFader is in active development and now ships through signed release artifacts. It builds, tests, packages locally, publishes a notarized GitHub DMG, and uploads a sandboxed Mac App Store package through CI. The Core Audio route path is implemented and continues to be hardened across more devices and stream layouts.

Area Status
Source discovery Working through Core Audio HAL process objects
Menu bar UI Working
Full app window Working
Saved profiles and templates Working
Auto-apply rules Working
Process tap routing Implemented, still being hardened
Gain, balance, EQ, limiter, meters Implemented in the render graph
Packaged .app for local testing Working through scripts/package-macos-app.sh
GitHub release DMG Automated through release-dmg.yml
App Store upload Automated through release-dmg.yml; manual upload workflow also available
Broad device/layout validation Roadmap

Quick Start

Requirements

  • macOS 14.2 or newer for Core Audio process taps
  • Xcode 16 or newer recommended
  • Swift 6 toolchain recommended
  • System Audio Capture permission for live gain/EQ rendering

The project was initially validated with Xcode 26.2 and Swift 6.2.3.

Build and Test

swift build
swift test

Run from SwiftPM

swift run OpenFader

The SwiftPM executable is useful for quick UI and model work. For live audio permission stability, use the packaged app bundle below.

Package a Local macOS App

System Audio Capture permission is tied to app identity, so live per-source gain/EQ testing should run from a signed app bundle:

./scripts/package-macos-app.sh debug
open .build/openfader-app/debug/OpenFader.app

The packaging script builds OpenFader, creates a minimal .app, copies the Info.plist, and signs it for local testing. It uses OPENFADER_CODESIGN_IDENTITY when set, otherwise the first available Apple Development or Developer ID identity, and falls back to ad-hoc signing when no local identity is available.

If macOS keeps an old System Audio Capture grant around after a rebuild, reset the grant and reopen the signed app:

tccutil reset AudioCapture app.openfader.OpenFader
open .build/openfader-app/debug/OpenFader.app

Demo Mode

Demo mode launches OpenFader with staged sources, output devices, templates, profiles, auto-apply rules, and live route state. It is designed for README screenshots, product demos, and UI review.

It uses an in-memory settings repository and does not read or write:

~/Library/Application Support/OpenFader/SourceSettings.json

Launch specific sections:

OPENFADER_DEMO_MODE=1 OPENFADER_DEMO_SECTION=mixer .build/openfader-app/debug/OpenFader.app/Contents/MacOS/OpenFader
OPENFADER_DEMO_MODE=1 OPENFADER_DEMO_SECTION=templates .build/openfader-app/debug/OpenFader.app/Contents/MacOS/OpenFader
OPENFADER_DEMO_MODE=1 OPENFADER_DEMO_SECTION=routing .build/openfader-app/debug/OpenFader.app/Contents/MacOS/OpenFader

Supported sections:

setup
mixer
templates
rules
routing
profiles
settings

How It Works

macOS does not expose a simple public API for setting another app's output volume. OpenFader uses the public route that does exist:

  1. Discover the process object for an active audio source.
  2. Create a private Core Audio process tap for that source.
  3. Mute the original source output while the tap is active.
  4. Read audio from the tap.
  5. Apply gain, balance, EQ, limiting, mute, solo, and meters.
  6. Write processed audio to the selected output device.
flowchart LR
    A["Core Audio process objects"] --> B["OpenFader source model"]
    B --> C["Saved profiles and templates"]
    C --> D["Process tap routing engine"]
    D --> E["Source render graph"]
    E --> F["Rendered output device"]
    B --> G["Menu bar and app UI"]
    G --> C
Loading

The code is split into a small app target and a core audio/model library:

Path Purpose
Sources/OpenFader SwiftUI/AppKit app, menu bar panel, main window, demo mode
Sources/OpenFaderCore Core Audio discovery, routing engine, render graph, settings model
Sources/OpenFaderRouteSmoke Runtime route validation utility
Tests/OpenFaderCoreTests Profile, template, DSP, routing, and render-plan tests
docs/ENGINE.md Engine contract, current risks, and work queue

Features in Detail

Source Control

  • active output source discovery through Core Audio HAL process objects
  • stable source identity through bundle IDs, normalized names, and PID fallback
  • per-source mute, solo, reset, compare, and diagnostics
  • per-source processed peak/RMS meters
  • 1 dB gain nudges plus continuous gain sliders
  • balance controls for stereo positioning

Audio Processing

  • gain from 0% to 200%
  • dB readouts and gain conversion helpers
  • five-band EQ: Sub, Bass, Low Mid, Presence, Air
  • peaking, low-shelf, and high-shelf EQ filters
  • per-band gain, frequency, Q, filter type, and bypass
  • full processing bypass for auditioning original audio
  • limiter ceiling and gain-staging warnings
  • explicit RMS target matching from live meters

Profiles, Templates, and Rules

  • durable per-source profiles in Application Support
  • built-in presets for common listening contexts
  • custom templates saved from source settings
  • template rename, update, duplicate, delete, export, and import
  • favorite and recent template promotion
  • source-aware preset recommendations
  • auto-apply rules by stable source key, bundle ID, or display-name match
  • stale reference cleanup for profiles, templates, rules, favorites, and recents

Routing and Diagnostics

  • output device discovery and persisted routing selection
  • virtual output warnings for devices such as BlackHole, Loopback, and Soundflower
  • selected-output recovery when a saved output disappears
  • private aggregate route planning for tapped sources
  • render-loop health checks and fail-closed behavior
  • buffer layout diagnostics for interleaved stereo, planar stereo, and unsupported layouts
  • copyable route diagnostics for each source

Route Smoke Testing

OpenFaderRouteSmoke is a runtime validation utility for engine work. It can attach to active output sources, spawn a temporary spoken test source, sweep available output devices, apply gain or presets, and require proof that processing and meters were observed.

Build it:

swift build --product OpenFaderRouteSmoke

Package it for permission-stable validation:

./scripts/package-route-smoke-app.sh debug

Run a strong local proof:

.build/openfader-app/debug/OpenFaderRouteSmoke.app/Contents/MacOS/OpenFaderRouteSmoke \
  --spawn-say \
  --template-pack Tests/Fixtures/route-smoke-template-pack.json \
  --auto-apply-preset custom:route-smoke-detail \
  --seconds 3 \
  --sweep-outputs \
  --require-processing \
  --require-meter

More route detail lives in docs/ENGINE.md.

Distribution

OpenFader's primary direct-install path is a signed and notarized GitHub Release DMG. Push a version tag such as v1 and the release workflow builds the DMG, notarizes it when Apple credentials are configured, and publishes it as a GitHub Release asset.

The same tag workflow uploads a sandboxed macOS .pkg to App Store Connect when the App Store secrets are configured and the repository variables confirm sandbox readiness. The App Store path does not use the GitHub DMG artifact.

See docs/DISTRIBUTION.md for required secrets, local dry runs, notarization, and App Store upload notes. See docs/APP_STORE_CONNECT_SETUP.md for the Apple Developer/App Store Connect account checklist and listing metadata.

Roadmap

  • Broader audible validation across physical and virtual output devices
  • App Store review follow-through and release polish
  • More guided onboarding for System Audio Capture permission
  • Stronger render failure recovery for device changes and unusual stream layouts
  • Reproducible release builds

Contributing

Contributions are welcome, especially around Core Audio validation, UI polishing, route diagnostics, packaging, and tests.

Before opening a pull request, run:

swift test
swift build --product OpenFader
swift build --product OpenFaderRouteSmoke

See CONTRIBUTING.md for local validation notes and runtime proof commands.

License

OpenFader is released under the MIT License.

About

Native macOS per-source volume and EQ mixer built on Core Audio process taps

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors