2011-10-12 7 views
7

Ho un lettore audio che utilizza NAudio e mi piacerebbe visualizzare un'intensità in tempo reale per ogni banda di frequenza.NAudio intensità banda di frequenza

ho un evento attivato per ogni blocco di 1024 campioni:

public void Update(Complex[] fftResults) 
{ 
    // ?? 
} 

Nei vorrei avere è un array di numeri che indicano l'intensità di ciascuna banda di frequenza. Diciamo che mi piacerebbe dividere la finestra in 16 bande.

Per esempio, quando ci sono più basse frequenze potrebbe assomigliare a questo:

░░░░░░░░░░░░░░░░ 
▓▓▓░░░░░░░░░░░░░ 
▓▓▓░░░░░░░░░░░░░ 
▓▓▓▓░░░░░░░░░░░░ 
▓▓▓▓▓░░░░░░░░░░░ 
▓▓▓▓▓▓▓▓░░░▓░░▓░ 

Cosa devo mettere in quel gestore di eventi, se questo è possibile con quei dati?

I dati in arrivo (Complesso []) sono già stati trasformati con la FFT. È un flusso stereo.

Prima prova:

double[] bandIntensity = new double[16] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 

    public void Update(Complex[] fftResults) 
    { 
     // using half fftResults because the others are just mirrored 
     int band = 0; 
     for (int n = 0; n < fftResults.Length/2; n++) 
     { 
      band = (int)((double)n/(fftResults.Length/2) * bandIntensity.Length); 
      bandIntensity[band] += Math.Sqrt(fftResults[n].X * fftResults[n].X + fftResults[n].Y * fftResults[n].Y); 
      bandIntensity[band] /= 2; 
     } 
    } 

È possibile che questo sta facendo qualcosa, ma penso troppo va nelle prime due fasce, e sto giocando Shakira che non ha più di tanto bassi.

Grazie!

risposta

8

Ci sono due questioni separate che, probabilmente, si vuole affrontare qui:

(1) funzione di finestra

È necessario applicare un window function ai dati prima della FFT, altrimenti otterrete spectral leakage che risulterà in uno spettro molto spalmato. Uno spiacevole effetto collaterale di dispersione spettrale è che se si dispone di un qualsiasi tipo di componente DC (0 Hz) significativo, questo si tradurrà nel tipo di forma 1/f che si vede sul grafico a barre.

(2) Log ampiezza/frequenza assi

dell'udito umano è essenzialmente logaritmica in entrambi gli assi di intensità e frequenza. Non solo, ma la voce e la musica tendono ad avere più energia nella parte a bassa frequenza dello spettro. Per ottenere una visualizzazione più gradevole e significativa dell'intensità rispetto alla frequenza, solitamente si effettuano logaritmici sia sull'asse di ampiezza che su quello di frequenza. Nel caso della grandezza dell'asse questo viene normalmente curata tracciando dB re di fondo scala, cioè

magnitude_dB = 10 * log10(magnitude); 

Nel caso della frequenza dell'asse probabilmente si vuole raggruppare i bidoni in bande, che potrebbe essere ciascuno un'ottava (intervallo di frequenza 2: 1), o più comunemente per una risoluzione maggiore, terza ottava. Quindi, se si desidera solo 10 "barre" allora si potrebbe utilizzare le seguenti bande di ottava:

25 - 50 Hz 
    50 - 100 Hz 
    100 - 200 Hz 
    200 - 400 Hz 
    400 - 800 Hz 
    800 - 1600 Hz 
1600 - 3200 Hz 
3200 - 6400 Hz 
6400 - 12800 Hz 
12800 - 20000 Hz 

(ammesso che abbiate una frequenza di campionamento di 44,1 kHz e un limite superiore del vostro hardware ingresso audio di 20 kHz).

Si noti che pur avendo una scala di intensità di magnitudine (dB) è praticamente obbligatorio per questo tipo di applicazione, l'asse di frequenza del registro è meno critico, quindi è possibile provare con il binning lineare esistente per ora, e vedere solo quale effetto si ottiene dall'applicazione di una funzione finestra nel dominio del tempo (supponendo che non ne abbiate già uno) e convertendo la scala della magnitudine in dB.

+1

sei il mio eroe. lol. –

+0

Per la finestra vedo che si usa BlackmannHarrisWindow. Tuttavia non ho ancora provato il 10xLog10(), vedrò come questo cambia il grafico. E rimuoverò il cestino 0Hz DC. –

+0

anche dopo aver applicato un ottava bin alla raccolta a banda, ottengo ancora numeri strani, ancora troppo sul lato sinistro ... ho convertito i numeri della scala y in dB –