音频单元中的输入缓冲区结构
Input buffer structure in an AudioUnit
我写了一个简单的音频单元,应该交换立体声源的左右声道。对于使用 BASS 库的命令行程序,此代码的移植版本在 C 中运行良好,但我无法让相同的代码在 Xcode 中用于音频单元。
对于例如 {1, 2, 3, 4, 5, 6}的缓冲区输入,我希望立体声反转为 {2, 1, 4, 3, 6, 5}。
我的代码以这种方式正确地反转了样本,但我听到的只是某种低通滤波,而不是样本的立体声反转。
我的输入缓冲区中的前 4 个值是:0.0001040.0001010.0000800.000113
输出为:0.0001010.0001040.0001130.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;
}
}
}
这段代码不起作用的原因是因为您使用的是 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
};
我的效应.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++;
}
}
- 从返回的顶点缓冲区查询顶点结构
- struct.error:解压缩 C++ 结构时,解包需要 288 字节的缓冲区
- C++:使用缓冲区中的数据填充结构
- 创建一个结构的关联数组,以创建一个缓冲区,供键快速访问
- 将结构数据存储在循环缓冲区中
- 在缓冲区/数组中使用颜色结构
- 如何通过解析缓冲区并将数据放入正确的结构来处理传入的数据包连接?
- 如何从平面缓冲区中反序列化联合结构的 void* 值的大小
- 多线程和共享资源:使用C++定期将数据从缓冲区(数据结构)复制到文件
- 将不相邻的内存缓冲区视为连续缓冲区的数据结构
- 将包含位字段和动态数据的结构复制到 Char 数组缓冲区中
- 从本机C++结构构建时,是否可以优化平面缓冲区序列化
- 将缓冲区数据解析为结构
- 尝试使用结构在C++中创建循环缓冲区
- 将缓冲区写入结构似乎没有起作用
- 将DER编码的X509证书缓冲区转换为Windows cert_context结构
- C++中的Google协议缓冲区:从现有结构中创建消息
- 在amd64体系结构上的C++中,将图像缓冲区blit到另一个缓冲区的xy偏移中的最快方法
- C/C++ 从字符缓冲区读取以填充结构
- 音频单元中的输入缓冲区结构