代码之家  ›  专栏  ›  技术社区  ›  patrick

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

  •  2
  • patrick  · 技术社区  · 10 年前

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

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

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

    我可以在网上找到的所有与设置音频单元图有关的示例都涉及使用具有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 回复  |  直到 10 年前
        1
  •  1
  •   ruoho ruotsi    10 年前

    我想这是 documentation 你要找的。

    总结一下:设置augraph,设置音频单元&将它们添加到图表中,写&附加 渲染回调 函数。运行图表。注意 渲染回调 是应用程序将被要求向augraph提供样本缓冲区的位置。这是您需要读取缓冲区并填充rendercallback提供的缓冲区的地方。我想这就是你所缺少的。

    如果你使用iOS8,我建议 AVAudioEngine ,这有助于隐藏一些图形和效果的grungier锅炉板细节

    额外费用:

    1. 完成iOS8之前的工作 example code 在github上
    2. 网间网操作系统 Music player app 它将MP3库中的音频读取到循环缓冲区中,然后通过augraph(使用混音器&eq AU)对其进行处理。您可以看到如何设置rendercallback以从缓冲区读取数据等。
    3. Amazing Audio Engine
    4. Novocaine Audio library