n音频频带强度

本文关键字:音频 | 更新日期: 2023-09-27 18:10:56

我有一个使用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)(.5 * n / fftResults.Length * bandIntensity.Length);
        bandIntensity[band] += Math.Sqrt(fftResults[n].X * fftResults[n].X + fftResults[n].Y * fftResults[n].Y);
        bandIntensity[band] /= 2;
    }
}

上面做了一些事情,但是我认为前两个乐队太多了,我玩的是shakira,没有那么多贝斯。

谢谢!

n音频频带强度

您可能需要在这里解决两个独立的问题:

(1)窗口函数

你需要在FFT之前对你的数据应用一个窗函数,否则你会得到频谱泄漏,这将导致一个非常模糊的频谱。频谱泄漏的一个令人不快的副作用是,如果你有任何一种显著的直流(0 Hz)分量,那么这将导致你在条形图上看到的那种1/f形状。

(2)对数幅频轴

人的听力在强度和频率轴上基本上都是对数的。不仅如此,语音和音乐往往在频谱的低频部分有更多的能量。为了得到一个更令人愉快和有意义的强度与频率的显示,我们通常使幅度和频率轴都是对数的。在震级轴的情况下,这通常是通过绘制dB为满量程来处理的,即

magnitude_dB = 10 * log10(magnitude);

在频率轴的情况下,您可能希望将箱子分组到频带中,每个频带可能是一个八度(2:1频率范围),或者更常见的是更高分辨率的第三个八度。因此,如果你只想要10个"bar",那么你可以使用以下的八度频带:

   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会产生什么效果。