如何在AUGraph中添加kAudioUnitSubType_LowPassFilter?

时间:2016-06-16 12:16:26

标签: ios core-audio augraph

我正在尝试将kAudioUnitSubType_LowPassFilter添加到AUGraph,但不会成功。

我实现了以下代码:

// create a new AUGraph
[Utilities checkError:NewAUGraph(&self.info->mGraph)
            operation: "Couldn't create a new AUGraph"];

AUNode rioNode;
AUNode lpfNode;

// Create filter audio unit
AudioComponentDescription lpfAU_description;
lpfAU_description.componentType = kAudioUnitType_Effect;
lpfAU_description.componentSubType = kAudioUnitSubType_LowPassFilter;
lpfAU_description.componentFlags = 0;
lpfAU_description.componentFlagsMask = 0;
lpfAU_description.componentManufacturer = kAudioUnitManufacturer_Apple;


// Create RemoteIO audio unit
AudioComponentDescription rioAU_description;
rioAU_description.componentType = kAudioUnitType_Output;
rioAU_description.componentSubType = kAudioUnitSubType_RemoteIO;
rioAU_description.componentManufacturer = kAudioUnitManufacturer_Apple;
rioAU_description.componentFlags = 0;
rioAU_description.componentFlagsMask = 0;

[Utilities checkError:AUGraphAddNode(self.info->mGraph, &rioAU_description, &rioNode)
            operation: "Couldn't add Graph Node"];
[Utilities checkError:AUGraphAddNode(self.info->mGraph, &lpfAU_description, &lpfNode )
            operation: "Couldn't add Graph Node"];

// Open graph
[Utilities checkError:AUGraphOpen(self.info->mGraph)
            operation: "Couldn't open graph"];

// Get audio units
[Utilities checkError:AUGraphNodeInfo(self.info->mGraph, lpfNode, NULL, &self.info->lpfUnit)
            operation: "Couldn't link node to audio unit"];

[Utilities checkError:AUGraphNodeInfo(self.info->mGraph, rioNode, NULL, &self.info->rioUnit)
            operation: "Couldn't link node to audio unit"];

// Make connections
[Utilities checkError:AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 1)
            operation: "Couldn't connect remoteIO output scope bus 1 to filter input scope bus 1"];// input -> filter

[Utilities checkError: AUGraphConnectNodeInput(self.info->mGraph, lpfNode, 0, rioNode, 0)
            operation: "Couldn't connect filter output scope bus 0 to remoteIO input scope bus 0"]; // filter -> output

// Enable IO for input and output (recording and playing)
AudioUnitElement kRemoteIOInputScopeMic = 1;
AudioUnitElement kRemoteIOOutputScopeSpeaker = 0;

UInt32 enableInput = 1;
[Utilities checkError:AudioUnitSetProperty (self.info->rioUnit,
                                            kAudioOutputUnitProperty_EnableIO,
                                            kAudioUnitScope_Input,
                                            kRemoteIOInputScopeMic,
                                            &enableInput,
                                            sizeof(enableInput))
            operation: "Couldn't enable RIO input"];

// set up the rio unit for playback
UInt32 enableOutput = 1;
[Utilities checkError:AudioUnitSetProperty (self.info->rioUnit,
                                            kAudioOutputUnitProperty_EnableIO,
                                            kAudioUnitScope_Output,
                                            kRemoteIOOutputScopeSpeaker,
                                            &enableOutput,
                                            sizeof(enableOutput))
            operation: "Couldn't enable RIO output"];

// Set property to low-pass filter
AudioUnitSetParameter(self.info->lpfUnit,
                      kLowPassParam_CutoffFrequency,
                      kAudioUnitScope_Global,
                      0,
                      1000,
                      0);



// Set callbacks
// Callback for input
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = recordingCallback;
callbackStruct.inputProcRefCon = (__bridge void*) self;


[Utilities checkError: AudioUnitSetProperty(self.info->rioUnit,
                                            kAudioOutputUnitProperty_SetInputCallback,
                                            kAudioUnitScope_Global,
                                            1, // Input bus
                                            &callbackStruct,
                                            sizeof(AURenderCallbackStruct))
            operation: "AudioUnitSetProperty set RenderCalback"];

