A Tremolo AU plugin with Max
Last week I came across a post on the Cycling ’74 Wiki about exporting gen~ code into an AU plugin. It looked too simple a process to be true, so I began investigating. After a few hours of work (and some help from the C74 forums because I stumbled across a bug) I managed to get a simple distortion plugin working. The whole process is actually quite simple, after you spend a few agonising hours figuring the system out – like with most things. I must mention that the code export feature in gen~ is still in beta, so things are expected to break. I look forward to a stable release, there’s so much that can be done with such a great sounding DSP library!
What is gen~?
Gen~ is an environment within Max that was introduced in version 6.0. It allows for patching of low level operations that are instantly compiled into great sounding objects without the limitations of MSP. I’ve been using it for about a year now and it sounds absolutely amazing. Version 6.1 of Max makes it possible to export gen~ objects as C++ code, making it portable. Cycling ’74 plans to add documentation for VST plugins and the iOS operating system in the near future.
For this tutorial we are going to attempt to create a tremolo AU plugin (sorry Windows users!). We’ll first start with trying to understand how a tremolo plugin works and implement a basic version within Max (I’ll translate object names for the Pd users out there) and then re-create it within gen~ so that we can export the code that will help create our AU plugin.
DISCLAIMER/WARNING/MESSAGE IN CAPS: gen~ is in beta and there are chances that the code you compile might not work. I’ve got the AU plugin working fine on my computer (OSX 10.7) but haven’t been able to get it to work properly in 10.8. I am also not a coder, I know just enough to hack (or break) my way around things. If you think you’ve come across a bug, do let the kind folks at Cycling ’74 know.
Let us begin!
How does a tremolo effect work?
If you move a fader up and down manually at a fixed rate you would achieve a tremolo effect. Although, its tough to get our hands to move a fader at a fixed rate! If we had to replace the hand with a modulating signal instead that moved the fader, we could create a decent sounding tremolo effect. You can try it yourself. Open your favourite DAW and draw in a repeating pattern on the volume automation lane:
How can we implement this idea into Max (or Pd)? Lets look at some signal processing basics first.
Signals and the -1 to 1 range:
Digital signals are stored as samples that are then read at a fixed rate (the sample rate) to reproduce sound. This is a hugely over simplified explanation of what is quite a complex process. The reproduced ‘sound’ is nothing but a voltage in the analogue domain that is then amplified by an amplifier to drive a speaker. Every device has limitations. A speaker cone moves both forwards and backwards (positively and negatively) and has a physical limitation, beyond which it will not move. Similarly, both digital and analogue mediums have limits. If you try and go beyond the limits you end up with distortion.
If we think of sound as a signal, it is nothing but a stream of numbers that change over time. The limitations of the medium and the system impose boundaries. In digital systems this range is usually between -1 to 1. If a signal crosses the boundaries of -1 and 1 it will distort (it will not distort within the system, but will distort on output). Here’s a sine wave occupying the full range (-1 and 1), on a digital meter it will peak at 0dbFS
If I want to scale down a number by half I could divide it by 2 or multiply it by 0.5. If I have a number ’10′:
10/2 = 5 or 10 * 0.5 = 5
Or if I have have a number ’1′:
1/2 = 0.5 or 1 * 0.5 = 0.5
If I have signal ranging from -1 to 1 and multiply it by 0.5, I decrease it by half (or drop it by 6dB). Multiplying a signal by a factor allows us to scale it or change its amplitude.
If we could change the amplitude or scale this signal at a constant rate with an oscillating signal, we would end up with a tremolo effect. Simple huh? What generates an oscillating signal? An oscillator of course! The default oscillator in Max (cycle~) and Pd (osc~) spits out an oscillating sine wave in the range of -1 and 1. We could directly patch the oscillator to a [*~] object to scale a signal, but since the oscillating signal ranges from -1 to 1, we will end multiplying the amplitude by a negative number and switching its polarity. Lets scale the oscillating signal to a more useable range of 0 to 1.
Quite simple. We can now add more features: make it stereo, add different waveform types, add depth control, etc. Lets first try and implement this basic version in gen~ before we turn into feature creeps.
The guts of gen~
Using the gen~ environment is as simple as creating a new object and typing in ‘gen~’. If you have worked with abstractions and sub-patches this will look familiar. Double clicking the gen~ object opens up a new window which gives you access to the insides of the gen~ object and the gen~ environment.
The default setup includes two inputs being summed into a single output. A point worth mentioning here: everything in gen~ is in the signal domain, there is no messaging system like Max.
Let’s create the first version of our tremolo effect:
First, we need an oscillator. Gen~ by default has a sine wavetable lookup oscillator like MSP, called ‘cycle’ (surprise surprise!). We then need to scale our modulating signal into a useable range (0 to 1) and use it to modulate the amplitude of our input signal.
The patch is very similar to what we had earlier, except we now have an input for our dry signal and an output for the ‘effected’ signal. I have made an additional output to analyse the modulation signal and also included an additional ‘param’ object. The ‘param’ object allows us to use named parameters from the parent patch to control objects within the gen~ environment. The image below should explain this:
This is the parent patch which includes the sound file player, the scope~ object to analyse our modulation signal and the gen~ object that includes the tremolo code. Additionally, we have a number box feeding into a message box named [Frequency $1]. ‘Frequency’ is the named parameter we created in gen~ that is connected to the inlet of the cycle object (to control it’s frequency). The $1 is used in Max and Pd to create a variable value, where the $1 is replaced by any value that is sent through the message object. So, if we send the number ’5′ to the message object in our case, it would spit out ‘Frequency 5′. Or, if we sent it the number ’10′, it would spit out ‘Frequency 10′. This message is sent to the gen~ object which then assigns the number to the cycle object because we have instructed it to do so using the ‘param’ object. Makes sense?
So this all works fine (if you have managed to stay on so far). Lets make this tremolo effect more interesting. I’d like to add dry/wet controls, have two different kinds of waveforms (sine and square) and be able to morph between them, make the effect work with stereo signals and be able to create a phase difference (offset) between the left and right modulation signals.
Lets get cracking!
First, we’re going to get rid of the ‘cycle’ object and instead use a phasor. A phasor is an object that generates steady ramps from 0 to 1 at a fixed frequency (a saw-tooth waveform). We are using the phasor so that we can create both a sine and square wave from the same time reference.
Output = sin(2*pi*Input)
In gen~ we can implement this using the ‘expr’ object and then scale the signal so that it falls within the 0 to 1 range:
Now, lets create a square wave from this same phasor object. A square wave is nothing but a signal that is at a constant 1 for the first half of a cycle and switches to a constant -1 for the second half of the cycle. But since we want to control amplitude, we want this range to be between 0 and 1. We can use the ‘>’ object to achieve this. The ‘>’ object is a comparison object that spits out a 1 if it’s input is greater than a specified value or it spits out a 0 if the input is less than the specified value. If we create a ‘>’ object with an argument of 0.5, we can create a square wave from a phasor (it spits out a 0 when the signal from the phasor is less than 0.5 and 1 when the signal is greater than 0.5).
If we crossfade between both signals (sine and square), we can create waveforms that are somewhat in-between both of these shapes. Thankfully there’s an object in gen~ that helps us do this. The ‘mix’ object has three inlets: the first two for the two signals that need to be crossfaded and the third for the control signal. If the control signal is at 0, the ‘mix’ object outputs only the signal it receives on the first inlet. If the control signal is at 1, it outputs only the signal it receives on the second inlet. As you rightly guessed, any value between 0 and 1 is a proportionate mix of both signals. We implement this in gen~ and create a parameter called ‘Shape’ that will allow us to crossfade between both waveform types.
Two more steps left. We are almost there! Now that we have a decent tremolo effect working, lets add another paramater that will allow us to offset the left the and right modulation signals so that we can create cool stereo effects. We can achieve this by changing the phase of one of the modulation signals (changing it’s starting point in time). To do this, we will add a value to the output of the phasor and then use a ‘wrap’ object to bring it back into the 0 and 1 range. The wrap objects works like a modulo object – if you are familiar with it. If we give the ‘wrap’ object the arguments ’0 1′, it will make sure that the signal always stays within that range. So, if we send it a 1.1 it will spit out 0.1, or if we sent it 1.7 it will spit out 0.7, or if we send it 2.3 it will spit out – you guessed it – 0.3. Let’s also create a parameter called ‘Phase’ to control the phase difference between both modulation signals and limit its range to 0 and 0.5.
It sounds quite decent already. The only issue I find with it is that when the ‘Shape’ parameter is turned all the way up to 1 (the square wave), it sounds quite clicky. We can fix this by using a low pass filter to smoothen the modulation signal. Unlike MSP, there is no lowpass object in gen~. We need to create one from scratch. Worry not! Thankfully Cycling ’74 have provided an amazing library of gen~ examples (Applications > Max 6. 1 > examples > gen) that include different filters. Lets copy the code for the lowpass filter and set it up so with a ‘Smooth’ parameter, so that when the ‘Smooth’ value is at 0 the filter is at 100Hz and when the ‘Smooth’ value is at 1 the filter is it 10Hz. Lets use the ‘scale’ object for this to save us some of the maths. Also make sure you assign different arguments to each of the history objects (y0 and z0 in this case).
And we are done!
By sending the gen~ object an ‘exportcode’ message, we can get it to export out the object as C++ code. Now lets convert it to
an AU plugin. Crack your knuckles!
I am breaking this section down into a list of steps, so that it is easier to follow (much of below is repeated from the post on the Cycling ’74 Wiki):
- If you haven’t installed Xcode and downloaded Audio Tools for Xcode, now is the time (check the pre-requisites section at the start of this post to make sure you have done everything right)
- Download “AUGenExport-v01.zip”, from the Cycling ’74 Wiki (available right at the start of the document)
- Unzip ”AUGenExport-v01.zip”
- Open Terminal (Applications/Utilities/Terminal)
- If you haven’t used Terminal before, now is a good time not to worry
- Type “cd ” (without the quote, make sure you add a space after cd)
- Drag the unzipped AUGenExport-v01 folder from the finder into the Terminal window. This will make the path of the folder show up in Terminal
- Hit Enter
- Type: “python duplicate.py MyAU Tremolo yourName” without the quotes. Replace yourName with your name or your company name or whatever. This is a python script that will duplicate the example Xcode project provided by Cycling 74 and rename it to the plugin name we have specified (Tremolo) and the your name or company name
- Hit Enter
- The python script should do its thing and create a folder named ‘Tremolo’. If you don’t see it you have done something wrong (obviously!)
- Go to the Max Tremolo project and send an “exportcode” message to the gen~ object
- Choose the new Xcode project folder we created (Tremolo) when prompted and hit OK
- Navigate to our Xcode project folder (Tremolo) and open up the Xcode project: Tremolo.xcodeproj
- Click on ‘Tremolo.r’ in the Project Navigator column on the left
- Change value for COMP_MANUF from FRED to your company name
- Change COMP_SUBTYPE to trem
- Change NAME “C74: Tremolo Plugin” to NAME “yourCompanyName: Tremolo”
- Open ‘Tremolo-Info.plist’ under Tremolo > Supporting Files in the Project Navigator column on the left
- Expand the AudioComponents field and change the ‘manufacturer’ to your company name, the ‘name’ to ‘Tremolo’ and the ‘subtype’ to ‘trem’.
- Almost there!
- Open Tremolo.cpp from the Project Navigator
- Scroll down until you see this block of code (line 87):
- Change the arguments of AUEffectBaseMultichannel to (component, 2, 2):
- Hit cmd+B to build!
- Xcode should pop up a long list of semantic errors. Ignore.
- Go to the ‘Library’ folder in your User directory (Users/YourName/Library). If you are on 10.7 and up, Google how to find it
- Under the Library folder go to ‘Caches’ and delete “com.apple.audiounits.cache” (this will force your DAW – Logic primarily – to rescan all AU plugs)
- Empty Trash
- Go back to the Project Navigator, under the ‘Products’ folder right (or control) click ‘Tremolo.component’ and click on ‘Show in Finder’
- Copy ‘Tremolo.component’ from Finder
- Paste it in: Mac HD > Library > Audio > Plug-Ins > Components
- Open up your AU host (you could also use ‘AU Lab’ provided with Audio Tools for Xcode)
- If you have any problems, recheck the steps (and the pre-requisites)
Hopefully this post is enough to get you started with exploring gen~ and its capabilities so that when the code export feature is out of beta you will be all ready to make the most use out of it!
I have made a few more changes to the code so that the plugin opens with some default parameters and better labels.
And a video of it in action:
You can download the patch, Xcode project and AU plugin from:
I just spent a few hours on this so there is no guarantee that the plugin or the Xcode project will work well on your computer. Moreover, the AU plugin is not the most efficient bit of DSP in the world. Converting a phasor to a sine wave in real time mathematically is not the most CPU efficient method (a wavetable in most cases can work better). Also, from what I understand the AU specification requires all parameters to be within the range of 0 to 1, which I have clearly broken with the Frequency and Phase parameter.
Happy coding and patching.
Do post any questions, comments or criticism.