2013-03-18 9 views
5

Sto lavorando su un'app per iPad e voglio analizzare l'audio da un video che sto riproducendo. Tutto sta andando bene, usando MTAudioProcessingTap. Attualmente ho un codice di prova per testare/misurare il volume del canale sinistro e destro. Questo è tutto andando abbastanza bene:Filtro passa-basso, calcolo RMS su iOS

void process(MTAudioProcessingTapRef tap, CMItemCount numberFrames, 
     MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut, 
     CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut) 
{ 
    OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, 
                flagsOut, NULL, numberFramesOut); 

    if (err) 
     NSLog(@"Error from GetSourceAudio: %ld", err); 

    float leftVolume, rightVolume; 

    for (CMItemCount i = 0; i < bufferListInOut->mNumberBuffers; i++) 
    { 
     AudioBuffer *pBuffer = &bufferListInOut->mBuffers[i]; 
     int cSamples = numberFrames * pBuffer->mNumberChannels; 

     float *pData = (float *)pBuffer->mData; 

     float rms = 0.0f; 

     for (int j = 0; j < cSamples; j++) 
     { 
      rms += pData[j] * pData[j]; 

     } 

     if (cSamples > 0) 
     { 
      rms = sqrtf(rms/cSamples); 
     } 

     if (0 == i) 
     { 
      leftVolume = rms; 
     } 

     if (1 == i || (0 == i && 1 == bufferListInOut->mNumberBuffers)) 
     { 
      rightVolume = rms; 
     } 
    } 

    NSLog(@"Left/Right Volume: %f/%f", leftVolume, rightVolume); 
} 

ma per lo scopo di questa applicazione, lo voglio per misurare solo RMS ("intensità") della gamma di 0-80Hz (come esempio). Pertanto, ho bisogno di un filtro passa-basso.

Sono stato Googling per un lungo periodo di tempo, ma il mio problema è che non riesco a trovare alcun post chiaro, tutorial o soluzione che sia ovvia. Quasi ogni problema che suona in qualche modo come il mio ha un codice casuale al di sotto con schifo o mancanza di commenti quindi non riesco a capire cosa ci fanno tutti i numeri magici, e cosa significano ..

Qualcuno potrebbe spingimi nella giusta direzione qui? Si noti che nel mio caso I do desidera comprendere il codice e non solo scappare con un campione funzionante.

Grazie

risposta

16

Se si può solo scappare con un esempio di lavoro, si sarebbe fortunati. :-)

L'elaborazione del segnale è un'area complessa e profonda. È complicato quando lo fai in teoria, ed è anche complicato quando vuoi farlo praticamente.

Si desidera avere un filtro passa-basso. Ci sono molte opzioni con diversi vantaggi e svantaggi.

I concetti fondamentali che è necessario affrontare quando si vuole capire cosa sta succedendo:

frequenza di dominio e nel dominio del tempo: dominio della frequenza è quando si parla di intervalli di frequenza come 0..80Hz per esempio. Il dominio del tempo è il tempo normale o, ad esempio, i singoli valori di esempio nel buffer di campionamento. Il codice sopra calcola il RMS nel dominio del tempo.

Regola fondamentale: dominio di frequenza e dominio del tempo sono completamente equivalenti.

È possibile eseguire molte operazioni in entrambi i domini con lo stesso risultato. Puoi sempre passare dal dominio della frequenza al dominio del tempo. Poiché alcune operazioni sono banali in un determinato dominio, è spesso utile passare prima al dominio desiderabile, eseguire l'operazione banale e quindi tornare al dominio originale (se necessario).

Il passaggio tra frequenza e dominio del tempo viene eseguito utilizzando un FT (trasformazione di Fourier). A livello di programmazione uno spesso utilizza il caso speciale di buffer che contengono una potenza di due numeri di campioni e l'algoritmo F2 FFT (Fast Fourier Transformation).

L'altra proprietà interessante è il teorema della convoluzione: il FT traduce tra la moltiplicazione delle funzioni in un dominio e la convoluzione delle funzioni sull'altro dominio.

Ora, che cosa ha a che fare tutto questo con il filtro passa basso?

