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.

Pre-requisites (you can skip this if you just want to make a tremolo effect in Max):

To get the AU plugin to work, you will need to do the following:

  • Make sure you are using Max 6.1 or later. You can download the demo here
  • You need to install Xcode 4.6 or later which you can get off the Mac App Store. More info here. You will need an Apple developer account which you can get for free
  • Download Audio Tools for Xcode (make sure you get the version dated Feb 16, 2012) [open Xcode and then Xcode > Open Developer Tool > More Developer Tools..]
  • Create a folder called ‘Developer’ under ‘Applications’ (Applications > Developer)
  • Copy the ‘CoreAudio’ folder from the Audio Tools image file into the ‘Developer’ folder you just created

 

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:
logicAutomHow 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

fsSineScaling a signal:

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.
fsSinePatch
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.

sine0to1We can now use this oscillating signal to modulate the amplitude of a sound:

TremoloBasicMax1Quite 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.
genDefaultThe 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.

genTrem1The 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:

genTrem1OutThis 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.

phasorOutTo create a sine wave from a phasor, we need to use a mathematical formula (lots of information about this online):

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:
creatingSineGenNow, 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).

squareWavesquareWaveScopeIf 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.

mixShapesGenmixShapesGreat! Now lets expand this so that it works for a stereo input by duplicating the patch for a second channel:

tremStereo Now, lets use a ‘mix’ object for each channel so that we can crossfade between the dry and wet signals. Lets also create a ‘Mix’ parameter to control the…mix.

tremMixTwo 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.

tremPhase2It 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).

tremComplete2smoothen

And we are done!

finPatch

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):

  1. 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)
  2. Download “AUGenExport-v01.zip‎”, from the Cycling ’74 Wiki (available right at the start of the document)
  3. Unzip ”AUGenExport-v01.zip‎”
  4. Open Terminal (Applications/Utilities/Terminal)
  5. If you haven’t used Terminal before, now is a good time not to worry
  6. Type “cd ” (without the quote, make sure you add a space after cd)
  7. 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
  8. Hit Enter
  9. 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
  10. Hit Enter
  11. 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!)
  12. terminalGo to the Max Tremolo project and send an “exportcode” message to the gen~ object
  13. Choose the new Xcode project folder we created (Tremolo) when prompted and hit OK
  14. Navigate to our Xcode project folder (Tremolo) and open up the Xcode project: Tremolo.xcodeproj
  15. Click on ‘Tremolo.r’ in the Project Navigator column on the left
  16. Change value for COMP_MANUF from FRED to your company name
  17. Change COMP_SUBTYPE to trem
  18. Change NAME “C74: Tremolo Plugin” to NAME “yourCompanyName: Tremolo”
  19. tremrXcodeOpen ‘Tremolo-Info.plist’ under Tremolo > Supporting Files in the Project Navigator column on the left
  20. Expand the AudioComponents field and change the ‘manufacturer’ to your company name, the ‘name’ to ‘Tremolo’ and the ‘subtype’ to ‘trem’.
  21. tremplistAlmost there!
  22. Open Tremolo.cpp from the Project Navigator
  23. Scroll down until you see this block of code (line 87):
    codeChange
  24. Change the arguments of AUEffectBaseMultichannel to (component, 2, 2):
  25. changeCodeHit cmd+B to build!
  26. Xcode should pop up a long list of semantic errors. Ignore.
  27. 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
  28. 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)
  29. Empty Trash
  30. Go back to the Project Navigator, under the ‘Products’ folder right (or control) click ‘Tremolo.component’ and click on ‘Show in Finder’
  31. Copy ‘Tremolo.component’ from Finder
  32. Paste it in: Mac HD > Library > Audio > Plug-Ins > Components
  33. Open up your AU host (you could also use ‘AU Lab’ provided with Audio Tools for Xcode)
  34. Done!
  35. 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.

TremAU

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.

 

14 Comments on “A Tremolo AU plugin with Max

  1. Pingback: Exporting Gen~ to an Audio Unit Plugin with Designing Sound « Cycling 74

  2. I’m not sure that is a good place to ask this after such a demonstration about what Max is able to do but, I still wonder why C74 introduce new concepts both syntactic and graphical. For example why the audio patchcords in [gen~] are the same look with the message one? Okay, ok that’s not the subject …

  3. How does one order the parameters in the AU?
    I’d love to see a way to take this to the next level by building a VST with a simple GUI. (Mac/PC)

    • Matt: You’ll have to reorder the parameters in gen_exported.cpp. Look at “void setparamater”, “void getparameter” and “void * self”. If you compare the gen_exported.cpp file you have with the one I’ve provided in the download package it should be clear.

      • Thanks. I also noticed that the parameter changes via the GUI and via Live’s device view don’t move the other GUIs’… Is this a bug in the template?

  4. My Plugin uses x 2 as much CPU as my Max for Live device.

    • Only expected Matt. This implementation of gen~ code as an AU plugin is very early stage. We can only wait to see the improvements made to gen code export once it gets out of being beta.

      The plugin doesn’t update visually with automation changes in Logic either. Seems like it isn’t implemented in the template or is a bug. Will report it to c74.

  5. very nice introduction, varun.

    as i try to build the tremolo.component(using your Tremolo.xcodeproj) i get an error saying “build failed”:
    /Applications/Developer/CoreAudio/PublicUtility/CADebugMacros.h:139:79: Invalid suffix on literal; C++11 requires a space between literal and identifier

    what i get is an tremolo.component file which is 2kb small.

    i repeat all the steps you described multiple times with Xcode 4.6.1 running on OSX 10.7.5. i put the core audio like you suggest into my applications/ developer folder. i also tried to put coreaudio into library/developer/ and /application/ Xcode/content/developer/extras/ that some other guys recommend.

    did you have any any idea why the building process of your tremolo.cpp failed within my xcode 4.6.1?
    is there any special xcode setting needed? thanks, jo

    • nevermind, when i set the path to coreaudio manually to
      /Users/j/Library/Developer/CoreAudio/ via CORE_AUDIO_LOCATION
      it works.

      is there an easy way to define the order in which the parameter-sliders appear in the au plugin?

        • Glad you got it all sorted!

          I haven’t tried reordering the params in the code box. I did it in the exported Cpp file.

          • good to know.
            did you know if tis possible to turn gen~ code into vst~ plugin?

  6. It seems to be hinted on the c74 blog/wiki. My guess is its a matter of time.

  7. Thank you so much for posting a well documented tutorial on Gen~ It’s the most useful guide I’ve come across covering waves and techniques for multishaping waveforms from a single source. You rock!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>