ho implementato il progetto di Demetri Pitch Detector per l'iPhone e che colpiscono contro due problemi. 1) qualsiasi tipo di rumore di fondo invia le banane di lettura della frequenza e 2) i suoni di frequenza inferiore non vengono inseriti correttamente. Ho cercato di accordare la mia chitarra e mentre le corde più alte hanno lavorato - il sintonizzatore non riuscivo a scorgere correttamente il basso E.FFT su iPhone di ignorare il rumore di fondo e trovare piazzole inferiori
codiceIl Pitch Detection si trova in RIOInterface.mm e va qualcosa di simile ...
// 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);
Demetri passa poi a determinare la frequenza 'dominante' come segue:
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)];
per cominciare, credo che ho bisogno di applicare un filtro passa-basso ... ma io non sono un esperto e non FFT sicuro esattamente dove o come farlo rispetto ai dati restituiti dalla funzione vDSP S. Inoltre, non sono sicuro di come migliorare la precisione del codice nelle frequenze più basse. Sembra che ci siano altri algoritmi per determinare la frequenza dominante, ma ancora una volta, cercando un calcio nella giusta direzione quando si utilizzano i dati restituiti dal framework Accelerate di Apple.
UPDATE:
Il accelerare quadro in realtà ha alcune funzioni a finestre. ha installato una finestra di base come questa
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);
che poi applico inserendo
vDSP_vmul(outputBuffer, 1, window, 1, transferBuffer, 1, windowSize);
prima della funzione vDSP_ctoz. Poi cambio il resto del codice per usare "transferBuffer" invece di outputBuffer ... ma finora non ho notato alcun cambiamento drammatico nell'ipotesi finale.
due cose che ricordo di aver giocato con questa roba qualche anno fa: è possibile impostare un livello di squelch per il suono di sottofondo semplicemente sottraendo i dati di input non elaborati da una quantità predeterminata (che si può immaginare per ora, finché non si calcola un buon algoritmo), impostando qualsiasi cosa che va sotto 0 a 0. e frequenze più basse, per qualche motivo non ricordo, non si registra tanto forte quanto più alto, quindi è necessario aumentare i volumi a bassa frequenza in modo esponenziale prima di confrontare a una frequenza dominante più alta. –
Sembra che non si stia applicando una funzione finestra adeguata prima della FFT, quindi ci saranno molti artefatti nello spettro di potenza che probabilmente rovinerebbero qualsiasi tipo di tentativo di rilevamento del pitch. –
Ecco una domanda quasi duplicata con una risposta simile: http://stackoverflow.com/questions/4227420/matlab-missing-fundamental-from-an-fft – hotpaw2