iOSのオーディオストリーム(音楽)からHz周波数値を取得するための最良の方法は何でしょうか?それを行うためにAppleが提供する最良かつ最も簡単なフレームワークは何ですか。前もって感謝します。
3 に答える
これは、AccelerateFrameworkを使用して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(TimeDomainDataLenght);
Float32時間領域データを渡し、戻り時に周波数領域データを取得します。Float32 * fftData = ComputeFFT(fftHelper、buffer、frameSize);
これで、インデックス=周波数、値=マグニチュード(マグニチュードの2乗?)の配列ができました。ナイキストの定理によると、そのアレイで可能な最大周波数はサンプルレートの半分です。つまり、サンプルレート= 44100の場合、エンコードできる最大周波数は22050Hzです。
したがって、サンプルレートのナイキスト最大周波数を見つけてください。constFloat32 NyquistMaxFreq = SAMPLE_RATE / 2.0;
Hzの検索は簡単です。Float32hz=((Float32)someIndex /(Float32)fftDataSize)* NyquistMaxFreq; (fftDataSize = frameSize / 2.0)
これは私のために働きます。Audacityで特定の周波数を生成して再生すると、このコードは正しい周波数を検出します(最も強い周波数です。これを行うには、fftDataでmaxを見つける必要もあります)。
(約1〜2%でまだ少し不一致があります。なぜこれが発生するのかわかりません。誰かが理由を説明してくれるなら、それは大いにありがたいです。)
編集:
この不一致は、FFTに使用するピースが小さすぎるために発生します。時間領域データのより大きなチャンク(16384フレーム)を使用すると、問題が解決します。この質問はそれを説明します: iPhoneで正しい周波数値を取得できません
編集: これがサンプルプロジェクトです:https ://github.com/krafter/DetectingAudioFrequency
このような質問は、ここSOでよく聞かれます。(私はここで同様の回答をしました)そこで、商用アプリやクローズドソースアプリでも使用できるコードを使用して小さなチュートリアルを作成しました。これは必ずしも最良の方法ではありませんが、多くの人が理解している方法です。「すべての短い音楽セグメントのHz平均値」の意味に基づいて変更する必要があります。たとえば、基本ピッチまたは周波数重心を意味しますか。
別の回答で示唆されているように、加速フレームワークでAppleのFFTを使用することをお勧めします。
それが役に立てば幸い。
http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html
Appleは、周波数またはピッチ推定のフレームワークを提供していません。ただし、iOS Accelerateフレームワークには、より高度な周波数およびピッチの認識または推定アルゴリズムのコンポーネントとして使用できるFFTおよび自己相関のルーチンが含まれています。
ノイズがほぼゼロの単一の長い連続定周波数の純粋な正弦波トーンを除いて、簡単で最良の方法はありません。この場合、長いウィンドウのFFTの補間されたマグニチュードピークが適している可能性があります。音声や音楽の場合、その単純な方法はほとんどの場合まったく機能しません。しかし、ピッチ検出または推定方法を検索すると、より適切なアルゴリズムに関する多くの研究論文が見つかります。