绘制声音的音高(频率)

2022-09-01 06:33:17

我想把声音的音高画成一个图表。

目前,我可以绘制振幅。下面的图表是由以下返回的数据创建的:getUnscaledAmplitude()

alt text

AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(file)));
byte[] bytes = new byte[(int) (audioInputStream.getFrameLength()) * (audioInputStream.getFormat().getFrameSize())];
audioInputStream.read(bytes);

// Get amplitude values for each audio channel in an array.
graphData = type.getUnscaledAmplitude(bytes, 1);


public int[][] getUnscaledAmplitude(byte[] eightBitByteArray, int nbChannels)
{
    int[][] toReturn = new int[nbChannels][eightBitByteArray.length / (2 * nbChannels)];
    int index = 0;

    for (int audioByte = 0; audioByte < eightBitByteArray.length;)
    {
        for (int channel = 0; channel < nbChannels; channel++)
        {
            // Do the byte to sample conversion.
            int low = (int) eightBitByteArray[audioByte];
            audioByte++;
            int high = (int) eightBitByteArray[audioByte];
            audioByte++;
            int sample = (high << 8) + (low & 0x00ff);

            toReturn[channel][index] = sample;
        }
        index++;
    }

    return toReturn;
}

但我需要显示音频的音高,而不是振幅。快速傅里叶变换似乎可以得到音高,但它需要知道比我拥有的原始字节更多的变量,并且非常复杂和数学。

有没有办法做到这一点?


答案 1

频率(客观指标)与音高(主观量)不同。一般来说,音高检测是一个非常棘手的问题。

假设您现在只想绘制频率响应图,那么您别无选择,只能使用FFT,因为它是获取时域数据频率响应的方法。(嗯,还有其他方法,例如离散余弦变换,但它们实现起来同样棘手,解释起来也更棘手)。

如果您正在为实现FFT而苦苦挣扎,请注意,它实际上只是计算离散傅里叶变换(DFT)的有效算法;请参阅 http://en.wikipedia.org/wiki/Discrete_Fourier_transform。基本的DFT算法要容易得多(只有两个嵌套循环),但运行速度要慢得多(O(N^2)而不是O(N log N))。

如果你想做任何比简单地绘制频率内容更复杂的事情(比如音高检测或窗口化(正如其他人所建议的那样),恐怕你会学到数学的含义。


答案 2

快速傅里叶变换不需要比您拥有的输入字节知道更多。不要被维基百科的文章吓跑。FFT算法将获取您的输入信号(使用常见的FFT算法,样本数需要为2的幂,例如256,512,1024),并返回具有相同大小的复数向量。由于您的输入是真实的,而不是复杂的(虚部设置为零),因此返回的向量将是对称的。其中只有一半将包含数据。由于你不关心相位,你可以简单地取复数的大小,即 sqrt(a^2+b^2)。仅仅取复数的绝对值也可能有效,在某些语言中,这等效于前面的表达式。

有FFT的Java实现可用,例如:http://www.cs.princeton.edu/introcs/97data/FFT.java.html

伪代码将如下所示:

Complex in[1024];
Complex out[1024];
Copy your signal into in
FFT(in, out)
for every member of out compute sqrt(a^2+b^2)
To find frequency with highest power scan for the maximum value in the first 512 points in out

输出将包含采样频率介于 0 到 1 半 之间的整数。

由于FFT假设重复信号,您可能需要对输入信号应用一个窗口。但一开始不要担心这一点。

您可以在网络上找到更多信息,例如:初学者的FFT

此外,正如Oli所指出的那样,当存在多个频率时,感知到的音高是一种更复杂的现象


推荐