如何在 AUGraph 中添加 kAudioUnitSubType_LowPassFilter?
How to add kAudioUnitSubType_LowPassFilter in a 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
时做错了什么吗?
编辑 2:
将您的 ASBD 更改为立体声。过滤器需要它。
我认为AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 1)
应该是AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 0)
。 inDestInputNumber 参数本质上是输入总线,过滤器只有一条总线,因此该参数应该是总线 0;如果那不能解决问题,post 您的 setStreamFormatWithInputASBD
方法中发生了什么(如果相关)。无论哪种方式,我通常都会明确设置我所有的输出 ASBD 以匹配它所连接的单元的输入。
给出这样的图 inUnit->unitA->unitB->outUnit 使用此模式设置 ASBD:
(audioUnitGetProperty 的伪代码和 ASBD 的 setproperty)
unitB.outputASBD = outUnit.inputASBD;
unitA.outputASBD = unitB.inputASBD;
inUnit.outputASBD = unitA.inputASBD;
有时这不是必需的,但有时是!大多数过滤器都采用强制立体浮点 ASBD 作为输入。
我正在尝试将 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
时做错了什么吗?
编辑 2:
将您的 ASBD 更改为立体声。过滤器需要它。
我认为AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 1)
应该是AUGraphConnectNodeInput(self.info->mGraph, rioNode, 1, lpfNode, 0)
。 inDestInputNumber 参数本质上是输入总线,过滤器只有一条总线,因此该参数应该是总线 0;如果那不能解决问题,post 您的 setStreamFormatWithInputASBD
方法中发生了什么(如果相关)。无论哪种方式,我通常都会明确设置我所有的输出 ASBD 以匹配它所连接的单元的输入。
给出这样的图 inUnit->unitA->unitB->outUnit 使用此模式设置 ASBD:
(audioUnitGetProperty 的伪代码和 ASBD 的 setproperty)
unitB.outputASBD = outUnit.inputASBD;
unitA.outputASBD = unitB.inputASBD;
inUnit.outputASBD = unitA.inputASBD;
有时这不是必需的,但有时是!大多数过滤器都采用强制立体浮点 ASBD 作为输入。