0

I'm new to Core Audio so I might not see something obvious… My aim is to process previously recorded audio signals. However, those signals should be filtered first. I don't need to play any audio. I only need to record and process it.

My graph looks like that: RemoteIO --> HighPassFilter --> callback (process audio)

And I set it up like this:

LBAudioDetectiveGetDefaultFormat(&detective->streamFormat);

// Create new AUGraph
OSStatus error = NewAUGraph(&detective->graph);
LBErrorCheck(error);

// Initialize AUNodes
AudioComponentDescription rioCD = {0};
rioCD.componentType = kAudioUnitType_Output;
rioCD.componentSubType = kAudioUnitSubType_RemoteIO;
rioCD.componentManufacturer = kAudioUnitManufacturer_Apple;

AUNode rioNode;
error = AUGraphAddNode(detective->graph, &rioCD, &rioNode);
LBErrorCheck(error);

AudioComponentDescription filterCD = {0};
filterCD.componentType = kAudioUnitType_Effect;
filterCD.componentSubType = kAudioUnitSubType_HighPassFilter;
filterCD.componentManufacturer = kAudioUnitManufacturer_Apple;

AUNode filterNode;
error = AUGraphAddNode(detective->graph, &filterCD, &filterNode);
LBErrorCheck(error);

// Open the graph so I can modify the AudioUnits
error = AUGraphOpen(detective->graph);

// Adapt rioUnit
error = AUGraphNodeInfo(detective->graph, rioNode, NULL, &detective->rioUnit);
LBErrorCheck(error);

UInt32 onFlag = 1;
AudioUnitElement bus1 = 1;
UInt32 propertySize = sizeof(UInt32);    
error = AudioUnitSetProperty(detective->rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, bus1, &onFlag, propertySize);
LBErrorCheck(error);

propertySize = sizeof(AudioStreamBasicDescription);
error = AudioUnitSetProperty(detective->rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, bus1, &detective->streamFormat, propertySize);
LBErrorCheck(error);

// Adapt filterUnit
error = AUGraphNodeInfo(detective->graph, filterNode, NULL, &detective->filterUnit);
LBErrorCheck(error);

AURenderCallbackStruct callback = {0};
callback.inputProc = _LBAudioDetectiveFilterOutput;
callback.inputProcRefCon = detective;
propertySize = sizeof(AURenderCallbackStruct);
error = AudioUnitSetProperty(detective->filterUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, propertySize);
LBErrorCheck(error);

// Connect the two units
AudioUnitElement bus0 = 0;
error = AUGraphConnectNodeInput(detective->graph, rioNode, bus1, filterNode, bus0);
LBErrorCheck(error);

AUGraphInitialize(detective->graph);

My code fails with the error -10879 when I try to set the callback. I'm assuming that the filter audio unit doesn't support this property. How am I supposed to get the recorded sound then? A second generic output unit isn't allowed as far as I know.

Thanks for your help in advance

lbrndnr
  • 3,361
  • 2
  • 24
  • 34

1 Answers1

4

Configure a callback on the output (bus 0) of the RemoteIO Audio Unit (instead of the filter unit or input bus), but in that RemoteIO callback, pull (render) from the filter unit. The filter unit will then be called to pull available data from RemoteIO input (bus 1) to process it.

Also fill the output buffers with zeros if you don't want to make any sounds.

Basically, the speaker side of RemoteIO provides the timing of the callbacks for data on the microphone side of RemoteIO, even if you don't want to play any sound out the speaker. This is because the whole Audio Unit chain is based on a pull model (there's no place for the ADC to push data into the API), but the hardware sample rates of the input and output happen to be identical. So the output is called at exactly the right time for the audio unit chain to pull from the microphone input buffers.

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • Hmm, that's a smart approach but that doesn't call the input callback anymore. What buses do I exactly need to connect. I've connected bus 1 of the rioUnit with bus 0 of the filterUnit. The callback struct was configured on bus 1 of the rioUnit of the output scope. The callback was called but it didn't contain any data in 'ioData->mBuffers[0].mData' – lbrndnr Apr 22 '13 at 19:40