在播放过程中使用iOS FFT Accerelate.framework绘制频谱

更新2016-03-15

请看看这个项目: https : //github.com/ooper-shlab/aurioTouch2.0-Swift 。 它已被移植到Swift,包含你正在寻找的每一个答案,如果你在这里拍摄。


我做了大量的研究,并学习了很多关于FFT和Accelerate Framework的内容。 但经过几天的实验,我有点沮丧。

我想在图表中播放时显示audio文件的频谱。 对于每个时间间隔,应该在X轴上显示每个频率(在本例中为512个值)的Y轴上的数值(以红色条显示)。

输出应该是这样的: 在这里输入图像说明

我用1024个样本填充一个缓冲区,只提取开始时的左声道。 然后我做所有这些FFT的东西。

这是我的代码到目前为止:

设置一些variables

- (void)setupVars { maxSamples = 1024; log2n = log2f(maxSamples); n = 1 << log2n; stride = 1; nOver2 = maxSamples/2; 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)); setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2); } 

做FFT。 FrequencyArray只是一个保存512个浮点值的数据结构。

 - (FrequencyArry)performFastFourierTransformForSampleData:(SInt16*)sampleData andSampleRate:(UInt16)sampleRate { NSLog(@"log2n %in %i, nOver2 %i", log2n, n, nOver2); // n = 1024 // log2n 10 // nOver2 = 512 for (int i = 0; i < n; i++) { originalReal[i] = (float) sampleData[i]; } vDSP_ctoz((COMPLEX *) originalReal, 2, &A, 1, nOver2); vDSP_fft_zrip(setupReal, &A, stride, log2n, FFT_FORWARD); 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); FrequencyArry frequencyArray; for (int i = 0; i < nOver2; i++) { frequencyArray.frequency[i] = log10f(obtainedReal[i]); // Magnitude in db??? } return frequencyArray; } 

输出看起来总是有点奇怪,虽然它似乎是如何根据音乐移动。

我很高兴我到目前为止,感谢这样一些非常好的post: 使用苹果FFT和加速框架

但是现在我不知道该怎么做。 我错过了什么?

首先,在FFT之前没有应用窗函数 – 这将导致由于频谱泄漏导致的频谱模糊。

其次,您只是使用FFT输出分箱的实际分量来计算dB量级 – 您需要使用复杂的量值:

 magnitude_dB = 10 * log10(re * re + im * im); 
Interesting Posts