我读过这些问题:
使用 Accelerate 框架进行 FFT 时如何设置缓冲区?
iOS FFT Accelelate.framework 在播放期间绘制频谱
它们都描述了如何使用加速框架设置 fft。在他们的帮助下,我能够设置 fft 并获得基本的频谱分析仪。现在,我正在显示从 fft 获得的所有值。但是,我只想显示 10 到 15 个或可变数量的条来表示某些频率。就像 iTunes 或 WinAmp 电平表一样。1. 我是否需要对一系列频率的幅度值进行平均?还是它们只是向您显示特定频率条的幅度?2. 另外,我需要将幅度值转换为 db 吗?3. 如何将我的数据映射到某个范围。我是否映射到我的声音位深度的最大分贝范围?获取 bin 的最大值将导致最大映射值跳跃。
我的渲染回调:
static OSStatus PlaybackCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
UInt32 maxSamples = kAudioBufferNumFrames;
UInt32 log2n = log2f(maxSamples); //bins
UInt32 n = 1 << log2n;
UInt32 stride = 1;
UInt32 nOver2 = n/2;
COMPLEX_SPLIT A;
float *originalReal, *obtainedReal, *frequencyArray, *window, *in_real;
in_real = (float *) malloc(maxSamples * sizeof(float));
A.realp = (float *) malloc(nOver2 * sizeof(float));
A.imagp = (float *) malloc(nOver2 * sizeof(float));
memset(A.imagp, 0, nOver2 * sizeof(float));
obtainedReal = (float *) malloc(n * sizeof(float));
originalReal = (float *) malloc(n * sizeof(float));
frequencyArray = (float *) malloc(n * sizeof(float));
//-- window
UInt32 windowSize = maxSamples;
window = (float *) malloc(windowSize * sizeof(float));
memset(window, 0, windowSize * sizeof(float));
// vDSP_hann_window(window, windowSize, vDSP_HANN_DENORM);
vDSP_blkman_window(window, windowSize, 0);
vDSP_vmul(ioBuffer, 1, window, 1, in_real, 1, maxSamples);
//-- window
vDSP_ctoz((COMPLEX*)in_real, 2, &A, 1, maxSamples/2);
vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);
vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE);
float scale = (float) 1.0 / (2 * n);
vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2);
vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2);
vDSP_ztoc(&A, 1, (COMPLEX *) obtainedReal, 2, nOver2);
vDSP_zvmags(&A, 1, obtainedReal, 1, nOver2);
Float32 one = 1;
vDSP_vdbcon(obtainedReal, 1, &one, obtainedReal, 1, nOver2, 0);
for (int i = 0; i < nOver2; i++) {
frequencyArray[i] = obtainedReal[i];
}
// Extract the maximum value
double fftMax = 0.0;
vDSP_maxmgvD((double *)obtainedReal, 1, &fftMax, nOver2);
float max = sqrt(fftMax);
}
播放一些音乐,我得到从 -96db 到 0db 的值。在以下位置绘制一个点:
CGPointMake(i, kMaxSpectrumHeight * (1 - frequencyArray[i]/-96.));
给了我一个相当圆润的曲线:
如果我不转换为 db,我可以通过将我的数组值乘以 10000 来绘制并获得漂亮的峰值。
我做错了什么吗?以及如何显示可变数量的条?