EZAudio:如何将缓冲区大小与 FFT 窗口大小分开(希望更高的频率 bin 分辨率)。
Posted
技术标签:
【中文标题】EZAudio:如何将缓冲区大小与 FFT 窗口大小分开(希望更高的频率 bin 分辨率)。【英文标题】:EZAudio: How do you separate the buffersize from the FFT window size(desire higher frequency bin resolution). 【发布时间】:2014-05-06 23:40:02 【问题描述】:https://github.com/syedhali/EZAudio
我已经成功使用了这个音频库,但现在我想提高读入的麦克风数据的分辨率,以便 FFT 分辨率或频率箱大小降至 10Hz。为此,我需要 8820 而不是 512 的缓冲区大小。麦克风的缓冲区大小和 FFT 窗口大小是否可分离?我看不出有什么方法可以分开它。
如何设置音频流描述,以便计算更大窗口的 FFT?
任何帮助将不胜感激。
【问题讨论】:
您在一个分析周期中处理的样本数量与频率分辨率有内在联系。要获得更高的分辨率,您需要处理更多的样本。在 FFT 代码的上游,您可以根据需要缓冲任何内容,只要您向 FFT 代码提供所需数量的样本即可。 【参考方案1】:FFT 大小和音频缓冲区大小应该完全独立。您可以只保存多个音频输入缓冲区(可能在循环 FIFO 或队列中),而无需处理它们,直到您有足够的样本来满足您所需的 FFT 长度。
以这种方式保存音频缓冲区还允许您对重叠帧进行 FFT 以获得更多时间分辨率。
【讨论】:
同意,我做了一个非 FIFO 解决方案,它可以工作,但 FIFO 缓冲区对于重叠窗口会更好。【参考方案2】:浏览了链接项目的源代码后,音频回调似乎传递了一个缓冲区大小,该缓冲区大小是麦克风设备的首选缓冲区大小。我建议您在调用 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
是跟踪写入位置的整数进入数组。
另外,我建议您在调用异步委托之前复制缓冲区参数。我之所以这么说是因为查看 EZMicrophone 的源代码,它看起来像是在回收缓冲区,所以你会有一个竞争条件。
【讨论】:
谢谢我修改了这段代码,现在我有一个工作的 FFT 窗口大小可选实现来获得你想要的 FFT res。包含在下面的答案中,因为我无法将其放入此评论部分。【参考方案3】:感谢 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;
);
【讨论】:
你在哪里初始化 dbVal ,_fftBuf,samplesRemaining,lastdbValue 变量。请尽快回复以上是关于EZAudio:如何将缓冲区大小与 FFT 窗口大小分开(希望更高的频率 bin 分辨率)。的主要内容,如果未能解决你的问题,请参考以下文章