Unlike VSTs or other audio plugin formats, as a Mac user, it is possible obtain code for AudioUnits without jumping through hoops, which is why I will focus on developing AudioUnits with JUCE. Developing for VSTs should not be much different except for the need to download the VST SDK from Steinberg.
Step 0. Download Xcode with OSX SDK
Download Xcode from the Apple App Store. This may take quite a while.Step 1. Download JUCE from Github
Download JUCE here.Step 2. Download CoreAudio Utility Classes
JUCE uses a few utility classes that do not come with the CoreAudio framework in the OSX SDK. These classes can be found here. Click on the "Download Sample Code" button.Once downloaded and unzipped, copy the
CoreAudio
folder to /Applications/Xcode.app/Contents/Developer/Extras
. You will need to create the Extra
folder. This is the default directory that JUCE searches for the CoreAudio Utility classes.I have yet to figure out how to make JUCE search for a more reasonable folder. Note: yes we are adding files to the Xcode app bundle, which is not a good idea since anytime you upgrade Xcode you will have to copy the files again. Hopefully this will be addressed in future JUCE releases.
Step 3. Compile and Run Introjucer
The quick and easy way to setup a JUCE project is by Introjucer. You can find the source code for Introjucer underextras
in the JUCE source code. Compile Introjucer by choosing the platform of interest under Builds
. Since we are focusing on OSX, lets open Builds/MacOSX/The Introjucer.xcodeproj
. This will open Xcode. Compile and run the project. It might be a good idea to archive the project as an app bundle, if you are going to develop many audio plugins with JUCE.Step 4. Setup an Xcode Project with Introjucer
Run Introjucer
![]() |
Figure 1. Introjucer with no Jucer project. |
From the menu choose "File > New Project" or press
cmd+N
.Create Project
![]() |
Figure 2. Creating a Jucer project. |
Name your project. I'm calling mine STTR. For project type, choose "Audio Plug-In". And choose the folder you want the files to be in. Add the folder name below the folder tree to create a new folder. (If not it will create the files in the current folder.) When you press "Create...", Introjucer will ask you for the "JUCE modules" folder. You can find the folder aptly named
modules
in the folder downloaded from Step 1.Setup Project
![]() |
Figure 3. Setting up a Jucer project. |
Introjucer has now created an introjucer project. (In the project folder you will find a
.jucer
file along with source code folders.) We now need to setup the project. For our case, we need to set the following,- the company name
- the output plugin formats
Step 5. Modify the Xcode Project for Live
Though Introjucer does most of the setup needed, there are a few steps we have to go through to make the project compile.Choose Architecture, Base SDK
![]() |
Figure 4. Xcode project settings. |
As of the time of writing Ableton recommends installing the 32-bit version of Live and the 32-bit version will not load 64-bit AudioUnits. Xcode 5 on the other hand defaults to 64-bit architectures, so we need to fix this. Open the build settings by clicking on the blueprint icons (See Figure 4). For "Architectures" choose, "32-bit Intel (i386)". For "Base SDK", choose "Latest OS X".
Fix line 263 in AUCarbonViewBase
AUCarbonViewBase
can be found in "Juce Library Code > Juce AU Wrapper". Use the Project Navigator on the left (the sidebar) to find it. You need to add the
static_cast
like below. Xcode will offer to fix it.
HISize originalSize = { static_cast(mBottomRight.h), static_cast(mBottomRight.v) };
This code is actually one of the files from Step 2, so you will only need to fix this every time you upgrade Xcode.
Fix line 1415 in juce_OpenGLGraphicsContext.cpp
If you try to build now (cmd+B
), you will get an error in juce_OpenGLGraphicsContext.cpp
. The file is in "Juce Modules > juce_opengl > opengl" .Removing fontHeight
should fix the problem.
const ScopedPointer et (font.getTypeface()->getEdgeTableForGlyph (glyphNumber, t, fontHeight));
(Caveat: I am not aware of the consequences of this workaround. I have not experienced any problems.)
Step 6. Write Code
For a quick example, let's create a ring modulator (which simply means multiplying the input signal with a sine wave). Before we start coding, let's look at the files we will be working in. JUCE automatically creates four C++ files when creating the project:PluginProcessor.h/.cpp
and PluginEditor.h/.cpp
. The former contains the signal processing code, while the latter is user interface code. The actual classes are named after your project name. For my project STTR
the class in PluginProcessor
is SttrAudioProcessor
, a subclass of AudiProcessor
.The function to access the audio buffer is
void SttrAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
. It uses one audio buffer for input and output, which means you read the buffer data from buffer
for the input signal, then write the output sample to the same object.The function is populated with some useful starter code. Replace it with the code below.
void SttrAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
static double phase = 0;
// This is the place where you'd normally do the guts of your plugin's
// audio processing...
for (int channel = 0; channel < getNumInputChannels(); ++channel)
{
float* channelData = buffer.getSampleData (channel);
// ..do something to the data...
for (int n = 0; n < buffer.getNumSamples(); n++) {
if (channel == 0) { // increment phase once per sample
phase += M_PI*2*880/getSampleRate(); // modulate by 880 Hz
if (phase > 2*M_PI)
phase -= 2*M_PI;
}
channelData[n] *= sin(phase);
}
}
// In case we have more outputs than inputs, we'll clear any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
{
buffer.clear (i, 0, buffer.getNumSamples());
}
}
Step 7. Compile the project
Compile the project by pressingcmd + B
.
You should find the compiled .component
file in [YourProject Folder]/Builds/MacOSX/build/Debug
.
Step 8. Install the .component
plugin
Now we have an AudioUnit plugin. While some DAWs allow the user to put the plugin in your own custom folder, Ableton Live expects the AudioUnit plugin to be in a predefined location. In OSX Mavericks (10.9.2), that location is /Library/Audio/Plug-Ins/Components
. Copy the .component
file into /Library/Audio/Plug-Ins/Components
. Since it's a system folder you will need administrator level access (i.e. be able to run sudo
). Now you should be able to see your plugin in Ableton Live under "Plug-ins".
What next?
For a complete synthesizer example, you can find one in "extras/audio plugin demo" in the JUCE repository. It is worth looking at the JUCE API Documentation. There are a lot of classes that implement commonly used functions, so I suggest taking a look before implementing your own.While preparing my own project and writing this post, I found this post helpful. http://feature-space.com/en/post161.html
No comments:
Post a Comment