来自wav的Audio Visualizer看起来不对劲

时间:2015-01-23 00:59:35

标签: c++ audio fft wav

我在制作视听器看起来很准确方面遇到了麻烦。具有大量声音的音箱倾向于正确绘制,但我遇到的问题是没有明显声音的所有频率似乎都会返回,其值通常在-60dB和-40dB之间反弹。这形成了扁平的弹跳线(通常在较高的频率中)。

我希望以每秒30帧的速度显示512个或更少的分档。我已经阅读了FFT和音频非停止几周了,到目前为止我的过程一直是:

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

我用几首歌测试了它,我生成的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(幅度)和log(幅度/ maxMagnitude)之间有任何区别。它似乎只是将所有bin的值均匀地向下移动。

EDIT2: 这是他们看起来像是一个视觉效果:

Song playing low sounds - 使用log(mag)

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

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

这是我应该做的吗?我试过这个,但看起来仍然不对劲。也许这只是一个扩展问题?当我这样做的时候,当它听起来应该是这样的时候,很多条都不会让它在线上方。如果他们确实使它高于0,那么他们就这么做了。

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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

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

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