NAudio频段强度

时间:2011-10-12 03:42:06

标签: c# algorithm fft naudio

我有一个使用NAudio的音频播放器,我想为每个频段显示实时强度。

我为1024个样本的每个块触发了一个事件:

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

我想要的是一组数字,表示每个频段的强度。让我们说我想将窗口划分为16个波段。

例如,当有更多低音频率时,它可能如下所示:

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

如果可以使用该数据,我应该在该事件处理程序中添加什么内容?

数据来了(Complex [])已经用FFT进行了转换。 这是一个立体声流。

首先尝试:

    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;
        }
    }

以上是做了一些事情,但我认为前两个乐队太多了,而且我正在演奏没有那么多低音的夏奇拉。

谢谢!

1 个答案:

答案 0 :(得分:8)

您可能希望在此处解决两个不同的问题:

(1)窗口函数

您需要在FFT之前对数据应用window function,否则您将获得spectral leakage,这将导致非常模糊的频谱。光谱泄漏的一个令人不快的副作用是,如果你有任何类型的重要DC(0 Hz)分量,那么这将导致你在条形图上看到的那种1 / f形状。

(2)记录幅度/频率轴

人类听力在强度和频率轴上基本上是对数的。不仅如此,语音和音乐往往在频谱的低频部分拥有更多的能量。为了获得更加令人愉悦和有意义的强度与频率的显示,我们通常使幅度和频率轴都成对数。在幅度轴的情况下,通常通过绘制dB re full scale,即

来处理
magnitude_dB = 10 * log10(magnitude);

在频率轴的情况下,您可能希望将频段分组为频段,每个频段可能是一个八度音阶(2:1频率范围),或者更常见的是更高分辨率,第三个八度音阶。因此,如果您只想要10个“条形”,那么您可以使用以下八度音阶:

   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

(假设您的采样率为44.1 kHz,音频输入硬件的上限为20 kHz)。

请注意,虽然这种应用具有幅度(dB)强度标度几乎是强制性的,但对数频率轴的关键性较低,因此您现在可以尝试使用现有的线性分级,并看看效果如何通过在时域中应用窗口函数(假设您还没有)并将幅度比例转换为dB。