Search code examples
iosaudiocore-audiospotify

Mix two AUNodes in Spotify iOS SDK


I'm trying to use the dynamic processor and a bunch of filters to compress a specific frequency band within the spotify method connectOutputBus but when i mix the nodes in the kAudioUnitSubType_MultiChannelMixer only the sound of the first added node comes out.

obs: i actually use filters on sourceNodeCopy to remove the freqs that will be compressed on the souceNode but to keep things short i omitted them.

Here's the code:

override func connectOutputBus(_ sourceOutputBusNumber: UInt32, ofNode  sourceNode: AUNode, toInputBus destinationInputBusNumber: UInt32, ofNode destinationNode: AUNode, in graph: AUGraph!) throws {

  let sourceNodeCopy = sourceNode //original node without the harsh freq

  //create a filter for the harsh frequencies
  var filterDescription = AudioComponentDescription()
  filterDescription.componentType = kAudioUnitType_Effect
  filterDescription.componentSubType = kAudioUnitSubType_BandPassFilter
  filterDescription.componentManufacturer = kAudioUnitManufacturer_Apple
  filterDescription.componentFlags = 0
  filterDescription.componentFlagsMask = 0

  AUGraphAddNode(graph, &filterDescription, &filterNode!) // Add the filter node
  AUGraphNodeInfo(graph, filterNode!, nil, &filterUnit!) // Get the Audio Unit from the node
  AudioUnitInitialize(filterUnit!) // Initialize the audio unit
  // Set filter params
  AudioUnitSetParameter(filterUnit!, kBandpassParam_CenterFrequency, kAudioUnitScope_Global, 0, 10038, 0)

  //create a processor to compress the frequency
  var dynamicProcessorDescription = AudioComponentDescription()
  dynamicProcessorDescription.componentType = kAudioUnitType_Effect
  dynamicProcessorDescription.componentSubType = kAudioUnitSubType_DynamicsProcessor
  dynamicProcessorDescription.componentManufacturer = kAudioUnitManufacturer_Apple
  dynamicProcessorDescription.componentFlags = 0
  dynamicProcessorDescription.componentFlagsMask = 0

  // Add the dynamic processor node
  AUGraphAddNode(graph, &dynamicProcessorDescription, &dynamicProcessorNode)
  AUGraphNodeInfo(graph, dynamicProcessorNode, nil, &dynamicProcessorUnit)
  AudioUnitInitialize(dynamicProcessorUnit!)

  // Set compressor params
  AudioUnitSetParameter(dynamicProcessorUnit!, kDynamicsProcessorParam_Threshold, kAudioUnitScope_Global, 0, -35, 0)
  AudioUnitSetParameter(dynamicProcessorUnit!, kDynamicsProcessorParam_AttackTime, kAudioUnitScope_Global, 0, 0.02, 0)
  AudioUnitSetParameter(dynamicProcessorUnit!, kDynamicsProcessorParam_ReleaseTime, kAudioUnitScope_Global, 0, 0.04, 0)
  AudioUnitSetParameter(dynamicProcessorUnit!, kDynamicsProcessorParam_HeadRoom, kAudioUnitScope_Global, 0, 0, 0)

  //mixer
  var mixerDescription = AudioComponentDescription()
  mixerDescription.componentType = kAudioUnitType_Mixer
  mixerDescription.componentSubType = kAudioUnitSubType_MultiChannelMixer
  mixerDescription.componentManufacturer = kAudioUnitManufacturer_Apple
  mixerDescription.componentFlags = 0
  mixerDescription.componentFlagsMask = 0

  AUGraphAddNode(graph, &mixerDescription, &audioEffectsController.mixerNode)
  AUGraphNodeInfo(graph, audioEffectsController.mixerNode, nil,
                    &audioEffectsController.mixerUnit)
  AudioUnitInitialize(audioEffectsController.mixerUnit!)

  AudioUnitSetParameter(mixerUnit!, kMultiChannelMixerParam_Volume, kAudioUnitScope_Input, 0, 1.0, 0);
    AudioUnitSetParameter(mixerUnit!, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, 1.0, 0);


  //connect the nodes
  AUGraphConnectNodeInput(graph, sourceNode, sourceOutputBusNumber, filterNode, 0)
  AUGraphConnectNodeInput(graph, filterNode, sourceOutputBusNumber, dynamicProcessorNode, 0)

  AUGraphConnectNodeInput(graph, sourceNodeCopy, sourceOutputBusNumber, mixerNode, 0)
  AUGraphConnectNodeInput(graph, fiterNode, sourceOutputBusNumber, mixerNode, 0)

  //connect the mixer to the output
  AUGraphConnectNodeInput(graph, audioEffectsController.mixerNode, 0, destinationNode, destinationInputBusNumber)

Solution

  • In your code you connect the node like this

    AUGraphConnectNodeInput(graph, sourceNodeCopy, sourceOutputBusNumber, mixerNode, 0)
    AUGraphConnectNodeInput(graph, fiterNode, sourceOutputBusNumber, mixerNode, 0)
    

    If you do this, you will connect sourceNodeCopy and filterNode to the same input (0) of the MixerNode. But only one can be connected...

    You should try this instead

    AUGraphConnectNodeInput(graph, sourceNodeCopy, sourceOutputBusNumber, mixerNode, 0)
    AUGraphConnectNodeInput(graph, fiterNode, sourceOutputBusNumber, mixerNode, 1)