C# 如何创建一个音频单元链,该音频单元是AEС;,重采样和低通滤波器

C# 如何创建一个音频单元链,该音频单元是AEС;,重采样和低通滤波器,c#,ios,xamarin.ios,resampling,audiounit,C#,Ios,Xamarin.ios,Resampling,Audiounit,我使用带有VoiceProcessingIO类型的音频单元来接收无回声的语音。在RenderCallback中,我获取声音样本,然后将所有缓冲区值设置为零,这样就不会播放。 现在,我需要在接收到声音后将其采样率从48000更改为16000,然后将产生的声音通过低通滤波器。 我不知道如何配置多个音频单元以相互连接并链接数据。 我知道我必须使用kAudioUnitSubType\u AUConverter作为转换器,使用kAudioUnitSubType\u低通滤波器作为滤波器。 我已经不顾一切地想

我使用带有VoiceProcessingIO类型的音频单元来接收无回声的语音。在RenderCallback中,我获取声音样本,然后将所有缓冲区值设置为零,这样就不会播放。 现在,我需要在接收到声音后将其采样率从48000更改为16000,然后将产生的声音通过低通滤波器。
我不知道如何配置多个音频单元以相互连接并链接数据。
我知道我必须使用kAudioUnitSubType\u AUConverter作为转换器,使用kAudioUnitSubType\u低通滤波器作为滤波器。
我已经不顾一切地想找人帮忙了

另外,我发现了一个类似的问题,但作者的问题从未得到回答。但我不明白作者为什么使用两个转换器。我还担心他使用远程类型,我不明白他为什么要按顺序连接这些总线。


公共静态类声音设置
{
公共静态只读int-SampleRate=16000;
公共静态只读int通道=1;
公共静态只读int BytesPerSample=2;
公共静态只读int-FramesPerPacket=1;
}
专用会话()
{
AudioSession.Initialize();
AudioSession.Category=AudioSessionCategory.Play和Record;
AudioSession.Mode=AudioSessionMode.GameChat;
AudioSession.PreferredHardwareIOBufferDuration=0.08f;
}
私人单位()
{
_srcFormat=新的音频流基本描述
{
格式=AudioFormatType.LinearPCM,
FormatFlags=AudioFormatFlags.LinearPCMIsSignedInteger |
AudioFormatFlags.linearpcm已打包,
SampleRate=AudioSession.CurrentHardwareSampleRate,
FramesPerPacket=SoundSettings.FramesPerPacket,
BytesPerFrame=SoundSettings.BytesPerSample*SoundSettings.Channel,
BytesPerPacket=SoundSettings.FramesPerPacket*
SoundSettings.BytesPerSample*
声音设置,频道,
BitsPerChannel=SoundSettings.BytesPerSample*8,
ChannelsPerFrame=SoundSettings.Channels,
保留=0
};
var audioComponent=audioComponent.FindComponent(AudioTypeOutput.VoiceProcessingIO);
_audioUnit=新的audioUnit.audioUnit(audioComponent);
_audioUnit.SetEnableIO(true,AudioUnitScopeType.Input,1);
_audioUnit.SetEnableIO(真,AudioUnitScopeType.Output,0);
_SetFormat(_srcFormat,AudioUnitScopeType.Input,0);
_SetFormat(_srcFormat,AudioUnitScopeType.Output,1);
_SetRenderCallback(this.RenderCallback,AudioUnitScopeType.Input,0);
}
专用AudioUnitStatus RenderCallback(
AudioUnitRenderActionFlags操作标志,
音频时间戳,
uint总线号,
单位数框架,
音频缓冲区(数据)
{
var status=_audioUnit.Render(参考actionFlags、timeStamp、1、numberFrames、data);
如果(状态!=AudioUnitStatus.OK)
{
返回状态;
}
var msgArray=新字节[dataByteSize];
Marshal.Copy(数据[0]。数据,msgArray,0,dataByteSize);
var msg=\u msgFactory.CreateAudioMsg(msgArray,msgArray.Length,(++\u lastIndex));
这个.onmsgrady(msg);
//禁用播放IO
var数组=新字节[dataByteSize];
Marshal.Copy(数组,0,数据[0]。数据,数据字节大小);
返回AudioUnitStatus.NoError;
}

这里是一个可用于连接两个音频单元的函数示例(请注意,在成功连接之前,源和目标必须具有相同的流格式):


下面是一个可用于连接两个音频单元的函数示例(请注意,在成功连接源和目标之前,源和目标必须具有相同的流格式):


看起来你有一个可以处理声音或音乐的音响系统。首先,您不需要更改采样率,您可以始终添加滤波以获得较低的频率。例如,从48000到16000,您只需每三次采样一次。更改要从一个进程中获取输出并输入到第二个进程中的数据,并实时执行此操作。最简单的方法是创建FIFO并使用计时器。我实现了一个“朴素”算法来降低采样率。我取了三个样品的平均值。基本上,我可以使用任何插值,因为我不确定输入采样率是否总是48000。但是,由于48000和16000之间的差异是两倍多,我需要一个过滤器来避免声音失真。在任何情况下,“重新采样”一节就是这样说的。最后,使用系统功能比自制算法更可取。以下是不同格式的列表:看起来您有一个可以处理语音或音乐的音响系统。首先,您不需要更改采样率,您可以始终添加滤波以获得较低的频率。例如,从48000到16000,您只需每三次采样一次。更改要从一个进程中获取输出并输入到第二个进程中的数据,并实时执行此操作。最简单的方法是创建FIFO并使用计时器。我实现了一个“朴素”算法来降低采样率。我取了三个样品的平均值。基本上,我可以使用任何插值,因为我不确定输入采样率是否总是48000。但是,由于48000和16000之间的差异是两倍多,我需要一个过滤器来避免声音失真。在任何情况下,“重新采样”一节就是这样说的。最后,使用系统功能比自制算法更可取。以下是不同格式的列表:
OSStatus connectAudioUnits(AudioUnit source, AudioUnit destination, AudioUnitElement sourceOutput, AudioUnitElement destinationInput) {
        
        AudioUnitConnection connection;
        connection.sourceAudioUnit    = source;
        connection.sourceOutputNumber = sourceOutput;
        connection.destInputNumber    = destinationInput;
        
        return AudioUnitSetProperty (
                                     destination,
                                     kAudioUnitProperty_MakeConnection,
                                     kAudioUnitScope_Input,
                                     destinationInput,
                                     &connection,
                                     sizeof(connection)
                                     );
    }