来自 wav 的音频可视化器看起来不对

Audio Visualizer from wav looks wrong

本文关键字:看起来 可视化 wav 音频 来自      更新时间:2023-10-16

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

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

  • 从 wav 文件加载 pcm 数据。这为每秒 44100 个样本,范围为 -/+ 32767。我假设在将它们传递给 FFT 时将它们视为实数。
  • 将这些样本分成每帧 1470 个。(446 被忽略)
  • 取 1024 个样本并应用汉恩窗口。
  • 将样本作为实数[1024]数组以及另一个相同大小的数组传递给FFT,虚部用零填充
  • 通过循环遍历(样本/2)箱来获取量级,并执行一个sqrt(real[i]*real[i] + img[i]*img[i])。
  • 取 20 * log(幅度) 得到每个箱的分贝水平
  • 为每个箱绘制一个矩形。为每个帧绘制这些图格。

我已经用几首歌曲和我生成的一个 wav 文件对其进行了测试,该文件只播放 440Hz 的音调。使用 wav 文件,我确实在 440 箱处得到一个峰值,但所有其他箱形成一条不比 440 箱短多少的线。同样每隔一帧,除了 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)之间有任何区别。它似乎所做的只是将箱的所有值均匀地向下移动。

编辑2:下面是它们获取视觉对象的外观:

歌曲播放低音 - 带日志(mag)

歌曲播放低音 - 相同,但带有日志(mag/maxMag)

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

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

你必须明白,你不是在取无限信号的傅里叶变换,而是在取其窗口版本的FT。你的窗户甚至不是普通的汉恩窗户。丢弃 446 个点实际上是一个矩形窗口函数。窗口函数的 FT 都将显示在您的输出中。

其次,dB刻度是对数的。这确实意味着在没有信号的情况下它可以变得相当低。你提到-60 dB,但实际上它可以达到负无穷大。唯一可以使您免于这种情况的是窗口功能,它将在大约 -110 dB 处引入拖尾。

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

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

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