I've written a simple audiounit that should swap the left and right channels of a stereo source. A ported version of this code worked fine in C for a command-line program that used the BASS library, but I'm having trouble getting the same code to work in Xcode for an audiounit.
For a buffer input of, for example, {1, 2, 3, 4, 5, 6}, i would expect the stereo reversal to be {2, 1, 4, 3, 6, 5}.
My code correctly reverses the samples in this manner, but all I hear is some sort of low-pass filtering, rather than a stereo reversal of samples.
The first 4 values in my input buffer are: 0.000104 0.000101 0.000080 0.000113
The output is: 0.000101 0.000104 0.000113 0.000080
Have I misunderstood something about the way the input/output buffers are structured?
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;
}
}
}
The reason that this code isn't working is because you are using AudioUnit kernels, which call your plugin to process a single channel of audio data (if I understand correctly). While kernels can be quite convenient in some cases, it's definitely not going to work for a plugin which does interdependent stereo processing. You are being passed the number of channels in your callback -- have you checked this value?
Regardless, you should instead inherit from the AUEffectBase
class and override the ProcessBufferLists()
method. Then you will get a proper AudioBufferList structure which contains non-interlaced buffers for each audio channel. It will also give you much finer control over the rendering process than using kernels.
Edit: Ok, it turns out that the Kernel callback is always being passed 1 channel of audio. Also, overridding Render()
as I originally suggested is not the best way to do this. According to a comment in the AUEffectBase.h
source code:
If your unit processes N to N channels, and there are no interactions between channels, it can override NewKernel to create a mono processing object per channel. Otherwise, don't override NewKernel, and instead, override ProcessBufferLists.
As AUEffectBase
isn't part of the "standard" AudioUnit code, you will need to add the cpp/h files into your project. They can be found under the AudioUnit SDK root in the AudioUnits/AUPublic/OtherBases
folder. So for your plugin, that would look something like this:
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++;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With