【问题标题】:How to create a chain of audio unit that was AEС, resampling and lowpass filter如何创建一个 AEС、重采样和低通滤波器的音频单元链
【发布时间】:2021-01-06 03:49:57
【问题描述】:

我使用 VoiceProcessingIO 类型的音频单元来接收没有回声的语音。在 RenderCallback 中,我获取声音样本,然后将所有缓冲区值设置为零,这样就不会播放了。 现在我需要在接收到声音后将其采样率从 48000 更改为 16000,然后将生成的声音通过低通滤波器。
我不知道如何配置多个音频单元以相互连接并链接数据。
我知道我必须对转换器使用 kAudioUnitSubType_AUConverter,对过滤器使用 kAudioUnitSubType_LowPassFilter。
我已经迫不及待地想要寻求任何形式的帮助。

附:我找到了这个blog post,有一个类似的问题,但作者从未回答过他的问题。但我不明白作者为什么使用两个转换器。我也担心他使用的是 Remote 类型,我不明白他为什么要按顺序连接这些总线。


public static class SoundSettings 
{
    public static readonly int SampleRate = 16000;
    public static readonly int Channels = 1;
    public static readonly int BytesPerSample = 2;
    public static readonly int FramesPerPacket = 1;
}
private void SetupAudioSession() 
{
    AudioSession.Initialize();
    AudioSession.Category = AudioSessionCategory.PlayAndRecord;
    AudioSession.Mode = AudioSessionMode.GameChat;
    AudioSession.PreferredHardwareIOBufferDuration = 0.08f;
}

private void PrepareAudioUnit() 
{
    _srcFormat = new AudioStreamBasicDescription 
    {
        Format = AudioFormatType.LinearPCM,
        FormatFlags = AudioFormatFlags.LinearPCMIsSignedInteger | 
        AudioFormatFlags.LinearPCMIsPacked,
        SampleRate = AudioSession.CurrentHardwareSampleRate,
        FramesPerPacket = SoundSettings.FramesPerPacket,
        BytesPerFrame = SoundSettings.BytesPerSample * SoundSettings.Channels,
        BytesPerPacket = SoundSettings.FramesPerPacket *
            SoundSettings.BytesPerSample * 
            SoundSettings.Channels,
        BitsPerChannel = SoundSettings.BytesPerSample * 8,
        ChannelsPerFrame = SoundSettings.Channels,
        Reserved = 0
    };

    var audioComponent = AudioComponent.FindComponent(AudioTypeOutput.VoiceProcessingIO);

    _audioUnit = new AudioUnit.AudioUnit(audioComponent);

    _audioUnit.SetEnableIO(true, AudioUnitScopeType.Input, 1);
    _audioUnit.SetEnableIO(true, AudioUnitScopeType.Output, 0);

    _audioUnit.SetFormat(_srcFormat, AudioUnitScopeType.Input, 0);
    _audioUnit.SetFormat(_srcFormat, AudioUnitScopeType.Output, 1);

    _audioUnit.SetRenderCallback(this.RenderCallback, AudioUnitScopeType.Input, 0);
}

private AudioUnitStatus RenderCallback(
    AudioUnitRenderActionFlags actionFlags,
    AudioTimeStamp timeStamp, 
    uint busNumber,
    uint numberFrames, 
    AudioBuffers data)
{
    var status = _audioUnit.Render(ref actionFlags, timeStamp, 1, numberFrames, data);

    if (status != AudioUnitStatus.OK) 
    {
        return status;
    }

    var msgArray = new byte[dataByteSize];
    Marshal.Copy(data[0].Data, msgArray, 0, dataByteSize);

    var msg = _msgFactory.CreateAudioMsg(msgArray, msgArray.Length, (++_lastIndex));
    this.OnMsgReady(msg);

    // Disable playback IO
    var array = new byte[dataByteSize];
    Marshal.Copy(array, 0, data[0].Data, dataByteSize);

    return AudioUnitStatus.NoError;
}

【问题讨论】:

  • 您的音响系统似乎可以处理语音或音乐。首先,您不需要更改采样率,您可以随时添加过滤以获得更低的频率。例如,从 48000 到 16000,您可以简单地每三个样本进行一次。将您想要从一个进程中获取输出并输入到第二个进程的输入中的数据进行实时传输。最简单的方法是创建一个FIFO并使用定时器。
  • 我实现了一个“朴素”的算法来降低采样率。我取了三个样本的平均值。基本上,我可以使用任何插值,因为我不确定输入采样率是否始终为 48000。但是,由于 48000 和 16000 之间的差异是其两倍以上,我需要一个滤波器来避免声音失真。无论如何,这就是article 所说的“重采样”部分。最后,使用系统能力比自制算法更可取。
  • 这里是不同格式的列表:docs.microsoft.com/en-us/dotnet/api/…

标签: c# ios xamarin.ios resampling audiounit


【解决方案1】:

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

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)
                                     );
    }

【讨论】:

    猜你喜欢
    • 2013-08-22
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 2014-10-01
    相关资源
    最近更新 更多