从麦克风输入和FFT-Java获取频率

时间:2014-01-29 19:44:49

标签: java math audio fft microphone

我的目标是能够处理来自吉他(或其他乐器)的单个音符,并将其转换为频率值。

这不一定是实时的 - 我认为记录一秒钟的声音并随后分析数据要容易得多。

我知道要做到这一点,我需要使用傅立叶变换(并且有一个将执行FFT的类)。但是,我并不真正理解FFT算法的输入/输出 - 我正在使用的类似乎使用复杂的矢量输入并给出复杂的矢量输出。这些代表什么?

此外,是否有人可以推荐任何可以检测和记录输入的Java类(如果可能,还可以提供可以插入FFT的频率或值?)?

提前致谢。

1 个答案:

答案 0 :(得分:2)

FFT的输入将是表示音频的时域信号。如果你从麦克风录下一些声音一秒钟,这将包含一个由不同频率的不同频率组成的波 - 希望主要是与您正在播放的音符对应的频率/频率,加上一些外部噪音和噪音麦克风和电子产品推出。如果在那1秒内你碰巧有512个时间点(所以麦克风可以每秒512次采样),那么每个时间点都代表麦克风拾取的强度。可以使用FFT将这些声强值从其时域表示转换为频域表示。

如果您现在将其赋予FFT,因为它是实值输入,您将获得对称复数输出(围绕中心值对称)并且可以忽略复数向量输出的后半部分并仅使用前半部分 - 即后半部分将与前半部分对称(因此“相同”)。输出表示每个频率对输入波形的贡献 - 实质上,每个“bin”或数组索引包含有关该频率幅度的信息。要提取您想要的幅度:

magnitudeFFTData[i] = Math.sqrt((real * real) + (imaginary * imaginary));

其中realimaginary是该频率仓中复数的实部和虚部。要获得与给定bin相对应的频率,您需要以下内容:

frequency = i * Fs / N;

其中i是bin或数组索引号,Fs采样频率和N数据点数。来自我最近使用过FFT的项目:

for (int i = (curPersonFFTData.length / 64); i < (curPersonFFTData.length / 40); i++) {
            double rr = (curPersonFFTData[i].getReal());
            double ri = (curPersonFFTData[i].getImaginary());

            magnitudeCurPersonFFTData[i] = Math.sqrt((rr * rr) + (ri * ri));
            ds.addValue(magnitudeCurPersonFFTData[i]);
        }

64和40的除法是任意的,仅对我的情况有用,只能得到某些频率成分,而不是你想要的所有频率。您可以轻松实时完成所有这些工作。