iOS的FFT频谱抽奖(iOS FFT Draw spectrum)

2019-08-17 20:50发布

我读过这些问题:

使用苹果FFT和加速框架

如何使用加速框架做一个FFT当我设置了一个缓冲?

iOS的FFT Accerelate.framework回放期间绘制光谱

他们都描述了如何设置FFT与加速框架。 有了他们的帮助,我能够设置FFT和获得一个基本的频谱分析仪。 现在,我在我显示从FFT得到了所有值。 不过,我只想显示10-15,或可变数目,酒吧respreseting某些频率。 就像iTunes或Winamp的液位计。 1.我是否需要平均幅度值在一定范围的频率? 或者他们只是告诉你对特定频率酒吧幅度? 2.另外,我需要将我的幅值到数据库? 3.如何将我的数据映射到一定范围内。 难道我对映射最大分贝范围内为我的声音比特深度? 获取最大价值仓会导致跳最大映射值。

我RenderCallback:

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.));

是给我的一个相当圆润的曲线:

plot1

如果我不转换为DB我可以通过我的10000阵列值乘以绘制,并得到很好的峰。

plot2

我做得完全错误的? 而我怎么来表示可变数量的吧?

Answer 1:

  1. 我需要从一个频率范围内的平均幅度值? 或者他们只是告诉你对特定频率酒吧幅度?

是的,你一定要在整个频带你定义的平均值。 显示只是一个FFT部分是疯狂。

  1. 另外,我需要将我的幅值到数据库?

是:分贝是一个对数刻度。 并非巧合的是,人的听力也可以(大约)对数标度。 因此,该值将绘制在他们面前显得更自然给人类,如果你采取的log 2()的值。

  1. 如何将我的数据映射到一定范围内。 难道我对映射最大分贝范围内为我的声音比特深度? 获取最大价值仓会导致跳最大映射值。

我觉得最简单的事做(概念至少)是你的价值观从任何格式转换为0..1 ,即“规范化,规模化”浮动值。 然后从那里你可以转换,如果有必要,你需要绘制的东西。 例如

SInt16 rawValue = fft[0]; // let's say this comes back as 12990

float scaledValue = rawValue/32767.; // This is MAX_INT for 16-bit;
        // dividing we get .396435438 which is much easier for most people
        // to see conceptually as 39% of our max possible value

float displayValue = log2(scaledValue);

my_fft[0] = displayValue;


文章来源: iOS FFT Draw spectrum