https://github.com/syedhali/EZAudio
我已成功使用此音频库,但现在我想提高读入的麦克风数据的分辨率,以便FFT分辨率或频率仓大小下降到10Hz。为此,我需要8820而不是512的缓冲区大小。麦克风的缓冲区大小和FFT窗口大小是否可分离?我无法找到分开它的方法。
如何设置音频流描述,以便用更大的窗口计算FFT?
非常感谢任何帮助。
答案 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;
}
});
}