Структура входного буфера в AudioUnit - PullRequest
5 голосов
/ 20 мая 2011

Я написал простой аудиоустройство, которое должно поменять местами левый и правый каналы стереофонического источника.Портированная версия этого кода прекрасно работала на C для программы командной строки, которая использовала библиотеку BASS, но у меня возникли проблемы с получением того же кода для работы в Xcode для аудиоустройства.

Для ввода в буфериз, например, {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;
}   
}   
}

1 Ответ

6 голосов
/ 20 мая 2011

Причина, по которой этот код не работает, заключается в том, что вы используете ядра AudioUnit, которые вызывают ваш плагин для обработки одного канала аудиоданных (если я правильно понимаю). Хотя в некоторых случаях ядро ​​может быть довольно удобным, оно определенно не будет работать для плагина, который выполняет взаимозависимую стереофоническую обработку. Вам передают количество каналов в вашем обратном вызове - вы проверили это значение?

Независимо от этого вы должны вместо этого наследовать от класса AUEffectBase и переопределить метод ProcessBufferLists(). Затем вы получите правильную структуру AudioBufferList , которая содержит не чересстрочные буферы для каждого аудиоканала. Это также даст вам гораздо более точный контроль над процессом рендеринга, чем использование ядер.

Редактировать : Ладно, получается, что обратному вызову ядра всегда передается 1 канал аудио. Кроме того, переопределение Render(), как я изначально предлагал, не лучший способ сделать это. Согласно комментарию в исходном коде AUEffectBase.h:

Если ваше устройство обрабатывает от N до N каналов, и нет взаимодействия между каналами, он может переопределить NewKernel для создания монообработанного объекта на канал. Иначе, не переопределяйте NewKernel, а вместо этого переопределяйте ProcessBufferLists.

Поскольку AUEffectBase не является частью "стандартного" кода AudioUnit, вам необходимо добавить файлы cpp / h в ваш проект. Их можно найти в корневом каталоге AudioUnit SDK в папке AudioUnits/AUPublic/OtherBases. Так что для вашего плагина это будет выглядеть примерно так:

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++;
  }
}
...