JUCE is a multi-platform C++ framework that amongst many things
can be used to develop audio plugins, including VST, AudioUnits, RTAS (Digidesign) and AAX.
My goto DAW being Ableton Live, I will focus on how to get started with JUCE for AU plugins to use with Ableton Live. In this post I will go over how to setup a project with JUCE and get it compiled with Xcode.
For this post, I am using Xcode 5.1 on OSX 10.9.2.
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 under
extras
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. |
You should see Introjucer with no project like Figure 1.
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
For Ableton Live users, the company name matters because Live organizes AudioUnits by the company name. Let's uncheck "Build VST" for now. (It is selected by default.) That will be enough for this post. However, I recommend scrolling down the list and skimming over the other options especially those starting with "Plugin". We are now ready to open Xcode. Click on "Save Project and Open in Xcode...".
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 pressing
cmd + 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