Il tuo filtro passa-basso suggerito 0-80 Hz, è una funzione rettangolare nel dominio della frequenza. Vuoi moltiplicarlo per il tuo input nel dominio della frequenza. Ciò significa lasciare che tutte le parti di frequenza al di sotto degli 80Hz e impostare tutti gli altri a zero.

Ora si potrebbe fare tutto ciò che nel dominio della frequenza, sarebbe facile, ma per ragioni di efficienza si desidera farlo nel dominio del tempo per evitare la FFT avanti e indietro. (Nel tuo caso vuoi solo avere l'energia che puoi calcolare nel dominio della frequenza nello stesso modo in cui lo fai ora (somma dei quadrati).)

Per fare il tuo filtro passa-basso nel dominio del tempo invece di FT-multiply-FT, puoi anche convogliare con FT (funzione rettangolare). FT (funzione rettangolare) è il filtro passa basso ideale: la funzione sinc().

sinc(x) := sin(pi*x)/pi*x 

Questo sinc (x) è la risposta impulsiva della funzione rettangolare. Questa risposta d'impulso concreta è infinita, il che è poco pratico. Ciò significherebbe che dovrai calcolare la convoluzione del tuo input con un numero infinito di valori.

quello che vuoi è un filtro con una risposta all'impulso finita : FIR. Ciò causerà errori al tuo filtro, in concreto non vedrai tutte le frequenze < 80Hz con lo stesso peso e vedrai anche alcune frequenze superiori a 80Hz nella tua energia.

Questo compromesso è inevitabile.

BTW: Quando si utilizza l'approccio FFT, in cui è possibile applicare la funzione rettangolare perfetta senza errori, anche questo errore si verifica indirettamente quando si esegue la finestra del segnale di input prima di eseguire la FFT. (Windowing significa tagliare pezzi (finestre) del tuo input per attivare la FFT.) Ciò avrà gli stessi effetti negativi per l'output e richiede gli stessi compromessi della funzione di filtro e del risultato.

Probabilmente vorrete un filtro FIR di qualche tipo come filtro passa-basso. E i numeri strani che vedi nel codice degli altri molto probabilmente saranno i coefficienti di un tale filtro FIR.

Il problema è che non esiste un compromesso "ottimale", perché il compromesso dipende molto da come si definisce "errore" nel filtro. Alcune persone devono evitare con ogni mezzo parti di frequenza oltre gli 82 Hz (nel tuo esempio) e quindi hanno bisogno di un bordo del filtro molto ripido. Questo di solito causa grandi artefatti vicino al limite 80Hz, che è necessario accettare in quel momento. Altre persone stanno bene con un po 'di energia proveniente da frequenze fino a 120 Hz e rimangono sotto il 10% sopra i 120 Hz, per ridurre gli artefatti vicino al limite degli 80Hz (un filtro passa-basso più morbido).

L'intero argomento è molto ben coperto qui: https://ccrma.stanford.edu/~jos/sasp/FIR_Digital_Filter_Design.html

Oppure, se si desidera avviare subito all'inizio: https://ccrma.stanford.edu/~jos/sasp/sasp.html

Anche dare un'occhiata alle pagine di Wikipedia di filtro FIR e sinc.

Quanto sopra non è sufficiente per progettare e implementare il proprio filtro, lo ammetto. Ma dovrebbe darti abbastanza sfondo e indicazioni per iniziare.

E non lasciatevi scoraggiare dalla matematica a volte strana.

Idea: un modo per visualizzare il funzionamento del filtro è eseguire una FFT dopo aver applicato il filtro e osservato lo spettro. Sarebbe molto difficile stabilire se il filtro funzioni correttamente osservando solo il valore RMS. Il tuo iPad ha una potenza di elaborazione più che sufficiente per fare ciò.

(ho appena visto che c'è anche http://dsp.stackexchange.com per l'elaborazione del segnale.)

+0

Woow! Grazie! Questo mi sta aiutando ad uscire alla grande! Voglio "ricompensarti" per la mia "taglia", ma ho detto che posso farlo solo in 20 ore, quindi vedrai che presto arriverà :) Grazie per tutto l'aiuto, in questo modo dovrei essere in grado per creare qualcosa :) –

+0

Impressionante, sicuramente una risposta degna della taglia! –

+0

Aggiungerei un altro 50 a questa risposta se potessi, è fantastico! –