尝试使用样本缓冲区作为输入来设置音频单元图

时间:2015-03-17 00:07:51

标签: core-audio

我正在尝试实现一个简单的音频单元图:

样本缓冲区 - >低通滤波器 - >通用输出

将通用输出复制到新缓冲区中,然后可以进一步处理,保存到磁盘等。

我在网上找到的所有与设置音频单元图有关的例子都涉及使用带有kAudioUnitSubType_AudioFilePlayer作为输入源的生成器...我正在处理已经获取的样本缓冲区,所以这些例子做没有帮助...基于在AudioUnitProperties.h文件中查看,看起来我应该使用的是kAudioUnitSubType_ScheduledSoundPlayer?

我似乎没有太多关于如何解决这个问题的文档,所以我很困惑,希望有人可以帮助我。

为简化起见,我刚开始试图让我的样本缓冲区直接进入系统输出,但我无法完成这项工作......

  #import "EffectMachine.h"
  #import <AudioToolbox/AudioToolbox.h>
  #import "AudioHelpers.h"
  #import "Buffer.h"

  @interface EffectMachine ()
  @property (nonatomic, strong) Buffer *buffer;
  @end

  typedef struct EffectMachineGraph {
      AUGraph   graph;
      AudioUnit input;
      AudioUnit lowpass;
      AudioUnit output;
  } EffectMachineGraph;

  @implementation EffectMachine {
      EffectMachineGraph machine;
  }

  -(instancetype)initWithBuffer:(Buffer *)buffer {
      if (self = [super init]) {
          self.buffer = buffer;

          // buffer is a simple wrapper object that holds two properties:
          // a pointer to the array of samples (as doubles) and the size (number of samples)

      }
      return self;
  }

  -(void)process {
      struct EffectMachineGraph initialized = {0};
      machine = initialized;

      CheckError(NewAUGraph(&machine.graph),
                 "NewAUGraph failed");

      AudioComponentDescription outputCD = {0};
      outputCD.componentType = kAudioUnitType_Output;
      outputCD.componentSubType = kAudioUnitSubType_DefaultOutput;
      outputCD.componentManufacturer = kAudioUnitManufacturer_Apple;

      AUNode outputNode;
      CheckError(AUGraphAddNode(machine.graph,
                                &outputCD,
                                &outputNode),
                 "AUGraphAddNode[kAudioUnitSubType_GenericOutput] failed");

      AudioComponentDescription inputCD = {0};
      inputCD.componentType = kAudioUnitType_Generator;
      inputCD.componentSubType = kAudioUnitSubType_ScheduledSoundPlayer;
      inputCD.componentManufacturer = kAudioUnitManufacturer_Apple;

      AUNode inputNode;
      CheckError(AUGraphAddNode(machine.graph,
                                &inputCD,
                                &inputNode),
                 "AUGraphAddNode[kAudioUnitSubType_ScheduledSoundPlayer] failed");

      CheckError(AUGraphOpen(machine.graph),
                 "AUGraphOpen failed");

      CheckError(AUGraphNodeInfo(machine.graph,
                                 inputNode,
                                 NULL,
                                 &machine.input),
                 "AUGraphNodeInfo failed");

      CheckError(AUGraphConnectNodeInput(machine.graph,
                                         inputNode,
                                         0,
                                         outputNode,
                                         0),
                 "AUGraphConnectNodeInput");

      CheckError(AUGraphInitialize(machine.graph),
                 "AUGraphInitialize failed");

      // prepare input

      AudioBufferList ioData = {0};
      ioData.mNumberBuffers = 1;
      ioData.mBuffers[0].mNumberChannels = 1;
      ioData.mBuffers[0].mDataByteSize = (UInt32)(2 * self.buffer.size);
      ioData.mBuffers[0].mData = self.buffer.samples;

      ScheduledAudioSlice slice = {0};
      AudioTimeStamp timeStamp  = {0};

      slice.mTimeStamp    = timeStamp;
      slice.mNumberFrames = (UInt32)self.buffer.size;
      slice.mBufferList   = &ioData;

      CheckError(AudioUnitSetProperty(machine.input,
                                      kAudioUnitProperty_ScheduleAudioSlice,
                                      kAudioUnitScope_Global,
                                      0,
                                      &slice,
                                      sizeof(slice)),
                 "AudioUnitSetProperty[kAudioUnitProperty_ScheduleStartTimeStamp] failed");

      AudioTimeStamp startTimeStamp = {0};
      startTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
      startTimeStamp.mSampleTime = -1;

      CheckError(AudioUnitSetProperty(machine.input,
                                      kAudioUnitProperty_ScheduleStartTimeStamp,
                                      kAudioUnitScope_Global,
                                      0,
                                      &startTimeStamp,
                                      sizeof(startTimeStamp)),
                 "AudioUnitSetProperty[kAudioUnitProperty_ScheduleStartTimeStamp] failed");

      CheckError(AUGraphStart(machine.graph),
                 "AUGraphStart failed");

  //    AUGraphStop(machine.graph);  <-- commented out to make sure it wasn't stopping before actually finishing playing.
  //    AUGraphUninitialize(machine.graph);
  //    AUGraphClose(machine.graph);

  }

有谁知道我在这里做错了什么?

1 个答案:

答案 0 :(得分:1)

我认为这是您正在寻找的documentation

总结一下:设置你的augraph,设置你的音频单元&amp;将它们添加到图表中,写入&amp;在图表的第一个节点上附加 rendercallback 函数。运行图表。请注意, rendercallback 是您的应用程序将被要求向augraph提供样本缓冲区的位置。这是您需要从缓冲区读取并填充rendercallback提供的缓冲区的地方。我认为这就是你所缺少的。

如果您使用的是iOS8,我建议使用AVAudioEngine,这有助于隐藏图形和效果的一些较为复杂的锅炉平台细节

附加功能:

  1. 在github
  2. 上完成iOS8之前的example code
  3. iOS Music player app,它将MP3库中的音频读入循环缓冲区,然后通过augraph(使用混音器和eq AU)处理它。您可以看到如何设置rendercallback以从缓冲区等读取
  4. Amazing Audio Engine
  5. Novocaine Audio library