简体   繁体   English

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

[英]Get frequency from microphone input and FFT- Java

My goal is to be able to process a single note from a guitar (or other instrument), and convert it into a frequency value. 我的目标是能够处理来自吉他(或其他乐器)的单个音符,并将其转换为频率值。

This does not have to be in real time- I figured it would be much easier to record a one-second sound and analyse the data afterwards. 这不一定是实时的 - 我认为记录一秒钟的声音并在之后分析数据要容易得多。

I understand that to do this I need to use a Fourier transform (and have a class that will perform a FFT). 我知道要做到这一点,我需要使用傅立叶变换(并有一个将执行FFT的类)。 However, I don't really understand the input / output of a FFT algorithm- the class I am using seems to use a complex vector input and give a complex vector output. 但是,我并不真正理解FFT算法的输入/输出 - 我正在使用的类似乎使用复杂的矢量输入并给出复杂的矢量输出。 What do these represent? 这些代表什么?

Also, could anyone recommend any Java classes that can detect and record an input (and if possible, give frequency or values that can be plugged into FFT?)? 此外,是否有人可以推荐任何可以检测和记录输入的Java类(如果可能,还可以提供可以插入FFT的频率或值?)?

Thanks in advance. 提前致谢。

Input to your FFT will be a time-domain signal representing the audio. FFT的输入将是表示音频的时域信号。 If you record some sound for a second from the mic, this will really contain a wave that is made up of various frequencies at different amounts - hopefully mostly the frequency/frequencies corresponding to the note which you are playing, plus some outside noise and noise introduced by the microphone and electronics. 如果你从麦克风录下一些声音一秒钟,这将包含一个由不同频率的不同频率组成的波 - 希望主要是与您正在播放的音符对应的频率/频率,加上一些外部噪音和噪音麦克风和电子产品推出。 If in that 1 second you happen to have, say, 512 time points (so the mic can sample at 512 times a second), then each of those time points represents the intensity picked up by the mic. 如果在那1秒内你碰巧有512个时间点(所以麦克风可以每秒512次采样),那么每个时间点都代表麦克风拾取的强度。 These sound intensity values can be turned from their time-domain representation to a frequency-domain representation using the FFT. 可以使用FFT将这些声强值从其时域表示转换为频域表示。

If you now give this to the FFT, as it is a real-valued input, you will get a symmetric complex output (symmetric around the central value) and can ignore the second half of the complex vector output and use only the first half - ie the second half will be symmetric (and thus "identical") to the first half. 如果你现在将它赋予FFT,因为它是一个实值输入,你将获得一个对称的复数输出(围绕中心值对称)并且可以忽略复数向量输出的后半部分并仅使用前半部分 - 即,后半部分将与前半部分对称(因此“相同”)。 The output represents the contributions of each frequency to the input waveform - in essence, each "bin" or array index contains information about that frequency's amplitude. 输出表示每个频率对输入波形的贡献 - 实质上,每个“bin”或数组索引包含有关该频率幅度的信息。 To extract the amplitude you want to do: 要提取您想要的振幅:

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

where real and imaginary are the real and imaginary parts of the complex number at that frequency bin. real imaginary和虚数是该频率仓中复数的实部和虚部。 To get the frequency corresponding to a given bin, you need the following: 要获得与给定bin相对应的频率,您需要以下内容:

frequency = i * Fs / N;

where i is bin or array index number, Fs the sampling frequency and N the number of data points. 其中i是bin或数组索引号, Fs是采样频率, N是数据点数。 From a project of mine wherein I recently used the FFT: 来自我最近使用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]);
        }

The divisions by 64 and 40 are arbitrary and useful for my case only, to only get certain frequency components, as opposed to all frequencies, which you might want. 64和40的除法是任意的,仅对我的情况有用,只能得到某些频率成分,而不是你想要的所有频率。 You can easily do all this in real time. 您可以轻松实时完成所有这些操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM