Category

Audio Units (AUv3) MIDI extension – Part 1: Parameters

Audio Units, version 3 (AUv3) Parameters

In my previous post on AUv3 MIDI plugins, the interval that was added to MIDI events was hard coded. In this post the user will be able to set that interval via an AUParameterEvent.

Introduction

Table of Contents

The old API for audio unit parameters was rather clunky and limited. Without going into it too much, here is an example of retrieving the information for the parameters supported by an AudioUnit. Note that it’s an AudioUnit and not the newer AUAudioUnit that we are using now.

Yeesh.

The new API has the parameters organized into a parameter tree. There can be many more of them since they are not globally scoped as in the old API. There are many more reasons why they’re better, but let’s just start using them. Watch the WWDC audio videos for the benefits.

The Parameter tree

Table of Contents

In the Apple template code you’ve seen some parameter code strewn about. Let’s take a step back.

In the previous iteration, I hard coded the interval that is added to each incoming MIDI note message. What I want to do here is to enable the user to set the interval. So that means the UI’s ViewControllers need to be able to set the interval parameter and be informed whenever it’s been changed. The Audio Unit needs to define the set of parameters that it uses. These are often the synthesis parameters such as a filter’s cut off frequency. Here we’re just concerned with MIDI.

So, the first step is to create the parameter.

I deleted the template code from the init method and created a setupParameters method instead. First I specify flags that allow the parameters to be read/write. For convenience of the UI, I’m also creating names for an octave of intervals. I’m bad and didn’t localize them. Kids, don’t do this at home. Then, to create the parameter, invoke the parameter tree’s create method. There are several parameters that are needed. Min and max are obvious. The unit has several constants defined. Percentages are available for example. Choose the appropriate one. I set the valueStrings to my interval name array. I’ll talk about the rest in a minute. Take a look at the following code first.

So now that you grok that completely, how do you get the parameter? Well in the audio unit, I defined an instance variable like this: AUParameter *intervalParam;

But what about the UI? We don’t have access to that variable. In AudioUnitViewController there is an audioUnit instance variable, which is initialized right in the VC since it is also an AUAudioUnitFactory. That’s pretty much the sum of the template UI code except for this comment:

// Get the parameter tree and add observers for any parameters that the UI needs to keep in sync with the AudioUnit

Gee thanks. How?

Well, we don’t know when the UI will be loaded if at all or when the audio unit create factory method is called. So we need to prepare for that. I created a method named connectUIToAudioUnit. Then modified the factory method to call it if the view has been loaded. For good measure, I also call this connect method from viewDidLoad. Many times I’ve had a crash if I put it in viewDidLoad alone. Don’t be like me.

So what does this connect method look like? Since we now have the audio unit, try to get it’s parameter tree. If you can’t, then you have to punt.

With the tree in hand (which is worth two in the bush) you can retrieve the parameter using its identifier. Or key. The API write is inconsistent. We said createParameterWithIdentifier: @”intervalParameter” – perhaps createParameterWithKey: @”intervalParameter” would have made more sense. We’re stuck with it so no use complaining. Since KVO returns the value as Any?, a cast is needed.

Or, instead of using the parameter’s identifier/key, we can retrieve it using its address. Note that back in the create call, one parameter is named address and we pass this in. In the template code, we see a global variable in the audio unit:

const AudioUnitParameterID myParam1 = 0;

So, define it here. (Either just rename myParam1 or add a new one with a new value)

const AudioUnitParameterID intervalParameter = 0;
Add it to the header file also.

BTW, if you’re going to have a ton of parameters like most synths, you’d be better off creating these in an enum. Just sayin’.

Then we can call parameterTree.parameter(withAddress: to retrieve it and update the UI components.

Wait. What’s that string(fromValue: method returning? The value strings we passed in? Not really. You have another hoop to jump through.

After you’ve created the tree, add this. This was part of the template code. Of course, it’s modified to return the interval name from my array.

What do you get if you don’t provide this? The actual value as a string. Try it. Comment it out.

Finally, in the render block, I capture the intervalParam. Remember, be selfless in the render block. Or of course, if you’re not using an instance variable, do the key lookup I showed above. Just do it in a local variable here that will be captured by the block and not in the block itself. (remember, the method internalRenderBlock is called once. The block it returns is called repeatedly at audio rate).

What else? That’s it except for creating a nice UI. Don’t look at me for that; I’m still wearing a shirt from 1973. No, not from a vintage store; I bought it in 1973. Yes, I’ve washed it. I think. I’ll get back to you on that.

Hosted in AUM

Next post: How about timing?

Play an arpeggio or sequence?

Would you like that?

Summary

Table of Contents

The new API for audio unit parameters is a lot less klunky than the old API. Note that I say “less klunky” and not “unklunky” or even “klunkless.

Resources

Table of Contents

8 thoughts on “Audio Units (AUv3) MIDI extension – Part 1: Parameters”

  1. Hi Gene!

    Your examples is AWESOME! Seriously, THE BEST core audio tutorials and examples on this planet!)

    What you do is just great.

  2. Thank you for your tutorials! It seems to be the only step by step guide to get a working AUv3 MIDI processor on the internet. I am just starting with it and have few questions:
    – why in newer templates Apple added DSP kernel classes and why MIDI output block is not reachable there?
    – how should I send MIDI messages based on user interactions? For example simple button that when pressed triggers note on/off messages. Is it done through parameters or with local audio unit variables (like a queue, and view controller somehow will push messages there)?

    1. Thanks!

      The example on GitHub plays MIDI notes when the user presses a ui button, so copy that for a starting point.

      Some apps might want to do both audio and MIDI, so Apple kept in some skeleton DSP frobs.
      Bram Bos has apps like this for example.

      They’ve modified the templates since I wrote the tutorials. More Swift for many more things (but not the real time audio).
      I’ll post new blog posts when I get done with my current project.

      1. Thank you for such fast reply! Although I haven’t found this example. The one that linked in this post (and others I could find in your github account) are changing interval parameter value based on segmented control value change.

        Please, can you share a url of the example you specified?

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.