Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FFT output with float buffer AudioUnit

I have a problem with vDSP_zrip & AudioUnit usage and configuration. In fact I configured AudioUnit to save packed data as float. I create a circular buffer and when this buffer is full I calculate an fft. I have a result but I don't understand why fft ouput is bad (cf figure)

AudioUnit configuration :

// describe format
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate       = 44100;
audioFormat.mFormatID         = kAudioFormatLinearPCM;
audioFormat.mFormatFlags      = kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsPacked|kAudioFormatFlagIsFloat|kAudioFormatFlagIsNonInterleaved;
audioFormat.mFramesPerPacket  = 1;
audioFormat.mChannelsPerFrame = 1; // mono
audioFormat.mBitsPerChannel   = sizeof(float) * 8;
audioFormat.mBytesPerFrame    = audioFormat.mChannelsPerFrame * sizeof(float);
audioFormat.mBytesPerPacket   = audioFormat.mFramesPerPacket * audioFormat.mBytesPerFrame;

Circular buffer:

_audioSample = new AudioSample(8192, 44100);
// in recording callback :
for(int i = 0; i < bufferList.mNumberBuffers; ++i)
{
    if(!status)
    {
        if(_sample->needData())
            _sample->put((float*)bufferList.mBuffers[i].mData,
                    bufferList.mBuffers[i].mDataByteSize);
        [...]
    }
}

vDSP call :

  // get a split complex vector (real signal divided into an even-odd config
  vDSP_ctoz((COMPLEX *)sample.get(), 2, &_complex, 1, _fftsize);
  vDSP_fft_zrip(_fftsetup, &_complex, 1, _log2n, kFFTDirection_Forward);
  // scale (from vDSP reference)
  float scale = 1.0 / (2.0 * _samples);
  vDSP_vsmul(_complex.realp, 1, &scale, _complex.realp, 1, _fftsize);
  vDSP_vsmul(_complex.imagp, 1, &scale, _complex.imagp, 1, _fftsize);
  _complex.imagp[0] = 0.0;

where _fftsize = _audioSample.capacity()/2

figure

like image 277
xunien Avatar asked Jan 15 '23 11:01

xunien


1 Answers

Your output looks pretty reasonable, so I'm going to interpret your question as more of a "How do I clean up these results?"

1) You're probably using a rectangular window

This means that you're not doing any windowing, which will introduce some noise into your results. vDSP comes with some functions for performing windowing, which you can use like this:

// N = number of samples in your buffer
int N = _audioSample.capacity();

// allocate space for a hamming window
float * hammingWindow = (float *) malloc(sizeof(float) * N);

// generate the window values and store them in the hamming window buffer
vDSP_hamm_window(hammingWindow, N, 0);

Then, whenever you're about to do your FFT, window your samples first (as in, do this before your vDSP_ctoz call) :

 vDSP_vmul(sample.get(), 1, hammingWindow, 1, sample.get(), 1, N);

2) You might want to run a magnitude function on your results

This will give you results similar to those you'd see in a standard FFT bar graph music visualizer thing. Do this after the FFT:

vDSP_zvmags(&_complex, 1, &_complex.realp, 1, _fftsize);

After that, _complex.realp will be an array of float values representing the magnitude of each FFT bin.

like image 143
admsyn Avatar answered Jan 28 '23 04:01

admsyn