Я реализовал проект Деметри Pitch Detector для iPhone и столкнулся с двумя проблемами. 1) любой фоновый шум посылает бананы считывания частоты и 2) звуки более низкой частоты не воспроизводятся правильно. Я попытался настроить свою гитару, и пока работали более высокие струны, тюнер не мог правильно различить низкую E.
Код определения высоты тона находится в RIOInterface.mm и выглядит примерно так ...
// get the data
AudioUnitRender(...);
// convert int16 to float
Convert(...);
// divide the signal into even-odd configuration
vDSP_ctoz((COMPLEX*)outputBuffer, 2, &A, 1, nOver2);
// apply the fft
vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);
// convert split real form to split vector
vDSP_ztoc(&A, 1, (COMPLEX *)outputBuffer, 2, nOver2);
Затем Деметри определяет «доминирующую» частоту следующим образом:
float dominantFrequency = 0;
int bin = -1;
for (int i=0; i<n; i+=2) {
float curFreq = MagnitudeSquared(outputBuffer[i], outputBuffer[i+1]);
if (curFreq > dominantFrequency) {
dominantFrequency = curFreq;
bin = (i+1)/2;
}
}
memset(outputBuffer, 0, n*sizeof(SInt16));
// Update the UI with our newly acquired frequency value.
[THIS->listener frequencyChangedWithValue:bin*(THIS->sampleRate/bufferCapacity)];
Для начала, я считаю, что мне нужно применить LOW PASS FILTER ... но я не эксперт по БПФ и не знаю, где и как это сделать с данными, возвращаемыми функциями vDSP. Я тоже не уверен, как повысить точность кода на низких частотах. Похоже, существуют и другие алгоритмы для определения доминирующей частоты - но опять же, поиск толчка в правильном направлении при использовании данных, возвращаемых фреймворком Apple Accelerate.
ОБНОВИТЬ:
Фреймворк ускорения на самом деле имеет некоторые оконные функции. Я настраиваю такое базовое окно
windowSize = maxFrames;
transferBuffer = (float*)malloc(sizeof(float)*windowSize);
window = (float*)malloc(sizeof(float)*windowSize);
memset(window, 0, sizeof(float)*windowSize);
vDSP_hann_window(window, windowSize, vDSP_HANN_NORM);
который я затем применяю, вставляя
vDSP_vmul(outputBuffer, 1, window, 1, transferBuffer, 1, windowSize);
перед функцией vDSP_ctoz. Затем я изменяю остальную часть кода, чтобы использовать transferBuffer вместо outputBuffer ... но до сих пор не заметил каких-либо кардинальных изменений в окончательном предположении о питче.