2

I am new AUAudioUnits and trying to get an understanding of how to use the v3 API. I am trying to schedule a parameter change on a kAudioUnitSubType_MultiChannelMixer AUAudioUnit so that I can ramp a gain change over time. I am able to set the gain directly with a slider and the change takes affect immediately like this:

/*...*/
// Inside my ViewController

  @IBAction func slider1Changed(sender: UISlider) {
    player.gainParameter.setValue(sender.value, originator: nil)
  }

// Inside my AudioPlayerClass

    guard let parameterTree = self.multichannelMixer.parameterTree else {
      print("Param Tree")
      return
    }

    self.gainParameter = parameterTree.parameterWithID(
      kMultiChannelMixerParam_Volume,
      scope: kAudioUnitScope_Input,
      element: 0)

but when I try to do this using the scheduleParameterBlock by adding this to the above AudioPlayerClass I would expect the gain to ramp from 1 to 0 over 10 seconds but there is no change:

    let scheduleMixerParamBlock = self.multichannelMixer.scheduleParameterBlock
    let rampTime = AUAudioFrameCount(10.secondsToSampleFrames)
    scheduleMixerParamBlock(AUEventSampleTimeImmediate, rampTime, self.gainParameter.address, 0)

Examples I have seen of it working in the apple examples include code such as this (without the dispatch_async part):

parameterTree.implementorValueObserver = {param, value in
  dispatch_async(dispatch_get_main_queue()) {
    print(param, value)
  }
  scheduleMixerParamBlock(AUEventSampleTimeImmediate, rampTime, param.address, value)
}

When I run this and change the gain parameter with the slider then the block is run and the param and value are printed to the console with the correct looking values but the gain is not changed in the actual audio. These examples I have seen are also on custom AUAudioUnits where the implementor has direct access to the dspKernel function so I might be missing something crucial there. The other alternative I have to calculate a series of ramp values and then set the gain parameter directly for each value but since the scheduleParameterBlock is there is seems like I should be able to use that. Any help would be great. Thanks

Dallas Johnson
  • 1,546
  • 10
  • 13

1 Answers1

1

You have to look at the AURenderEvent head in the internalRenderBlock which is operating on the audio render thread. Your scheduled parameter events will appear there for you to respond to.

For example, pass the head to this function:

void doEvents(AURenderEvent const* event)
    {
        while (event != nullptr) {
            switch (event->head.eventType) {
                case AURenderEventParameter:
                    doParameterEvent(event->parameter);
                    break;
                default:
                    break;
            }
            event = event->head.next;
        }
    }

void doParameterEvent(AUParameterEvent const &event) {
        switch (event.parameterAddress) {
            case FilterParameterAddressFoo:
                doFoo();
                break;
            case FilterParameterAddressBar:
                doBar();
                break;
            default:
                break;
        }
    }
Steve M
  • 9,296
  • 11
  • 49
  • 98