wav 的 Audio Visualizer 看起来不对

Audio Visualizer from wav looks wrong

我在使音频可视化工具看起来准确时遇到了问题。具有大量声音的箱子往往会正确绘制,但我遇到的问题是所有没有明显声音的频率似乎都以通常在 -60dB 和 -40dB 之间反弹的值返回。这形成一条平坦的弹跳线(通常在较高频率)。

我想以每秒 30 帧的速度显示 512 个 bin 或更少。几周来我一直在不停地阅读 FFT 和音频,到目前为止我的过程是:

我已经用几首歌曲和我生成的 wav 文件对其进行了测试,该文件仅以 440Hz 播放音调。对于 wav 文件,我确实在 440 bin 处出现尖峰,但所有其他 bin 形成的线并不比 440 bin 短多少。同样每隔一帧,除了 440 之外的箱子看起来像一个图形对数函数,在其他箱子上有下降。

我正在用 C++ 编写这个。使用 STK 仅从音频文件加载左声道:

//put every sample in the song into a temporary vector
for (int i = 0; i < stkObject->getSize(); i++)
{
    standardVector.push_back(stkObject->tick(LEFT));
}

我正在使用 FFTReal 执行 FFT:

    std::vector<std::vector <double> > leftChannelData;
    int numberOfFrames = stkObject->getSize()/samplesPerFrame;

    leftChannelData.resize(numberOfFrames);
    for(int i = 0; i < numberOfFrames; i++)
    {
        for(int j = 0; j < FFT_SAMPLE_LENGTH; j++)
        {
            real[j] = standardVector[j + (i*samplesPerFrame)];
        }

        applyHannWindow(real, FFT_SAMPLE_LENGTH);
        fft_object.do_fft(imaginary,real);

        //FFTReal instructions say to run this after an fft
        fft_object.rescale(real);

        leftChannelData[i].resize(FFT_SAMPLE_LENGTH/2);
        for (int j = 0; j < FFT_SAMPLE_LENGTH/2; j++)
        {
            double magnitude = sqrt(real[j]*real[j] + imaginary[j]*imaginary[j]);
            double dbValue = 20 * log(magnitude/maxMagnitude);

            leftChannelData[i].at(j) = dbValue;
        }
    }

我不知道是什么原因造成的。我尝试了各种方法来提取我忽略的那 446 个样本,但结果似乎没有改变。我想我可能做错了一些根本性的事情。我试过在将 pcm 数据交给 fft 之前对其进行归一化,并且在找到分贝之前尝试过对幅度进行归一化,但它似乎没有用。有什么想法吗?

编辑:我看不出 log(magnitude) 和 log(magnitude/maxMagnitude) 之间有什么区别。它所做的一切似乎就是将 bin 的所有值均匀向下移动。

编辑2: 这是他们获得视觉效果的样子:

Song playing low sounds - 对数(mag)

Song playing low sounds - 相同但有 log(mag/maxMag)

同样,log(mag) 和 log(mag/maxMag) 通常看起来相同,但值跨度为负。正如 MSalters 所说,分贝可以接近-infinite,所以我可以将这些值限制在-100dB。然后取 log(mag/maxMag) 并加 100。这样矩形的高度范围从 0 到 100 而不是 -100 到 0。

这是我应该做的吗?我已经试过了,但它看起来仍然不对。也许这只是一个缩放问题?当我这样做时,很多小节并没有在听起来应该的时候超过线。如果他们确实做到了高于 0,他们也只是勉强做到了。

您必须明白,您不是在对无限信号进行傅立叶变换,而是对其进行 windowed 版本的 FT。而且你的 window 甚至不是普通的 Hann window。丢弃 446 个点实际上是一个矩形 window 函数。 window 函数的 FT 都将显示在您的输出中。

其次,dB 标度是对数的。这确实意味着它可以在没有信号的情况下变得非常低。您提到 -60 dB,但实际上它可能达到负无穷大。唯一能让你免于此的是 window 函数,它会在大约 -110 dB 处引入拖影。

长度为 1024 的量化 Von Hann window 产生的噪声(阻带纹波)很可能在 -40 到 -60 dB 左右。因此,一种策略是只设置一个阈值,并忽略(不绘制)低于该阈值的所有值。

此外,请尝试删除 rescale(real) 函数,因为这可能会在您获取对数幅度之前扭曲您的复向量。

此外,请确保您确实将音频样本正确加载到您的真实向量中(符号、位数和字节顺序)。