IOS FFT Accerelate.framework рисовать спектр во время воспроизведения
ОБНОВЛЕНИЕ 2016-03-15
Пожалуйста, взгляните на этот проект: https://github.com/ooper-shlab/aurioTouch2.0-Swift. Он был перенесен на Swift и содержит каждый ответ, который вы ищете, если вы здесь.
Я много исследовал и много узнал о FFT и Accelerate Framework. Но после нескольких дней экспериментов я расстроен.
Я хочу отобразить частотный спектр аудиофайла во время воспроизведения на диаграмме. Для каждого интервала времени он должен показывать величину в db по оси Y (отображается красной полосой) для каждой частоты (в моем случае 512 значений), вычисленной БПФ на оси X.
Результат должен выглядеть следующим образом:
![enter image description here]()
Я заполняю буфер 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);
}
Выполнение БПФ. FrequencyArray - это просто структура данных, которая содержит 512 значений float.
- (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;
}
Выход выглядит как бы странным, хотя некоторые, как кажется, движутся в соответствии с музыкой.
Я рад, что дошел до сих пор благодаря очень хорошим сообщениям здесь:
Использование яблочного FFT и ускорение Framework
Но теперь я не знаю, что делать. Что мне не хватает?
Ответы
Ответ 1
Во-первых, вы не применяете функцию окна до FFT - это приведет к размытию спектра из-за спектральная утечка.
Во-вторых, вы просто используете реальный компонент выходных лотков FFT для вычисления величины dB - вам нужно использовать сложную величину:
magnitude_dB = 10 * log10(re * re + im * im);