Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input buffer structure in an AudioUnit

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;
}   
}   
}
like image 626
JimmyB Avatar asked May 19 '11 23:05

JimmyB


1 Answers

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++;
  }
}
like image 173
Nik Reiman Avatar answered Sep 21 '22 12:09

Nik Reiman