iOS FFT Accerelate.framework在播放期间绘制频谱

ben*_*wig 14 fft frequency spectrum ios

更新2016-03-15

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


我做了很多研究,并学到了很多关于FFT和Accelerate Framework的知识.但经过几天的实验,我有点沮丧.

我想在图表中播放期间显示音频文件的频谱.对于每个时间间隔,它应该在X轴上通过FFT计算的每个频率(在我的情况下为512个值)显示Y轴上的数值(由红色条显示).

输出应如下所示: 在此输入图像描述

我用1024个样本填充缓冲区,仅为开头提取左侧通道.然后我做所有这些FFT的东西.

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

设置一些变量

- (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);  
}
Run Code Online (Sandbox Code Playgroud)

做FFT.FrequencyArray只是一个包含512个浮点值的数据结构.

- (FrequencyArry)performFastFourierTransformForSampleData:(SInt16*)sampleData andSampleRate:(UInt16)sampleRate   
{  
    NSLog(@"log2n %i n %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;  
}
Run Code Online (Sandbox Code Playgroud)

输出看起来总是有点奇怪,虽然它看起来像是根据音乐移动.

我很高兴我到目前为止感谢这里有一些非常好的帖子: 使用apple FFT和加速Framework

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

Pau*_*l R 15

首先,你没有在FFT之前应用窗口函数 - 这将导致由于频谱泄漏导致的光谱模糊.

其次,您只是使用FFT输出箱的实部来计算dB幅度 - 您需要使用复杂的幅度:

magnitude_dB = 10 * log10(re * re + im * im);
Run Code Online (Sandbox Code Playgroud)

  • vDSP_zvmags(&A,1,obtainReal,1,nOver2); 得到相同的结果 (2认同)