### Install BlackHole via Installer Package Source: https://context7.com/existentialaudio/blackhole/llms.txt Install BlackHole by downloading and running the signed installer package. Close all audio applications before installation and restart CoreAudio afterwards. ```bash # Close all audio applications first, then open the .pkg file # After installation, restart CoreAudio (or reboot the system) sudo killall -9 coreaudiod ``` -------------------------------- ### Install BlackHole via Homebrew Source: https://context7.com/existentialaudio/blackhole/llms.txt Install prebuilt channel variants of BlackHole using Homebrew. Ensure you have Homebrew installed. ```bash # Install the 2-channel variant brew install blackhole-2ch ``` ```bash # Install the 16-channel variant brew install blackhole-16ch ``` ```bash # Install the 64-channel variant brew install blackhole-64ch ``` -------------------------------- ### Automated Installer Creation Script Source: https://context7.com/existentialaudio/blackhole/llms.txt The `create_installer.sh` script builds, signs, and notarizes all standard BlackHole channel variants, producing distributable `.pkg` installers. Requires a valid Apple Developer Team ID and a configured `notarytool` keychain profile. Run from the repo root. ```bash # Prerequisites: # 1. Set your Developer Team ID in create_installer.sh: # devTeamID="YOUR_TEAM_ID" # 2. Set your notarytool keychain profile name: # notarizeProfile="your-profile-name" # 3. Run from repo root: cd /path/to/BlackHole ./Installer/create_installer.sh # Output: Installer/BlackHole2ch-0.6.1.pkg # Installer/BlackHole16ch-0.6.1.pkg # Installer/BlackHole64ch-0.6.1.pkg # Installer/BlackHole128ch-0.6.1.pkg # Installer/BlackHole256ch-0.6.1.pkg # To skip notarization (development/testing builds): # Set notarize=false in create_installer.sh ``` -------------------------------- ### Install BlackHole via Homebrew Source: https://github.com/existentialaudio/blackhole/blob/master/README.md Use Homebrew to install different channel versions of BlackHole. Ensure you have Homebrew installed and choose the appropriate command for your needs. ```bash brew install blackhole-2ch ``` ```bash brew install blackhole-16ch ``` ```bash brew install blackhole-64ch ``` -------------------------------- ### Record System Audio with BlackHole Source: https://context7.com/existentialaudio/blackhole/llms.txt Steps to configure Audio MIDI Setup and a DAW to record system audio using BlackHole. ```bash # Example: Record system audio into a DAW # 1. In Audio MIDI Setup, create a Multi-Output Device: # - Click "+" → "Create Multi-Output Device" # - Check both "Built-in Output" and "BlackHole Xch" # - Set Built-in Output as the master (clock source) # 2. Set System Preferences → Sound → Output to the Multi-Output Device # 3. In GarageBand / Logic / Reaper: # - Set input device to "BlackHole Xch" # - Create a track recording from channel 1-2 (or 1-N for multi-channel) # 4. Press Record — all system audio is now captured # Example: Route audio between two DAWs # Sending DAW: Output device → BlackHole Xch, output to channels 1-2 # Receiving DAW: Input device → BlackHole Xch, input from channels 1-2 ``` -------------------------------- ### Change Directory to HAL Source: https://github.com/existentialaudio/blackhole/wiki/Uninstallation Navigate to the directory where audio drivers are installed. This is a prerequisite for removing the BlackHole driver. ```bash cd /Library/Audio/Plug-Ins/HAL ``` -------------------------------- ### Adjust BlackHole Clock Speed via Audio MIDI Setup Source: https://context7.com/existentialaudio/blackhole/llms.txt BlackHole offers two clock source modes: `Internal Fixed` (default) and `Internal Adjustable`. The adjustable mode allows for ±1% pitch shift via the Balance slider, useful for locking BlackHole's clock to an external device without aggregate devices. ```text # Audio chain that benefits from clock adjustment: # Player app → BlackHole → DSP app → Audio out device # # Steps (Audio MIDI Setup GUI): # 1. Open Audio MIDI Setup (Spotlight → "Audio Midi Setup") # 2. Select the BlackHole device in the Audio Devices window # 3. Click the "Clock Source" dropdown ``` -------------------------------- ### Remove BlackHole Driver Files Source: https://github.com/existentialaudio/blackhole/wiki/Uninstallation Use the `sudo rm -rf` command to forcefully remove the BlackHole driver files. Ensure you use the correct command for the version of BlackHole installed (e.g., 2ch, 16ch, 64ch, or older versions). This requires administrator privileges. ```bash sudo rm -rf BlackHole2ch.driver ``` ```bash sudo rm -rf BlackHole16ch.driver ``` ```bash sudo rm -rf BlackHole64ch.driver ``` ```bash sudo rm -rf BlackHole.driver ``` -------------------------------- ### Build BlackHole Driver from Source Source: https://context7.com/existentialaudio/blackhole/llms.txt Clone the repository, build the driver bundle using Xcode from the command line, copy it to the HAL plug-ins folder, and restart CoreAudio. ```bash # Clone the repo git clone https://github.com/ExistentialAudio/BlackHole.git cd BlackHole # Build with Xcode (GUI: open BlackHole.xcodeproj, press ⌘B) # Or from command line: xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build # Install the built driver cp -R build/BlackHole.driver /Library/Audio/Plug-Ins/HAL/ # Restart CoreAudio to load the new driver sudo killall -9 coreaudiod ``` -------------------------------- ### Configure Mirror Device for Input/Output Split Source: https://context7.com/existentialaudio/blackhole/llms.txt Configure the hidden mirror device to expose separate input-only or output-only devices. Hidden devices remain accessible programmatically via kAudioHardwarePropertyTranslateUIDToDevice. ```bash # Expose two separate devices: one output-only, one input-only # The audio written to the output device is readable from the input device xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kDevice_IsHidden=false kDevice_HasInput=false kDevice_HasOutput=true kDevice2_IsHidden=false kDevice2_HasInput=true kDevice2_HasOutput=false' ``` ```objective-c # Programmatic access to hidden mirror device (Objective-C / CoreAudio): # AudioObjectPropertyAddress addr = { # kAudioHardwarePropertyTranslateUIDToDevice, # kAudioObjectPropertyScopeGlobal, # kAudioObjectPropertyElementMain # }; # CFStringRef uid = CFSTR("BlackHole2ch_2_UID"); # AudioObjectID deviceID = kAudioObjectUnknown; # UInt32 dataSize = sizeof(deviceID); # AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, # sizeof(uid), &uid, &dataSize, &deviceID); ``` -------------------------------- ### Restrict Sample Rates with Preprocessor Constant Source: https://context7.com/existentialaudio/blackhole/llms.txt Build the BlackHole driver to support only specific sample rates by overriding the default set using the `kSampleRates` preprocessor definition. Use comma-separated values. ```bash # Build supporting only 44.1 kHz and 48 kHz xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kSampleRates=44100,48000' ``` ```c #define kSampleRates 8000, 16000, 24000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000 ``` -------------------------------- ### Route Audio from One App to Another Source: https://context7.com/existentialaudio/blackhole/llms.txt This section explains how to route audio from one application to another using BlackHole. It involves setting the output of the sending application to BlackHole and the input of the receiving application to BlackHole. ```APIDOC ## Routing Audio Between Applications ### Route Audio from One App to Another Set the sending application's audio output to "BlackHole" and the receiving application's input to "BlackHole". Both see the same shared ring buffer. **Example: Record system audio into a DAW** 1. In Audio MIDI Setup, create a Multi-Output Device: - Click "+" → "Create Multi-Output Device" - Check both "Built-in Output" and "BlackHole Xch" - Set Built-in Output as the master (clock source) 2. Set System Preferences → Sound → Output to the Multi-Output Device 3. In GarageBand / Logic / Reaper: - Set input device to "BlackHole Xch" - Create a track recording from channel 1-2 (or 1-N for multi-channel) 4. Press Record — all system audio is now captured **Example: Route audio between two DAWs** Sending DAW: Output device → BlackHole Xch, output to channels 1-2 Receiving DAW: Input device → BlackHole Xch, input from channels 1-2 ``` -------------------------------- ### Customize Driver Latency with Preprocessor Constant Source: https://context7.com/existentialaudio/blackhole/llms.txt Build the BlackHole driver with additional latency by setting `kLatency_Frame_Size`. The default is 0 for zero-latency operation. Latency in seconds is calculated as `kLatency_Frame_Size / sample_rate`. ```bash # Build with 1024-frame latency (~21.3ms at 48kHz) xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kLatency_Frame_Size=1024' ``` ```c #define kLatency_Frame_Size 1024 # At 48000 Hz: 1024 / 48000 = 0.0213 seconds = 21.3 ms ``` -------------------------------- ### Manual Uninstall of BlackHole Source: https://context7.com/existentialaudio/blackhole/llms.txt Manually remove the BlackHole driver bundle and restart CoreAudio. Replace 'X' with the channel count (2, 16, or 64). ```bash # Remove the driver bundle (replace X with 2, 16, or 64) rm -R /Library/Audio/Plug-Ins/HAL/BlackHoleXch.driver # Restart CoreAudio sudo killall -9 coreaudiod ``` -------------------------------- ### Define Number of Channels in BlackHole.c Source: https://github.com/existentialaudio/blackhole/wiki/Change-the-Number-of-Channels Modify the kNumber_Of_Channels macro in BlackHole.c to set the desired number of audio channels. Be aware of potential DAW limitations with channel counts over 256. ```c #define kNumber_Of_Channels 16 ``` -------------------------------- ### Build Multiple BlackHole Drivers with Unique UIDs Source: https://context7.com/existentialaudio/blackhole/llms.txt Build multiple BlackHole variants with distinct UIDs for simultaneous loading. The channel count is embedded in UIDs when kHas_Driver_Name_Format is true. Ensure to copy drivers to the HAL directory and restart CoreAudio. ```bash # Build BlackHole2ch (UID: "BlackHole2ch_UID") xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build2ch \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kNumber_Of_Channels=2' ``` ```bash # Build BlackHole16ch (UID: "BlackHole16ch_UID") xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build16ch \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kNumber_Of_Channels=16' ``` ```bash # Copy both drivers to HAL directory cp -R build2ch/BlackHole.driver /Library/Audio/Plug-Ins/HAL/BlackHole2ch.driver cp -R build16ch/BlackHole.driver /Library/Audio/Plug-Ins/HAL/BlackHole16ch.driver # Restart CoreAudio to load both sudo killall -9 coreaudiod ``` -------------------------------- ### Customize Channel Count with Preprocessor Constant Source: https://context7.com/existentialaudio/blackhole/llms.txt Build a specific channel variant of the BlackHole driver by setting the `kNumber_Of_Channels` preprocessor definition during the Xcode build. DAWs may not support channel counts above 256. ```bash # Build a 16-channel variant xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ CONFIGURATION_BUILD_DIR=build \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kNumber_Of_Channels=16' ``` ```c #define kNumber_Of_Channels 16 ``` -------------------------------- ### Customize BlackHole Build with Pre-compiler Constants Source: https://github.com/existentialaudio/blackhole/blob/master/README.md Use these pre-compiler constants to customize a build of BlackHole. Specify them at build time with xcodebuild using GCC_PREPROCESSOR_DEFINITIONS. ```bash kDriver_Name kPlugIn_BundleID kPlugIn_Icon kDevice_Name kDevice_IsHidden kDevice_HasInput kDevice_HasOutput kDevice2_Name kDevice2_IsHidden kDevice2_HasInput kDevice2_HasOutput kLatency_Frame_Size kNumber_Of_Channels kSampleRates ``` ```bash xcodebuild \ -project BlackHole.xcodeproj \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kSomeConstant=value' ``` -------------------------------- ### CoreAudio Driver I/O Operations Source: https://context7.com/existentialaudio/blackhole/llms.txt Simplified C code illustrating the CoreAudio driver's I/O operations for writing application audio to the ring buffer and reading from it, including volume and mute application. ```c // Simplified view of what the HAL calls each I/O cycle: // --- APPLICATION → BLACKHOLE (Write path) --- // inOperationID == kAudioServerPlugInIOOperationWriteMix // ioMainBuffer contains the app's mixed output audio (Float32 LPCM) // The driver copies it into gRingBuffer at the correct offset: UInt32 ringStart = mSampleTime % kRing_Buffer_Frame_Size; // Split copy handles ring buffer wrap-around: memcpy(gRingBuffer + ringStart * kNumber_Of_Channels, ioMainBuffer, firstPartFrameSize * kNumber_Of_Channels * sizeof(Float32)); memcpy(gRingBuffer, (Float32*)ioMainBuffer + firstPartFrameSize * kNumber_Of_Channels, secondPartFrameSize * kNumber_Of_Channels * sizeof(Float32)); // --- BLACKHOLE → APPLICATION (Read path) --- // inOperationID == kAudioServerPlugInIOOperationReadInput // The driver copies from gRingBuffer into ioMainBuffer, // then applies the master volume scalar: memcpy(ioMainBuffer, gRingBuffer + ringStart * kNumber_Of_Channels, firstPartFrameSize * kNumber_Of_Channels * sizeof(Float32)); // Volume is applied via Accelerate vDSP: vDSP_vsmul(ioMainBuffer, 1, &gVolume_Master_Value, ioMainBuffer, 1, inIOBufferFrameSize * kNumber_Of_Channels); // Mute: replaces output with silence if (gMute_Master_Value) { vDSP_vclr(ioMainBuffer, 1, inIOBufferFrameSize * kNumber_Of_Channels); } ``` -------------------------------- ### Restart Core Audio Subsystem Source: https://github.com/existentialaudio/blackhole/wiki/Uninstallation Restart the Core Audio daemon to apply the changes after removing the driver files. This command requires administrator privileges. ```bash sudo killall -9 coreaudiod ``` -------------------------------- ### Configure Device Mirroring in BlackHole Source: https://github.com/existentialaudio/blackhole/blob/master/README.md Customize the default hidden mirrored audio device in BlackHole using pre-compiler constants. This allows for separate input-only and output-only devices. ```text // Original Device kDevice_IsHidden kDevice_HasInput kDevice_HasOutput // Mirrored Device kDevice2_IsHidden kDevice2_HasInput kDevice2_HasOutput ``` ```text // Original Device kDevice_IsHidden=false kDevice_HasInput=true kDevice_HasOutput=false // Mirrored Device kDevice2_IsHidden=false kDevice2_HasInput=false kDevice2_HasOutput=true ``` -------------------------------- ### Define Driver Latency Source: https://github.com/existentialaudio/blackhole/wiki/Adjust-Driver-Latency Modify this macro in BlackHole.c to set the desired driver latency in samples. The default value is 0. ```c #define LATENCY_FRAME_SIZE 0 ``` -------------------------------- ### Rename BlackHole with Pre-compiler Constants Source: https://github.com/existentialaudio/blackhole/blob/master/README.md Customize BlackHole by changing driver name, bundle ID, and icon using pre-compiler constants with xcodebuild. Ensure the bundle ID matches the target bundleID. ```bash driverName="BlackHole" bundleID="audio.existential.BlackHole" icon="BlackHole.icns" xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ PRODUCT_BUNDLE_IDENTIFIER=$bundleID \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kDriver_Name="'$driverName'" kPlugIn_BundleID="'$bundleID'" kPlugIn_Icon="'$icon'"' ``` -------------------------------- ### BlackHole_DoIOOperation — Core Ring Buffer I/O Source: https://context7.com/existentialaudio/blackhole/llms.txt The central function of the driver, `BlackHole_DoIOOperation`, is called by the HAL each I/O cycle. It handles writing application audio to the ring buffer or reading data from the ring buffer into an application's input buffer. ```APIDOC ## CoreAudio Driver Interface Reference ### `BlackHole_DoIOOperation` — Core Ring Buffer I/O The central function of the driver. Called by the HAL each I/O cycle to either write mixed output from an application into the ring buffer (`kAudioServerPlugInIOOperationWriteMix`) or read data from the ring buffer into an application's input buffer (`kAudioServerPlugInIOOperationReadInput`). Uses `vDSP_vsmul` for volume application and `vDSP_vclr` for mute/silence operations. ```c // Simplified view of what the HAL calls each I/O cycle: // --- APPLICATION → BLACKHOLE (Write path) --- // inOperationID == kAudioServerPlugInIOOperationWriteMix // ioMainBuffer contains the app's mixed output audio (Float32 LPCM) // The driver copies it into gRingBuffer at the correct offset: UInt32 ringStart = mSampleTime % kRing_Buffer_Frame_Size; // Split copy handles ring buffer wrap-around: memcpy(gRingBuffer + ringStart * kNumber_Of_Channels, ioMainBuffer, firstPartFrameSize * kNumber_Of_Channels * sizeof(Float32)); memcpy(gRingBuffer, (Float32*)ioMainBuffer + firstPartFrameSize * kNumber_Of_Channels, secondPartFrameSize * kNumber_Of_Channels * sizeof(Float32)); // --- BLACKHOLE → APPLICATION (Read path) --- // inOperationID == kAudioServerPlugInIOOperationReadInput // The driver copies from gRingBuffer into ioMainBuffer, // then applies the master volume scalar: memcpy(ioMainBuffer, gRingBuffer + ringStart * kNumber_Of_Channels, firstPartFrameSize * kNumber_Of_Channels * sizeof(Float32)); // Volume is applied via Accelerate vDSP: vDSP_vsmul(ioMainBuffer, 1, &gVolume_Master_Value, ioMainBuffer, 1, inIOBufferFrameSize * kNumber_Of_Channels); // Mute: replaces output with silence if (gMute_Master_Value) { vDSP_vclr(ioMainBuffer, 1, inIOBufferFrameSize * kNumber_Of_Channels); } ``` ``` -------------------------------- ### Change BlackHole UIDs in BlackHole.c Source: https://github.com/existentialaudio/blackhole/wiki/Running-Multiple-BlackHole-Drivers Modify these preprocessor directives in `BlackHole.c` to assign unique identifiers to each BlackHole instance. This is crucial for distinguishing between multiple running drivers. ```c #define kBox_UID "BlackHole_UID" #define kDevice_UID "BlackHole_UID" #define kDevice_ModelUID "BlackHole_ModelUID" ``` -------------------------------- ### Manually Uninstall BlackHole Driver Source: https://github.com/existentialaudio/blackhole/blob/master/README.md Remove the BlackHole driver files from your system using the terminal. This method requires replacing 'X' with the specific channel count (2, 16, or 64) and restarting the CoreAudio daemon. ```bash rm -R /Library/Audio/Plug-Ins/HAL/BlackHoleXch.driver ``` ```bash sudo killall -9 coreaudiod ``` -------------------------------- ### Rename BlackHole Driver and Bundle ID Source: https://context7.com/existentialaudio/blackhole/llms.txt Use these build flags to rename the BlackHole driver and set a custom bundle identifier. The bundle identifier must match the Xcode target's PRODUCT_BUNDLE_IDENTIFIER. This is useful for embedding BlackHole in commercial products under a custom name. ```bash driverName="MyAudioDriver" bundleID="com.mycompany.MyAudioDriver" icon="MyAudioDriver.icns" xcodebuild \ -project BlackHole.xcodeproj \ -configuration Release \ PRODUCT_BUNDLE_IDENTIFIER=$bundleID \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kDriver_Name="'$driverName'" kPlugIn_BundleID="'$bundleID'" kPlugIn_Icon="'$icon"' ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.