5

我编写了一个简单的音频单元,它应该交换立体声源的左右声道。此代码的移植版本在 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;
}   
}   
}
4

1 回答 1

6

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

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

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

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

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

我的效果.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
};

我的效果.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++;
  }
}
于 2011-05-20T07:23:05.423 回答