Я прочитал этот вопрос:
Использование Apple FFT и ускорение Framework
Как настроить буфер при выполнении БПФ с использованием рамки Accelerate?
iOS FFT Accerelate.framework рисовать спектр во время воспроизведения
Все они описывают, как настроить fft с ракурсом ускорения. С их помощью я смог настроить fft и получить базовый анализатор спектра. Прямо сейчас, я показываю все значения, которые я получил от fft. Тем не менее, я хочу показать только 10-15 или переменное число баров, пересчитывающих определенные частоты. Точно так же как измеритель уровня iTunes или WinAmp. 1. Нужно ли мне усреднять значения амплитуды из диапазона частот? Или они просто показывают вам величину для конкретной полосы частот? 2. Кроме того, мне нужно преобразовать значения величины в db? 3. Как сопоставить мои данные с определенным диапазоном. Я сопоставляю с диапазоном max db для своих битов бит? Получение максимального значения для бина приведет к максимальному отображению значений перехода.
Мой 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.));
дает мою довольно закругленную кривую:
Если я не конвертирую в db, я могу построить, умножив значение моего массива на 10000 и получив хорошие пики.
Я делаю что-то совершенно не так? И как я могу показать переменное количество баров?