Skip to content

VincentCusson/standin

Repository files navigation

standin

Build custom BlackHole-based virtual audio drivers that mimic a specific real audio interface: same name, same exact per-direction channel count, same per-channel labels (e.g. "ADAT 3", "Headphones L").

Why

A placeholder stands in for a real interface inside a CoreAudio aggregate device while the hardware is disconnected. Without one, an aggregate missing a member loses its channel routing, so a DAW routed to specific channels loses or misaligns them. A placeholder with the exact same name, channel count, and channel labels keeps that routing valid whether or not the real hardware is plugged in.

Requirements

  • Full Xcode.app (not just the Command Line Tools). xcodebuild needs the full toolchain. Install from the App Store, then:
    sudo xcode-select -s /Applications/Xcode.app
    sudo xcodebuild -license
    sudo xcodebuild -runFirstLaunch
  • git, python3 (both ship with macOS / Xcode CLT). standin is a single stdlib-only Python script, no pip installs.

Tested on macOS 26 (Tahoe) with Python 3.14.

Install

standin runs straight from the repo, no build step:

git clone https://github.com/VincentCusson/standin
cd standin
./standin list

To call it as standin from anywhere instead of ./standin, symlink it onto your PATH:

sudo ln -s "$PWD/standin" /usr/local/bin/standin

Quick start

./standin list                    # see available presets
./standin build --preset solo    # build a placeholder for a Focusrite Scarlett Solo (4th Gen)
./standin activate solo          # build + install it (asks before running sudo)
./standin status                 # confirm it's installed
./standin deactivate solo        # uninstall it

Or clone a device that's connected right now. It reads the real name, channel counts, sample rates, and channel labels straight from CoreAudio and turns them into a preset:

./standin clone                   # list connected devices, numbered
./standin clone 2                 # inspect one by number...
./standin clone "Scarlett 4i4"   # ...or by name, and offer to save it as a preset

Or build fully manually, for any device:

./standin build \
    --name "Focusrite Placeholder" \
    --channels 18 \
    --bundle-id com.you.focusriteplaceholder \
    [--input-channels 4] [--output-channels 2] \
    [--input-channel-names "Analog 1,Analog 2,..."] \
    [--output-channel-names "Analog 1,Analog 2,..."]

standin build never runs sudo. It builds the driver and prints the install commands. standin activate/standin deactivate are the only commands here that touch sudo, and both print the exact commands and confirm before doing so.

Usage

standin is the single entry point: one stdlib-only Python script, six subcommands.

Subcommand What it does
standin list [-v] List known presets from presets.json
standin clone [device] Read a connected device's real config via CoreAudio into a preset
standin status Show which presets are currently installed
standin build Build one driver from a preset or manual flags (no install)
standin activate <key> Build + install a preset (sudo, confirms first)
standin deactivate <key> Uninstall a preset (sudo, confirms first)

Full guide: GUIDE.md.

Presets

presets.json is a small catalog of example devices, currently the Focusrite Scarlett 4th Gen lineup (solo, 2i2, 4i4, 16i16, 18i16). These aren't meant to be exact, just close enough to the real hardware to be handy stand-ins or a quick starting point. Each entry looks like:

"solo": {
  "device_name": "Fakecusrite Solo",
  "bundle_id": "com.standin.fakecusritesolo",
  "input_channels": 4,
  "output_channels": 2,
  "input_channel_names": "Instrument/Line Input,Microphone Input,Loopback 1,Loopback 2",
  "output_channel_names": "Output Left (Headphones Left),Output Right (Headphones Right)"
}

notes and sample_rates are optional. standin clone adds new entries from live hardware automatically.

Got hardware that isn't here? PRs adding presets are welcome. standin clone <device> gives you most of the entry already.

Patches

Both patches are fully independent of each other and apply to vanilla BlackHole. They're applied fresh to a cached checkout (blackhole-src-cache/, gitignored) on every build.

You can also find these changes in my BlackHole fork.

License

standin itself (the CLI, docs, presets.json) is MIT-licensed. It builds against BlackHole, which is GPLv3: a .driver binary built by standin build is a derivative of BlackHole and is GPLv3 if you distribute it. See LICENSE for details.

About

Placeholder audio drivers that stand in for disconnected interfaces in CoreAudio aggregate devices, keeping DAW routing valid across the swap.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages