【问题标题】:Input buffer structure in an AudioUnitAudioUnit 中的输入缓冲区结构
【发布时间】:2011-05-19 23:58:26
【问题描述】:

我编写了一个简单的音频单元,可以交换立体声源的左右声道。此代码的移植版本在 C 中适用于使用 BASS 库的命令行程序,但我无法在 Xcode 中为 audiounit 使用相同的代码。

对于例如 {1, 2, 3, 4, 5, 6} 的缓冲区输入,我希望立体声反转为 {2, 1, 4, 3, 6, 5}。

我的代码以这种方式正确地反转了样本,但我听到的只是某种低通滤波,而不是样本的立体声反转。

我的输入缓冲区中的前 4 个值是: 0.000104 0.000101 0.000080 0.000113

输出是: 0.000101 0.000104 0.000113 0.000080

我是否误解了输入/输出缓冲区的结构方式?

void        First::FirstKernel::Process(    const Float32   *inSourceP,
                                                Float32         *inDestP,
                                                UInt32          inSamplesToProcess,
                                                UInt32          inNumChannels, 
                                                bool            &ioSilence )
{


if (!ioSilence) {                                                 

    const Float32 *sourceP = inSourceP;  
    Float32  *destP = inDestP;  
    for (int i = inSamplesToProcess/2; i>0; --i) { 


        *(destP+1) = *sourceP;
        *destP = *(sourceP+1);

        sourceP = sourceP +2;
        destP = destP +2;
}   
}   
}

【问题讨论】:

    标签: c++ xcode audio buffer audiounit


    【解决方案1】:

    此代码不起作用的原因是因为您使用的是 AudioUnit 内核,它调用您的插件来处理单通道音频数据(如果我理解正确的话)。虽然内核在某些情况下可能非常方便,但它绝对不适用于执行相互依赖的立体声处理的插件。您在回调中被传递了通道数——您检查过这个值吗?

    无论如何,您应该从AUEffectBase 类继承并覆盖ProcessBufferLists() 方法。然后你会得到一个正确的AudioBufferList 结构,其中包含每个音频通道的非隔行缓冲区。与使用内核相比,它还可以让您更好地控制渲染过程。

    编辑:好的,事实证明内核回调总是被传递 1 个音频通道。此外,按照我最初的建议覆盖 Render() 并不是最好的方法。根据AUEffectBase.h源代码中的评论:

    如果您的单元处理 N 到 N 个通道,并且通道之间没有交互, 它可以覆盖 NewKernel 来为每个通道创建一个单声道处理对象。除此以外, 不要覆盖 NewKernel,而是覆盖 ProcessBufferLists。

    由于AUEffectBase 不是“标准”AudioUnit 代码的一部分,您需要将 cpp/h 文件添加到您的项目中。它们可以在 AudioUnits/AUPublic/OtherBases 文件夹中的 AudioUnit SDK 根目录下找到。所以对于你的插件,它看起来像这样:

    MyEffect.h:

    #include "AUEffectBase.h"
    
    class MyEffect : public AUEffectBase {
    public:
      // Constructor, other overridden methods, etc.
      virtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags &ioActionFlags,
                                          const AudioBufferList &inBuffer,
                                          AudioBufferList &outBuffer,
                                          UInt32 inFramesToProcess);
    
    
    private:
      // Private member variables, methods
    };
    

    MyEffect.cpp:

    // Other stuff ....
    
    OSStatus MyEffect::ProcessBufferLists(AudioUnitRenderActionFlags &ioActionFlags,
                                          const AudioBufferList &inBuffer,
                                          AudioBufferList &outBuffer,
                                          UInt32 inFramesToProcess) {
      const float *srcBufferL = (Float32 *)inBuffer.mBuffers[0].mData;
      const float *srcBufferR = (Float32 *)inBuffer.mBuffers[1].mData;
      float *destBufferL = (Float32 *)outBuffer.mBuffers[0].mData;
      float *destBufferR = (Float32 *)outBuffer.mBuffers[1].mData;
    
      for(UInt32 frame = 0; frame < inFramesToProcess; ++frame) {
        *destBufferL++ = *srcBufferL++;
        *destBufferR++ = *srcBufferR++;
      }
    }
    

    【讨论】:

    • 谢谢!经过一番努力,我设法发现了一系列论坛帖子,其中有遇到同样问题的人,主要是因为苹果给出的 AU 示例不是立体声处理器。谢谢您的帮助!不过,我仍然无法覆盖 Render();自从我深入研究这种事情以来已经有一段时间了,我有点生疏了。首先,在头文件中,我定义了一个名为 Render 的虚拟函数,它采用与 AUEffectBase 中相同的参数。然后,在我的 cpp 文件中,我构建了渲染函数“First::Render”,它调用了 Process 函数……这是正确的过程吗?
    • 顺便说一句,在当前版本的 AudioUnits 中,inNumChannels 始终为 1;我认为它可以为未来版本的开发留出空间。
    • @JimmyB 是的,事实证明,正如我所怀疑的那样,内核严格用于 N-N 处理。我在答案中添加了更多信息和示例代码以反映这一点。希望这对您有所帮助,如果解决了问题,请不要忘记将答案标记为正确!
    • 如果不以这种方式覆盖这些方法,每个通道都会实例化一个单独的内核,对吗?在一个单独的项目中,我正在尝试实现一个双二阶滤波器(通道之间没有交互),它只是给了我一个奇怪的环形调制器效果。我使用 BASS 库在 C 中编写的前一个过滤器工作得很好,但只有一个交错样本通道。我认为我需要更好地了解 AU 如何处理数据,然后再继续进行……如果您有任何关于这些方面的信息,我将非常感激!再次感谢!
    • @JimmyB Kernels 是一个方便的 N-N 处理框架,构建在 AudioUnits 之上,但您不必使用它们。如果您有其他问题,您应该提出一个新问题。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    相关资源
    最近更新 更多