Two AUParameter's affect the same Audio Unit

Setting up a custom AUAudioUnit with a single parameter

I’ve created a custom AudioUnit by subclassing

AUAudioUnit
. The implementation can be seen in this gist. 

My goal here is to have a single parameter on this unit called “frequency”. The DSP/Render-Block is a basic sin wave generator which uses this parameter to set the frequency.

The documentation of Audio Unit parameters in the new AudioUnit V3 extends only to the docs, one WWDC3 video and three total examples of its use on the world wide web. But from looking over those example projects and perusing Apple header files, I see that I need the

AUParameterTree
attached to the Audio Unit. A
AudioUnitParameterID
, an instance variable to hold the float, and the
implementorValueProvider
and
implementorValueObserver
.

Instantiating multiple custom AU instances



Now my goal is two instantiate two instances of this Audio Unit. I use an

AVAudioEngine
two connect both instances to the main mixer node in the engine. I expect to hear two sin waves playing at the default frequency set in my
AUAudioUnit
subclass.

Now in my Host app’s View Controller I set the units up and store references to them like this:



  [_audioEngine setupAUWithComponentDescription:desc andCompletion:^(AUAudioUnit *unit) { NSLog(@"%p", unit); au = unit; } name:0]; [_audioEngine setupAUWithComponentDescription:desc andCompletion:^(AUAudioUnit *unit) { NSLog(@"%p", unit); au2 = unit; [_audioEngine startEngine]; } name:1];



I’m just logging the addresses to check that they are distinct and waiting until the second one is connected to the mixer before starting the engine. 

You can see the engine implementation in this gist.

Now, in order to test that, I have some code to set the “frequency” parameter independently on each Audio Unit's

AUParameterTree
:

Testing my assumptions





- (void)tapped:(UIPanGestureRecognizer *)recognizer { AUParameter * p = [au.parameterTree valueForKeyPath:@"frequency"]; AUParameter * p2 = [au2.parameterTree valueForKeyPath:@"frequency"]; [p setValue:100 originator:nil]; [p2 setValue:200 originator:nil]; }

The Issue

And… nothing. I hear a single tone. I put a breakpoint on my

implementorValueObserver


:

_parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) { switch (param.address) { case frequencyAddress: printf("pointer to self in value observer: %p \n", pointerToSelf); frequency = value; break; default: break; } };



pointerToSelf
is logged twice. Both memory addresses are the same. In the host code, I see two distinct
AUAudioUnit
s. When I get the
AUParameterTree
and
AUParameter
’s I see these are distinct as well. In fact, at the end of the
tapped:
method,
p
and
p2
have values
100
and
200
respectively as I was expecting. But
pointerToSelf
shows that the
implementorValueObserver
block is being called twice on on Audio Unit. 

Now the DSP running in one of the two Audio Unit’s is seeing
frequency
(the instance variable in my
AUAudioUnit
subclass) as
200
. Since the same one is set to
100
and then
200
.

what next?



I’ve searched endlessly for some explanation on why this is happening. Assuming its not some stupid mistake I’m overlooking in my code, it could be that I’m not understanding the

AUParameterTree
abstraction, but even after watching the WWDC video, and reading for hours, I don’t see what is wrong here..

I’d greatly appreciate any insight on this issue.