// Callback to render data
callbackStruct.inputProc = renderCallback;
callbackStruct.inputProcRefCon = (__bridge void*) self;


[Utilities checkError: AudioUnitSetProperty(self.info->rioUnit,
                                            kAudioUnitProperty_SetRenderCallback,
                                            kAudioUnitScope_Input, //kAudioUnitScope_Global, ????
                                            0, // Output bus
                                            &callbackStruct,
                                            sizeof(AURenderCallbackStruct))
            operation: "AudioUnitSetProperty set RenderCalback"];

[Utilities checkError: AUGraphInitialize(self.info->mGraph)
            operation: "Couldn't initialize graph"];


// Input ASBD
AudioStreamBasicDescription inputasbd;
UInt32 propSize = sizeof(inputasbd);
[Utilities checkError:AudioUnitGetProperty(self.info->rioUnit,
                                           kAudioUnitProperty_StreamFormat,
                                           kAudioUnitScope_Input,
                                           1,
                                           &inputasbd,
                                           &propSize)
            operation:"Failed to get stream format of microphone input scope"];

// Output ASBD
AudioStreamBasicDescription outputasbd;
UInt32 typeByteSize   = sizeof(float);
outputasbd.mBitsPerChannel   = 8 * typeByteSize;
outputasbd.mChannelsPerFrame = 1;
outputasbd.mBytesPerFrame    = typeByteSize * outputasbd.mChannelsPerFrame;
outputasbd.mFormatFlags      = kAudioFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved;
outputasbd.mFormatID         = kAudioFormatLinearPCM;
outputasbd.mFramesPerPacket  = 1;
outputasbd.mBytesPerPacket   = outputasbd.mFramesPerPacket * outputasbd.mBytesPerFrame;
outputasbd.mSampleRate       = inputasbd.mSampleRate;

// Set stream format to output scope of input bus
[Utilities checkError:AudioUnitSetProperty (self.info->rioUnit,
                                            kAudioUnitProperty_StreamFormat,
                                            kAudioUnitScope_Output,
                                            1,
                                            &inputasbd,
                                            sizeof (AudioStreamBasicDescription))
            operation: "Couldn't set ASBD for RIO on output scope / bus 1"];

// Set format on inputscope of output bus
[Utilities checkError:AudioUnitSetProperty(self.info->rioUnit,
                                           kAudioUnitProperty_StreamFormat,
                                           kAudioUnitScope_Input,
                                           0,
                                           &outputasbd,
                                           sizeof(AudioStreamBasicDescription))
            operation: "Couldn't set ASBD for RIO on input scope / bus 0"];


// Start AUGraph
[Utilities checkError:AUGraphStart(self.info->mGraph)
        operation: "Couldn't start AUGraph"];

但不幸的是,AU Graph无法从这个代码开始(OSStatus -10863)。 当我通过注释AUGraphConnectNodeInput方法删除过滤器或直接使用remoteIO AU时,音频会从麦克风播放到扬声器而不会出现问题。

有人能给我一个提示,说明我在配置kAudioUnitSubType_LowPassFilter时遇到了什么问题吗?

1 个答案:

答案 0 :(得分:0)

编辑2:

将您的ASBD更改为立体声。过滤器需要它。

我认为AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 1)应该是AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 0)。 inDestInputNumber参数本质上是输入总线,并且过滤器只有一个总线,因此该参数应该是总线0;如果这不能解决问题,请发布setStreamFormatWithInputASBD方法中的内容(如果相关)。无论哪种方式,我通常会明确地设置所有输出ASBD以匹配它所连接的单元的输入。

如下图所示:unit-> unitA-> unitB-> outUnit使用此模式设置ASBD:

(audioUnitGetProperty的伪代码和ASBD的setproperty)

unitB.outputASBD = outUnit.inputASBD; 
unitA.outputASBD = unitB.inputASBD; 
inUnit.outputASBD = unitA.inputASBD; 

有时这不是必要的,但有时它是!大多数滤波器都使用强制立体浮点ASBD作为输入。