从iPhone上的音频流获取Hz频率

从iPhone上的音频流获取Hz频率,iphone,ios,audio,core-audio,fft,Iphone,Ios,Audio,Core Audio,Fft,在iOS上从音频流(音乐)中获取Hz频率值的最佳方法是什么?苹果提供的最好、最简单的框架是什么。提前感谢。苹果没有提供频率或基音估计框架。然而,iOS Accelerate框架确实包含FFT和自相关例程,这些例程可以用作更复杂的频率和基音识别或估计算法的组件 除了几乎零噪声中的单个长连续恒定频率纯正弦音调外,没有一种方法既简单又最好,其中长窗FFT的插值幅度峰值可能是合适的。对于声音和音乐,这种简单的方法通常根本不起作用。但是,对基音检测或估计方法的研究会发现许多关于更合适的算法的研究论文。像这

在iOS上从音频流(音乐)中获取Hz频率值的最佳方法是什么?苹果提供的最好、最简单的框架是什么。提前感谢。

苹果没有提供频率或基音估计框架。然而,iOS Accelerate框架确实包含FFT和自相关例程,这些例程可以用作更复杂的频率和基音识别或估计算法的组件


除了几乎零噪声中的单个长连续恒定频率纯正弦音调外,没有一种方法既简单又最好,其中长窗FFT的插值幅度峰值可能是合适的。对于声音和音乐,这种简单的方法通常根本不起作用。但是,对基音检测或估计方法的研究会发现许多关于更合适的算法的研究论文。

像这样的问题在这里被问了很多。(我已经回答了一个类似的问题)所以我写了一个小教程,里面的代码你甚至可以在商业和封闭源码的应用程序中使用。这不一定是最好的方式,但这是许多人理解的方式。您必须根据您所说的“每个短音乐片段的Hz平均值”对其进行修改。例如,你是指基音节还是频率质心

正如另一个答案所建议的那样,您可能希望在accelerate框架中使用Apple的FFT

希望能有帮助


以下是我使用Accelerate框架在iOS中执行FFT的一些代码,这使它非常快

//keep all internal stuff inside this struct
    typedef struct FFTHelperRef {
        FFTSetup fftSetup; // Accelerate opaque type that contains setup information for a given FFT transform.
        COMPLEX_SPLIT complexA; // Accelerate type for complex number
        Float32 *outFFTData; // Your fft output data
        Float32 *invertedCheckData; // This thing is to verify correctness of output. Compare it with input.
    } FFTHelperRef;
//首先-使用此函数初始化FFTHelperRef

FFTHelperRef * FFTHelperCreate(long numberOfSamples) {

    FFTHelperRef *helperRef = (FFTHelperRef*) malloc(sizeof(FFTHelperRef));
    vDSP_Length log2n = log2f(numberOfSamples);    
    helperRef->fftSetup = vDSP_create_fftsetup(log2n, FFT_RADIX2);
    int nOver2 = numberOfSamples/2;
    helperRef->complexA.realp = (Float32*) malloc(nOver2*sizeof(Float32) );
    helperRef->complexA.imagp = (Float32*) malloc(nOver2*sizeof(Float32) );

    helperRef->outFFTData = (Float32 *) malloc(nOver2*sizeof(Float32) );
    memset(helperRef->outFFTData, 0, nOver2*sizeof(Float32) );

    helperRef->invertedCheckData = (Float32*) malloc(numberOfSamples*sizeof(Float32) );

    return  helperRef;
}
//在此传递初始化的FFTHelperRef、数据和数据大小。返回大小为numSamples/2的FFT数据

Float32 * computeFFT(FFTHelperRef *fftHelperRef, Float32 *timeDomainData, long numSamples) {
    vDSP_Length log2n = log2f(numSamples);
    Float32 mFFTNormFactor = 1.0/(2*numSamples);

    //Convert float array of reals samples to COMPLEX_SPLIT array A
    vDSP_ctoz((COMPLEX*)timeDomainData, 2, &(fftHelperRef->complexA), 1, numSamples/2);

    //Perform FFT using fftSetup and A
    //Results are returned in A
    vDSP_fft_zrip(fftHelperRef->fftSetup, &(fftHelperRef->complexA), 1, log2n, FFT_FORWARD);

    //scale fft 
    vDSP_vsmul(fftHelperRef->complexA.realp, 1, &mFFTNormFactor, fftHelperRef->complexA.realp, 1, numSamples/2);
    vDSP_vsmul(fftHelperRef->complexA.imagp, 1, &mFFTNormFactor, fftHelperRef->complexA.imagp, 1, numSamples/2);

    vDSP_zvmags(&(fftHelperRef->complexA), 1, fftHelperRef->outFFTData, 1, numSamples/2);

    //to check everything =============================
    vDSP_fft_zrip(fftHelperRef->fftSetup, &(fftHelperRef->complexA), 1, log2n, FFT_INVERSE);
    vDSP_ztoc( &(fftHelperRef->complexA), 1, (COMPLEX *) fftHelperRef->invertedCheckData , 2, numSamples/2);
    //=================================================    

    return fftHelperRef->outFFTData;
}
像这样使用它:

  • 初始化它:FFTHelperCreate(TimeDomainDataLength)

  • 传递Float32时域数据,返回时获取频域数据:Float32*fftData=computeFFT(fftHelper,buffer,frameSize)

  • 现在有了一个数组,其中索引=频率,值=幅值(平方幅值?)。 根据你的估计,这个阵列中的最大可能频率是你采样率的一半。也就是说,如果采样率=44100,则可以编码的最大频率为22050 Hz

    因此,找到采样率的Nyquist最大频率:const Float32 NyquistMaxFreq=sample_rate/2.0

    找到Hz很容易:Float32 Hz=((Float32)someIndex/(Float32)fftDataSize)*NyquistMaxFreq (fftDataSize=frameSize/2.0)

    这对我有用。如果我在Audacity中生成特定的频率并播放它,那么这段代码将检测到正确的频率(最强的频率,您还需要在fftData中找到max来执行此操作)

    (仍有大约1-2%的不匹配。不确定为什么会发生这种情况。如果有人能解释原因,我将不胜感激。)

    编辑:

    这种不匹配的发生是因为我用于FFT的片段太小。使用更大的时域数据块(16384帧)解决了这个问题。 这个问题解释了这一点:

    编辑:
    下面是一个示例项目:

    您需要更具体一些-您正在查看哪种类型的输入?演讲音乐?一种乐器演奏一个音符?纯音?好的-那么你希望提取什么样的频率信息呢?只是一个短期功率谱,或者更复杂的东西?我只需要每个短音乐片段的平均赫兹值。片段长度小于0.2秒。没有单一的“Hz值”——一种复杂的音乐声音包含许多不同频率的能量,能量随频率的分布不断变化。你能发布一个示例项目吗?太棒了。。。在我的iPhone 5上,它在这个网站上的峰值为19K Hz:。有人用过奴佛卡因吗?@suthar你可以在AccumeratorDalenght中使用较小的值。请记住,值越小,频率越不准确。感谢您的努力!stackoverflow不是这样工作的。指向外部网站的链接不是答案。我提供了一个链接,指向一个类似问题的更完整答案。