EZAudio:如何将缓冲区大小与FFT窗口大小分开(需要更高频率的分辨率)。

时间:2014-05-06 23:40:03

标签: ios objective-c audio fft

https://github.com/syedhali/EZAudio

我已成功使用此音频库,但现在我想提高读入的麦克风数据的分辨率,以便FFT分辨率或频率仓大小下降到10Hz。为此,我需要8820而不是512的缓冲区大小。麦克风的缓冲区大小和FFT窗口大小是否可分离?我无法找到分开它的方法。

如何设置音频流描述,以便用更大的窗口计算FFT?

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:1)

FFT大小和音频缓冲区大小应完全独立。您可以保存多个音频输入缓冲区(可能在循环FIFO或队列中),无需处理它们,直到您有足够的样本用于所需长度的FFT。

以这种方式保存音频缓冲区还允许您对重叠帧进行FFT以获得更多时间分辨率。

答案 1 :(得分:0)

浏览了链接项目的源后,似乎音频回调传递的缓冲区大小是麦克风设备的首选缓冲区大小。我建议你在调用FFT之前缓冲所需数量的样本。以下代码是在EZAudioFFTExample:

中的FFTViewController.m中修改的
#pragma mark - EZMicrophoneDelegate
-(void)    microphone:(EZMicrophone *)microphone
     hasAudioReceived:(float **)buffer
       withBufferSize:(UInt32)bufferSize
 withNumberOfChannels:(UInt32)numberOfChannels {
  dispatch_async(dispatch_get_main_queue(), ^{

    // Update time domain plot
    [self.audioPlotTime updateBuffer:buffer[0]
                      withBufferSize:bufferSize];

    // Setup the FFT if it's not already setup
    if( !_isFFTSetup ){
      [self createFFTWithBufferSize:bufferSize withAudioData:buffer[0]];
      _isFFTSetup = YES;
    }

    int samplesRemaining = bufferSize;
    while (samplesRemaining > 0)
    {
        int samplestoCopy = max(bufferSize, FFTLEN - _fftBufIndex);
        memcpy(_fftBuf, buffer[0], samplesToCopy*sizeof(float));       
        _fftBufIndex += samplesToCopy;
        samplesRemaining -= samplesToCopy;

        if (_fftBufIndex == FFTLEN)
        {
            _fftBufIndex = 0;
            [self updateFFTWithBufferSize:FFTLEN withAudioData:_fftBuf];
        }
    }
  });
 }

在修改后的程序中,FFTLEN是您定义的值,_fftBuf是您分配的浮点数组,需要保存FFTLEN个元素,_fftBufIndex是一个整数,用于跟踪数组中的写入位置。

另外,我建议你在调用异步委托之前复制一个buffer参数。我说这个的原因是因为查看EZMicrophone的来源,它看起来像是在回收缓冲区,所以你会遇到竞争条件。

答案 2 :(得分:0)

感谢Jaket的建议。缓冲是可行的方法,现在这是我使用可调FFT窗口的同一功能的工作实现:

    -(void)microphone:(EZMicrophone *)microphone
            hasAudioReceived:(float **)buffer
            withBufferSize:(UInt32)bufferSize
            withNumberOfChannels:(UInt32)numberOfChannels {

dispatch_async(dispatch_get_main_queue(),^{

    [self.audioPlot updateBuffer:buffer[0] withBufferSize:bufferSize];

    // Decibel Calculation.
    float one       = 1.0;
    float meanVal   = 0.0;
    float tiny      = 0.1;
    vDSP_vsq(buffer[0], 1, buffer[0], 1, bufferSize);
    vDSP_meanv(buffer[0], 1, &meanVal, bufferSize);
    vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0);
    // Exponential moving average to dB level to only get continous sounds.
    float currentdb = 1.0 - (fabs(meanVal)/100);
    if (lastdbValue == INFINITY || lastdbValue == -INFINITY || isnan(lastdbValue)) {
        lastdbValue = 0.0;
    }
    dbValue =   ((1.0 - tiny)*lastdbValue) + tiny*currentdb;
    lastdbValue = dbValue;
    // NSLog(@"dbval:  %f",dbValue);
    //
    // Setup the FFT if it's not already setup
    int samplestoCopy = fmin(bufferSize, FFTLEN - _fftBufIndex);
    for ( size_t i = 0; i < samplestoCopy; i++ ) {
        _fftBuf[_fftBufIndex+i] = buffer[0][i];
    }
    _fftBufIndex        += samplestoCopy;
   _samplesRemaining    -= samplestoCopy;
    if (_fftBufIndex == FFTLEN) {
        if( !_isFFTSetup ){
            [self createFFTWithBufferSize:FFTLEN withAudioData:_fftBuf];
            _isFFTSetup = YES;
        }
        [self updateFFTWithBufferSize:FFTLEN withAudioData:_fftBuf];
        _fftBufIndex        = 0;
        _samplesRemaining   = FFTLEN;
    } 
});  

}