Add custom audio effect processing to apps like Logic Pro X and GarageBand by creating Audio Unit (AU) plug-ins.
- iOS 13.0+
- macOS 10.15+
- Xcode 11.1+
This sample app shows you how to create a custom audio effect plug-in using the latest Audio Unit standard (AUv3). The AUv3 standard builds on the App Extensions model, which means you deliver your plug-in as an extension that’s contained in an app distributed through the App Store or your own store.
The sample Audio Unit is a low-pass filter that allows frequencies at or below the cutoff frequency to pass through to the output. It attenuates frequencies above this point. It also lets you change the filter’s resonance, which boosts or attenuates a narrow band of frequencies around the cutoff point. You set these values by moving the draggable point around the plug-in’s user interface as shown in the figure below.
The project has targets for both iOS and macOS. Each platform’s main app target has two supporting targets:
AUv3Filter, which contains the plug-in packaged as an Audio Unit extension, and
AUv3Filter, which bundles the plug-in’s code and resources.
Create a Custom Audio Effect Plug-In
The extension itself contains two primary pieces: an Audio Unit proper and a factory object that creates it.
The sample app’s Audio Unit is
AUv3Filter. This is a Swift class that subclasses
AUAudio and defines the plug-in’s interface, including key features like its parameters, presets, and I/O busses. A class called
Filter provides the plug-in’s digital signal processing (DSP) logic, and is written in C++ to ensure real-time safety. Because Swift can’t talk directly to C++, the sample project also includes an Objective-C++ adapter class called
Filter to act as an intermediary.
AUv3Filter is the Audio Unit’s main view controller. It adopts the
AUAudio protocol and is responsible for creating new instances of your plug-in. You implement the protocol’s
create factory method to return a new instance of
AUv3Filter when a host app requests it.
Add Custom Parameters to Your Audio Unit
In most Audio Units, you’ll provide one or more parameters to configure the audio processing. Your Audio Unit arranges its parameters into a tree structure, provided by an instance of
AUParameter. This object represents the root node of the plug-in’s tree of parameters and parameter groupings.
AUv3Filter has parameters to control the filter’s cutoff frequency and resonance. You create its parameters using a factory method on
The cutoff parameter defines a frequency range between 12Hz and 20kHz, and the resonance parameter defines a decibel range between -20dB and 20dB. Each parameter is readable and writeable, and also supports ramping, which means you can modify its value over time.
You arrange the parameters into a tree by creating an
AUParameter instance and setting them as the tree’s children.
Next, you bind handlers to the parameter tree’s readable and writeable values by installing closures for its
implementor properties. These closures delegate to the filter adapter instance, which in turn communicates with the underlying DSP logic.
Connect the Parameters to Your User Interface
The sample app’s iOS and macOS targets each provide a platform-specific user interface. You use a shared view controller called
AUv3Filter to coordinate the communication between the user interface and the Audio Unit. Connect your user interface to the Audio Unit’s parameters in the
As shown above, in the
connect method, you find the Audio Unit’s parameter tree and retrieve its cutoff and resonance parameters. You also add an observer closure to update the user interface as the plug-in’s parameter values change.
Add Factory Presets
Most audio plug-ins provide a collection of preset values known as factory presets. A factory preset is a preconfigured arrangement of the plug-in’s parameter values that provide a useful starting point for further customization. A host app presents these presets in its user interface so the user can select them.
The following code example shows how to define the factory presets and their associated values.
Support User Presets
Factory presets provide a useful starting point for further user customization, but users also want the ability save their changes and create their own custom presets.
AUAudio provides built-in support for user presets. To enable this support in your Audio Unit, override the
supports property to return
Opting in to support for user presets automatically enables your Audio Unit to load, save, and delete user presets. The default implementation of the
delete API reads from and writes to an internal store, but you’re free to override this property and methods if you want to directly manage the persistence behavior. For example, you can override the default behavior to persist user presets to an iCloud container or some other remote location.
Select Factory and User Presets
A host app selects a factory or user preset by setting the plug-in’s
current property. You override this property and take the appropriate action depending on the preset type selected. If the user selected a factory preset (a preset
number greater than
0), look up its associated values and set the parameter values accordingly. If the user selected a user preset (a preset
number less than
0), restore the preset’s parameter state by calling the
preset method and setting the returned data as the
Package Your Plug-In to Run In-Process
Like all App Extensions, AUv3 plug-ins run out-of-process by default, which means the extension runs in a separate process from the host app, and all communication between the two occurs over interprocess communication (IPC). This model provides increased security and stability for the host app. For example, if an AUv3 plug-in crashes, the host app won’t crash. However, the IPC communication adds a small amount of overhead to each render cycle, which may be unacceptable depending on the needs of a given application. In macOS only, you can package your plug-in to run in-process, which eliminates the IPC communication as your Audio Unit runs as part of the host’s process.
Running a plug-in in-process requires an agreement between the host and the Audio Unit. The host requests in-process instantiation by passing the
load option during the plug-in’s creation, and you need to package your Audio Unit as described and shown below.
Your extension’s main binary cannot be dynamically loaded into another app, which means all executable code needs to reside in a separate framework bundle. However, the extension target still needs to contain at least one source file for the extension binary to be created, properly loaded, and linked with the framework bundle. To ensure the extension is created, add some unused placeholder code in your extension target, like that found in
The macOS sample packages all of the Audio Unit’s code into the
AUv3Filter target. You indicate that the extension’s code exists in a separate bundle by adding an
Audio extension attribute to the target’s Info.plist file.
If you’re using a xib or Storyboard for your user interface, override your view controller’s
init(nib initializer and pass the framework bundle to the superclass initializer. This ensures your user interface properly loads when the system requests your Audio Unit extension.
Finally, in the extension’s Info.plist file, set the Audio Unit’s factory object,
AUv3Filter, as the extension’s principal class.