title: OSX: FFT Analysis AudioUnit
body: <p>i am interested in FFT analysis for mac osx. I have found an tutorial for iOS (<a href="http://demetrimiller.com/2011/01/25/pitch-detection-in-ios-4-x/" rel="nofollow">http://demetrimiller.com/2011/01/25/pitch-detection-in-ios-4-x/</a>) and tried to "port" it to OSX.</p>
  
  <p>I have created a new Xcode-Project, integrated the code and removed the visible bugs. Although is does not work :(</p>
  
  <p>I tried many modifications about the AudioUnit part, but it does not help.</p>
  
  <p><strong>Has anybody an idea what is wrong?
  Thank you very much :)</strong></p>
  
  <p>myView.h</p>
  
  <pre><code>#import &lt;Cocoa/Cocoa.h&gt;
  
  @class RIOInterface;
  
  @interface myView : NSView {
  
  
  BOOL isListening;
  RIOInterface *rioRef;
  
  NSMutableString *key;
  float currentFrequency;
  NSString *prevChar;
  }
  
  @property(nonatomic, retain) NSMutableString *key;
  @property(nonatomic, retain) NSString *prevChar;
  @property(readwrite) RIOInterface *rioRef;
  @property(nonatomic, assign) float currentFrequency;
  @property(assign) BOOL isListening;
  
  
  #pragma mark Listener Controls
  - (IBAction)toggleListening:(id)sender;
  - (void)startListener;
  - (void)stopListener;
  
  - (void)frequencyChangedWithValue:(float)newFrequency;
  - (void)updateFrequencyLabel;
  
  @end
  </code></pre>
  
  <p>myView.m</p>
  
  <pre><code>#import "myView.h"
  #import "RIOInterface.h"
  
  
  @implementation myView
  @synthesize key;
  @synthesize prevChar;
  @synthesize isListening;
  @synthesize rioRef;
  @synthesize currentFrequency;
  
  #pragma mark -
  #pragma mark Listener Controls
  - (void)toggleListening {
  if (isListening) {
      [self stopListener];
  } else {
      [self startListener];
  }
  
  isListening = !isListening;
  }
  
  - (void)startListener {
  [rioRef startListening:self];
  }
  
  - (void)stopListener {
  [rioRef stopListening];
  }
  
  
  
  #pragma mark -
  #pragma mark Lifecycle
  // Implement viewDidLoad to do additional setup after loading the view, typically from a     nib.
  - (void)viewDidLoad {
  rioRef = [RIOInterface sharedInstance];
  [self toggleListening];
  }
  
  -(id)initWithCoder:(NSCoder *)coder
  {
  
  if (self = [super initWithCoder:coder]) {
  
      [self viewDidLoad];
  }
  
  return self;
  }
  
  
  
  @end
  </code></pre>
  
  <p>RIOInterface.h</p>
  
  <pre><code>#import &lt;Foundation/Foundation.h&gt;
  #import &lt;AudioUnit/AudioUnit.h&gt;
  #import &lt;AVFoundation/AVFoundation.h&gt;
  #import &lt;AudioToolbox/AudioToolbox.h&gt;
  #import &lt;Accelerate/Accelerate.h&gt;
  #include &lt;stdlib.h&gt;
  
  @class myView;
  
  /**
   *  This is a singleton class that manages all the low level CoreAudio/RemoteIO
   *  elements. A singleton is used since we should never be instantiating more
   *  than one instance of this class per application lifecycle.
   */
  
  #define kInputBus 1
  #define kOutputBus 0
  #define kBufferSize 1024
  #define kBufferCount 1
  #define N 10
  
  
  @interface RIOInterface : NSObject {
  NSView *selectedViewController;
  myView *listener;
  
  AUGraph processingGraph;
  AudioUnit ioUnit;
  AudioBufferList* bufferList;
  AudioStreamBasicDescription streamFormat;
  
  FFTSetup fftSetup;
  COMPLEX_SPLIT A;
  int log2n, n, nOver2;
  
  void *dataBuffer;
  float *outputBuffer;
  size_t bufferCapacity;  // In samples
  size_t index;   // In samples
  
  float sampleRate;
  float frequency;
  }
  
  @property(nonatomic, assign) id&lt;AVAudioPlayerDelegate&gt; audioPlayerDelegate;
  @property(readwrite) myView *listener;
  
  @property(assign) float sampleRate;
  @property(assign) float frequency;
  
  #pragma mark Lifecycle
  
  #pragma mark Audio Session/Graph Setup
  - (void)initializeAudioSession;
  - (void)createAUProcessingGraph;
  - (size_t)ASBDForSoundMode;
  
  #pragma mark Playback Controls
  - (void)startPlayback;
  - (void)startPlaybackFromEncodedArray:(NSArray *)encodedArray;
  - (void)stopPlayback;
  - (void)printASBD:(AudioStreamBasicDescription)asbd;
  
  #pragma mark Listener Controls
  - (void)startListening:(myView*)aListener;
  - (void)stopListening;
  
  #pragma mark Generic Audio Controls
  - (void)initializeAndStartProcessingGraph;
  - (void)stopProcessingGraph;
  
  #pragma mark Singleton Methods
  + (RIOInterface *)sharedInstance;
  
  @end
  </code></pre>
  
  <p>RIOInterface.m</p>
  
  <pre><code>#import "RIOInterface.h"
  #import "CAStreamBasicDescription.h"
  #import "CAXException.h"
  #import "myView.h"
  
  @implementation RIOInterface
  
  @synthesize listener;
  @synthesize audioPlayerDelegate;
  @synthesize sampleRate;
  @synthesize frequency;
  
  float MagnitudeSquared(float x, float y);
  void ConvertInt16ToFloat(RIOInterface* THIS, void *buf, float *outputBuf, size_t capacity);
  
  #pragma mark -
  #pragma mark Lifecycle
  
  - (void)dealloc {
  if (processingGraph) {
      AUGraphStop(processingGraph);
  }
  
  
  
  }
  
  #pragma mark -
  #pragma mark Playback Controls
  - (void)startPlayback {
  [self createAUProcessingGraph];
  [self initializeAndStartProcessingGraph];
  //AudioOutputUnitStart(ioUnit);
  }
  
  
  - (void)startPlaybackFromEncodedArray:(NSArray *)encodedArray {
  // TODO: once we have our generated array, set up the timer to
  // play the encoded array correctly.
  }
  
  - (void)stopPlayback {
  AUGraphStop(processingGraph);
  //AudioOutputUnitStop(ioUnit);
  }
  
  
  #pragma mark -
  #pragma mark Listener Controls
  - (void)startListening:(myView*)aListener {
  self.listener = aListener;
  [self createAUProcessingGraph];
  [self initializeAndStartProcessingGraph];
  }
  
  
  - (void)stopListening {
  [self stopProcessingGraph];
  }
  
  #pragma mark -
  #pragma mark Generic Audio Controls
  - (void)initializeAndStartProcessingGraph {
  OSStatus result = AUGraphInitialize(processingGraph);
  if (result &gt;= 0) {
      AUGraphStart(processingGraph);
  } else {
      XThrow(result, "error initializing processing graph");
  }
  }
  
  - (void)stopProcessingGraph {
  AUGraphStop(processingGraph);
  }
  
  #pragma mark -
  #pragma mark Audio Rendering
  OSStatus RenderFFTCallback (void                    *inRefCon,
                          AudioUnitRenderActionFlags  *ioActionFlags,
                          const AudioTimeStamp            *inTimeStamp,
                          UInt32                      inBusNumber,
                          UInt32                      inNumberFrames,
                          AudioBufferList             *ioData)
  {
  RIOInterface* THIS = (__bridge RIOInterface *)inRefCon;
  COMPLEX_SPLIT A = THIS-&gt;A;
  void *dataBuffer = THIS-&gt;dataBuffer;
  float *outputBuffer = THIS-&gt;outputBuffer;
  FFTSetup fftSetup = THIS-&gt;fftSetup;
  
  uint32_t log2n = THIS-&gt;log2n;
  uint32_t n = THIS-&gt;n;
  uint32_t nOver2 = THIS-&gt;nOver2;
  uint32_t stride = 1;
  int bufferCapacity = THIS-&gt;bufferCapacity;
  SInt16 index = THIS-&gt;index;
  
  AudioUnit rioUnit = THIS-&gt;ioUnit;
  OSStatus renderErr;
  UInt32 bus1 = 1;
  
  renderErr = AudioUnitRender(rioUnit, ioActionFlags,
                              inTimeStamp, bus1, inNumberFrames, THIS-&gt;bufferList);
  if (renderErr &lt; 0) {
      return renderErr;
  }
  
  // Fill the buffer with our sampled data. If we fill our buffer, run the
  // fft.
  int read = bufferCapacity - index;
  if (read &gt; inNumberFrames) {
      memcpy((SInt16 *)dataBuffer + index, THIS-&gt;bufferList-&gt;mBuffers[0].mData, inNumberFrames*sizeof(SInt16));
      THIS-&gt;index += inNumberFrames;
  } else {
      // If we enter this conditional, our buffer will be filled and we should
      // perform the FFT.
      memcpy((SInt16 *)dataBuffer + index, THIS-&gt;bufferList-&gt;mBuffers[0].mData, read*sizeof(SInt16));
  
      // Reset the index.
      THIS-&gt;index = 0;
  
      /*************** FFT ***************/
      // We want to deal with only floating point values here.
      ConvertInt16ToFloat(THIS, dataBuffer, outputBuffer, bufferCapacity);
  
      /**
       Look at the real signal as an interleaved complex vector by casting it.
       Then call the transformation function vDSP_ctoz to get a split complex
       vector, which for a real signal, divides into an even-odd configuration.
       */
      vDSP_ctoz((COMPLEX*)outputBuffer, 2, &amp;A, 1, nOver2);
  
      // Carry out a Forward FFT transform.
      vDSP_fft_zrip(fftSetup, &amp;A, stride, log2n, FFT_FORWARD);
  
      // The output signal is now in a split real form. Use the vDSP_ztoc to get
      // a split real vector.
      vDSP_ztoc(&amp;A, 1, (COMPLEX *)outputBuffer, 2, nOver2);
  
      // Determine the dominant frequency by taking the magnitude squared and
      // saving the bin which it resides in.
      float dominantFrequency = 0;
      int bin = -1;
      for (int i=0; i&lt;n; i+=2) {
          float curFreq = MagnitudeSquared(outputBuffer[i], outputBuffer[i+1]);
          if (curFreq &gt; dominantFrequency) {
              dominantFrequency = curFreq;
              bin = (i+1)/2;
          }
      }
      memset(outputBuffer, 0, n*sizeof(SInt16));
  
  
      printf("Dominant frequency: %f   bin: %d \n", bin*(THIS-&gt;sampleRate/bufferCapacity), bin);
  }
  
  NSLog(@"hh");
  return noErr;
  }
  
  float MagnitudeSquared(float x, float y) {
  return ((x*x) + (y*y));
  }
  
  void ConvertInt16ToFloat(RIOInterface* THIS, void *buf, float *outputBuf, size_t capacity) {
  AudioConverterRef converter;
  OSStatus err;
  
  size_t bytesPerSample = sizeof(float);
  AudioStreamBasicDescription outFormat = {0};
  outFormat.mFormatID = kAudioFormatLinearPCM;
  outFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
  outFormat.mBitsPerChannel = 8 * bytesPerSample;
  outFormat.mFramesPerPacket = 1;
  outFormat.mChannelsPerFrame = 1;
  outFormat.mBytesPerPacket = bytesPerSample * outFormat.mFramesPerPacket;
  outFormat.mBytesPerFrame = bytesPerSample * outFormat.mChannelsPerFrame;
  outFormat.mSampleRate = THIS-&gt;sampleRate;
  
  const AudioStreamBasicDescription inFormat = THIS-&gt;streamFormat;
  
  UInt32 inSize = capacity*sizeof(SInt16);
  UInt32 outSize = capacity*sizeof(float);
  err = AudioConverterNew(&amp;inFormat, &amp;outFormat, &amp;converter);
  err = AudioConverterConvertBuffer(converter, inSize, buf, &amp;outSize, outputBuf);
  }
  
  /* Setup our FFT */
  - (void)realFFTSetup {
  UInt32 maxFrames = 2048;
  dataBuffer = (void*)malloc(maxFrames * sizeof(SInt16));
  outputBuffer = (float*)malloc(maxFrames *sizeof(float));
  log2n = log2f(maxFrames);
  n = 1 &lt;&lt; log2n;
  assert(n == maxFrames);
  nOver2 = maxFrames/2;
  bufferCapacity = maxFrames;
  index = 0;
  A.realp = (float *)malloc(nOver2 * sizeof(float));
  A.imagp = (float *)malloc(nOver2 * sizeof(float));
  fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
  }
  
  
  #pragma mark -
  #pragma mark Audio Session/Graph Setup
  // Sets up the audio session based on the properties that were set in the init
  // method.
  - (void)initializeAudioSession {
  NSError *err = nil;
      // After activation, update our sample rate. We need to update because there
  // is a possibility the system cannot grant our request.
  
  [self realFFTSetup];
  }
  
  
  // This method will create an AUGraph for either input or output.
  // Our application will never perform both operations simultaneously.
  - (void)createAUProcessingGraph {
  OSStatus err;
  // Configure the search parameters to find the default playback output unit
  // (called the kAudioUnitSubType_RemoteIO on iOS but
  // kAudioUnitSubType_DefaultOutput on Mac OS X)
  AudioComponentDescription ioUnitDescription;
  ioUnitDescription.componentType = kAudioUnitType_Output;
  ioUnitDescription.componentSubType = kAudioUnitSubType_DefaultOutput;
  ioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
  ioUnitDescription.componentFlags = 0;
  ioUnitDescription.componentFlagsMask = 0;
  
  // Declare and instantiate an audio processing graph
  NewAUGraph(&amp;processingGraph);
  
  // Add an audio unit node to the graph, then instantiate the audio unit.
  /*
   An AUNode is an opaque type that represents an audio unit in the context
   of an audio processing graph. You receive a reference to the new audio unit
   instance, in the ioUnit parameter, on output of the AUGraphNodeInfo
   function call.
   */
  AUNode ioNode;
  AUGraphAddNode(processingGraph, &amp;ioUnitDescription, &amp;ioNode);
  
  AUGraphOpen(processingGraph); // indirectly performs audio unit instantiation
  
  // Obtain a reference to the newly-instantiated I/O unit. Each Audio Unit
  // requires its own configuration.
  AUGraphNodeInfo(processingGraph, ioNode, NULL, &amp;ioUnit);
  
  // Initialize below.
  AURenderCallbackStruct callbackStruct = {0};
  UInt32 enableInput;
  UInt32 enableOutput;
  
  // Enable input and disable output.
  enableInput = 1; enableOutput = 0;
  callbackStruct.inputProc = RenderFFTCallback;
  
  err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO,
                             kAudioUnitScope_Input,
                             kInputBus, &amp;enableInput,     sizeof(enableInput));
  
  err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO,
                             kAudioUnitScope_Output,
                             kOutputBus, &amp;enableOutput, sizeof(enableOutput));
  
  err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_SetInputCallback,
                             kAudioUnitScope_Input,
                             kOutputBus, &amp;callbackStruct, sizeof(callbackStruct));
  
  
  // Set the stream format.
  size_t bytesPerSample = [self ASBDForSoundMode];
  
  err = AudioUnitSetProperty(ioUnit, kAudioUnitProperty_StreamFormat,
                             kAudioUnitScope_Output,
                             kInputBus, &amp;streamFormat, sizeof(streamFormat));
  
  err = AudioUnitSetProperty(ioUnit, kAudioUnitProperty_StreamFormat,
                             kAudioUnitScope_Input,
                             kOutputBus, &amp;streamFormat, sizeof(streamFormat));
  
  
  
  
  // Disable system buffer allocation. We'll do it ourselves.
  UInt32 flag = 0;
  err = AudioUnitSetProperty(ioUnit, kAudioUnitProperty_ShouldAllocateBuffer,
                             kAudioUnitScope_Output,
                             kInputBus, &amp;flag, sizeof(flag));
  
  
  // Allocate AudioBuffers for use when listening.
  // TODO: Move into initialization...should only be required once.
  bufferList = (AudioBufferList *)malloc(sizeof(AudioBuffer));
  bufferList-&gt;mNumberBuffers = 1;
  bufferList-&gt;mBuffers[0].mNumberChannels = 1;
  
  bufferList-&gt;mBuffers[0].mDataByteSize = kBufferSize*bytesPerSample;
  bufferList-&gt;mBuffers[0].mData = calloc(kBufferSize, bytesPerSample);
  }
  
  
  // Set the AudioStreamBasicDescription for listening to audio data. Set the
  // stream member var here as well.
  - (size_t)ASBDForSoundMode {
  AudioStreamBasicDescription asbd = {0};
  size_t bytesPerSample;
  bytesPerSample = sizeof(SInt16);
  asbd.mFormatID = kAudioFormatLinearPCM;
  asbd.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
  asbd.mBitsPerChannel = 8 * bytesPerSample;
  asbd.mFramesPerPacket = 1;
  asbd.mChannelsPerFrame = 1;
  asbd.mBytesPerPacket = bytesPerSample * asbd.mFramesPerPacket;
  asbd.mBytesPerFrame = bytesPerSample * asbd.mChannelsPerFrame;
  asbd.mSampleRate = sampleRate;
  
  streamFormat = asbd;
  [self printASBD:streamFormat];
  
  return bytesPerSample;
  }
  
  #pragma mark -
  #pragma mark Utility
  - (void)printASBD:(AudioStreamBasicDescription)asbd {
  
  char formatIDString[5];
  UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID);
  bcopy (&amp;formatID, formatIDString, 4);
  formatIDString[4] = '\0';
  
  NSLog (@"  Sample Rate:         %10.0f",  asbd.mSampleRate);
  NSLog (@"  Format ID:           %10s",    formatIDString);
  NSLog (@"  Format Flags:        %10lX",    asbd.mFormatFlags);
  NSLog (@"  Bytes per Packet:    %10ld",    asbd.mBytesPerPacket);
  NSLog (@"  Frames per Packet:   %10ld",    asbd.mFramesPerPacket);
  NSLog (@"  Bytes per Frame:     %10ld",    asbd.mBytesPerFrame);
  NSLog (@"  Channels per Frame:  %10ld",    asbd.mChannelsPerFrame);
  NSLog (@"  Bits per Channel:    %10ld",    asbd.mBitsPerChannel);
  }
  
  
  
  // *************** Singleton *********************
  
  static RIOInterface *sharedInstance = nil;
  
  #pragma mark -
  #pragma mark Singleton Methods
  + (RIOInterface *)sharedInstance
  {
  if (sharedInstance == nil) {
      sharedInstance = [[RIOInterface alloc] init];
  }
  
  return sharedInstance;
  }
  
  + (id)allocWithZone:(NSZone *)zone {
  @synchronized(self) {
      if (sharedInstance == nil) {
          sharedInstance = [super allocWithZone:zone];
          return sharedInstance;  // assignment and return on first allocation
      }
  }
  return nil; // on subsequent allocation attempts return nil
  }
  
  - (id)copyWithZone:(NSZone *)zone {
  return self;
  }
  
  @end
  </code></pre>