1

我知道之前被问了一千次,但我仍然找不到解决方案。搜索SO,我确实找到了它的算法,但缺乏真正理解它所需的数学知识,我无助地迷失了!

首先,我的目标是计算整个频谱图并将其保存到图像中,以便将其用于可视化器。

我尝试使用 Sound.computeSpectrum,但这需要播放声音并等待它结束,我想以比聆听所有歌曲所需的时间更短的方式计算频谱图。我有 2 小时长的 mp3。

我现在正在做的是从 Sound 对象中读取字节,分成两个 Vectors(.); 然后使用计时器,每 100 毫秒我调用一个函数(步骤 1),其中我有算法的实现,如下所示:

  1. 对于每个向量(每个向量),我将 hann 函数应用于元素;
  2. 对于每个向量,我都会取消虚部(我有一个辅助向量)
  3. 对于每个向量,我应用 FFT
  4. 对于每个向量,我找到前 N / 2 个元素的大小
  5. 对于每个向量,我将平方幅度转换为 dB 比例
  6. 结尾。

但我只得到负值,只有 30% 的结果可能有用(其余部分相同)

我将只发布一个频道的代码,以摆脱“每个矢量”部分。

private var N:Number = 512;
private function step1() : void
{
    var xReLeft:Vector.<Number> = new Vector.<Number>(N);
    var xImLeft:Vector.<Number> = new Vector.<Number>(N);

    var leftA:Vector.<Number> = new Vector.<Number>(N);

    // getting sample range
    leftA = this.channels.left.slice(step * N, step * (N) + (N));

    if (leftA.length < N)
    {
        stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
        return;
    }
    else if (leftA.length == 0)
    {
        stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
        return;
    }

    var i:int;

    // hann window function init
        m_win = new Vector.<Number>(N);
        for ( var i:int = 0; i < N; i++ )
            m_win[i] = (4.0 / N) * 0.5 * (1 - Math.cos(2 * Math.PI * i / N));

    // applying hann window function
    for ( i = 0; i < N; i++ )
    {
        xReLeft[i] = m_win[i]*leftA[i];
        //xReRight[i] = m_win[i]*rightA[i];
    }

    // nullify the imaginary part
    for ( i = 0; i < N; i++ )
    {
        xImLeft[i] = 0.0;
        //xImRight[i] = 0.0;
    }

    var magnitutel:Vector.<Number> = new Vector.<Number>(N);

    fftl.run( xReLeft, xImLeft );

    current = xReLeft;
    currf = xImLeft;

    for ( i = 0; i < N / 2; i++ )
    {
        var re:Number = xReLeft[i];
        var im:Number = xImLeft[i];
        magnitutel[i] = Math.sqrt(re * re + im * im);
    }

    const SCALE:Number = 20 / Math.LN10;
    var l:uint = this.total.length;
    for ( i = 0; i < N / 2; i++ )
    {
        magnitutel[i] = SCALE * Math.log( magnitutel[i] + Number.MIN_VALUE );
    }

    var bufferl:Vector.<Number> = new Vector.<Number>();

    for (i = 0; i < N / 2 ; i++)
    {
        bufferl[i] =  magnitutel[i];
    }

    var complete:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
    complete[0] = bufferl;
    this.total[step] = complete;

    this.step++;
}

该函数在定时器(步进器)调度的事件中执行。显然我做错了什么,正如我所说的,我只有负值,而且更多的值在 1 到 7000 之间(至少)。

我要提前感谢您的帮助。

怀着敬意,保罗

4

1 回答 1

0

负分贝值是可以的。只需添加一个常数(代表您的音量控制),直到您要着色的点数变为正数。保持负数的其余值通常仅在频谱图中显示或着色为黑色。无论多么负(因为它们可能只是 FFT 的数值噪声,可能是一个巨大的负 dB 数,甚至是 NaN 或 log(0) 的 -Inf)。

于 2012-06-18T14:24:06.913 回答