java 从音频文件计算FFT

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17565269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 02:20:32  来源:igfitidea点击:

Calculate FFT from audio file

javaaudiofftaudiotrack

提问by raisa_

Before, I asked question about Get frequency wav audio using FFT and Complex class,

之前,我问过关于使用 FFT 和复杂类获取频率 wav 音频的问题,

There, I need to calculate FFT value from AudioRecord input --> from microphone , I somehow managed to get the FFT value...

在那里,我需要从 AudioRecord 输入计算 FFT 值 --> 从麦克风,我以某种方式设法获得了 FFT 值......

Now I need to calculate FFT value from *.wav audio file that I saved before, I saved the audio in 'raw' folder inside 'res' folder from my project

现在我需要从我之前保存的 *.wav 音频文件中计算 FFT 值,我将音频保存在我项目的“res”文件夹内的“raw”文件夹中

I still using the same FFT Class: http://www.cs.princeton.edu/introcs/97data/FFT.java

我仍然使用相同的 FFT 类:http: //www.cs.princeton.edu/introcs/97data/FFT.java

The complex class to go with it: http://introcs.cs.princeton.edu/java/97data/Complex.java.html

与之配套的复杂类:http: //introcs.cs.princeton.edu/java/97data/Complex.java.html

I use this method to read audio file from my raw foldern, then I call method calculateFFT to go with it

我使用这种方法从我的原始文件夹中读取音频文件,然后我调用方法 calculateFFT 来配合它

private static final int RECORDER_BPP = 16;
  private static final int RECORDER_SAMPLERATE = 44100;
  private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
  private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;


private void asli(){

            int counter = 0;
            int data;
            InputStream inputStream  = getResources().openRawResource(R.raw.b1);
            DataInputStream dataInputStream = new DataInputStream(inputStream);
            List<Integer> content = new ArrayList<Integer>(); 

            try {
                while ((data = dataInputStream.read()) != -1) {
                    content.add(data);
                    counter++; }
            } catch (IOException e) {
                e.printStackTrace();}

                int[] b = new int[content.size()];
                int cont = 0;
                byte[] audio = convertArray(b);
        }

Method to convert to byte

转换为字节的方法

public byte[] convertArray(int[] array) { 

            int minBufferSize = AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING);
                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING,minBufferSize, AudioTrack.MODE_STREAM);

        byte[] newarray = new byte[array.length];
        for (int i = 0; i < array.length; i++) {
        newarray[i] = (byte) ((array[i]) & 0xFF);       }

            absNormalizedSignal = calculateFFT(newarray);
            return newarray;
        }

And this is the CalculateFFT method

这是CalculateFFT方法

public double[] calculateFFT(byte[] signal)
        {           
            final int mNumberOfFFTPoints =1024;
            double mMaxFFTSample;
            double temp;
            Complex[] y;
            Complex[] complexSignal = new Complex[mNumberOfFFTPoints];
            double[] absSignal = new double[mNumberOfFFTPoints/2];

            for(int i = 0; i < mNumberOfFFTPoints; i++){
                temp = (double)((signal[2*i] & 0xFF) | (signal[2*i+1] << 8)) / 32768.0F;
                complexSignal[i] = new Complex(temp,0.0);
            }

            y = FFT.fft(complexSignal);

            mMaxFFTSample = 0.0;
            mPeakPos = 0;
            for(int i = 0; i < (mNumberOfFFTPoints/2); i++)
            {
                 absSignal[i] = Math.sqrt(Math.pow(y[i].re(), 2) + Math.pow(y[i].im(), 2));
                 if(absSignal[i] > mMaxFFTSample)
                 {
                     mMaxFFTSample = absSignal[i];
                     mPeakPos = i;
                 } 
            }

            return absSignal;

        }

I used this CalculateFFT method too to process audio from AudioRecorder --> that one with microphone input before... I managed to get value from the AudioRecorder, but I failed to get value from my audio file... I'm not planning to play the audio.. I just need to process it with FFT.

我也使用了这种CalculateFFT 方法来处理来自AudioRecorder 的音频--> 之前带有麦克风输入的那个...我设法从AudioRecorder 中获得了价值,但是我未能从我的音频文件中获得价值......我没有计划播放音频.. 我只需要用 FFT 处理它。

Is there any wrong with my code ?? :o Seems like I fail at getting value from method Asli(); But I dont know which part is wrong..

我的代码有问题吗??:o 好像我没能从方法 Asli() 中获取价值;但我不知道哪个部分是错误的..

Any help would be appreciated... :) Thanks

任何帮助将不胜感激... :) 谢谢

采纳答案by Nicholas DiPiazza

I spent a better part of the morning coding a solution for this using bits and pieces of FFT java snippets I was finding... but then I stumbled upon this amazingly wondeful google code project that has a bunch of util classes for doing signal processing tasks on WAV and MP3 files alike.

我花了一个上午的大部分时间,使用我找到的 FFT java 片段的零碎部分为此编写了一个解决方案……但后来我偶然发现了这个非常棒的谷歌代码项目,它有一堆用于执行信号处理任务的 util 类WAV 和 MP3 文件。

https://github.com/Uriopass/audio-analysisFormerly SVN export was on Google code here: https://storage.googleapis.com/google-code-archive-source/v2/code.google.com/audio-analysis/source-archive.zip

https://github.com/Uriopass/audio-analysis以前 SVN 导出在谷歌代码上:https: //storage.googleapis.com/google-code-archive-source/v2/code.google.com/audio-分析/源归档.zip

It now becomes INSANELY easy:

现在变得非常简单:

WaveDecoder decoder = new WaveDecoder(new FileInputStream(wavFile));
FFT fft = new FFT(1024, wavFileObj.getSampleRate());

Now you can use the fft object to do various calculations. They have a bunch of great examples, such as generating a List containing the spectral flux:

现在您可以使用 fft 对象进行各种计算。他们有很多很好的例子,比如生成一个包含光谱通量的列表:

    float[] samples = new float[1024];
    float[] spectrum = new float[1024 / 2 + 1];
    float[] lastSpectrum = new float[1024 / 2 + 1];
    List<Float> spectralFlux = new ArrayList<Float>();

    while (decoder.readSamples(samples) > 0) {
        fft.forward(samples);
        System.arraycopy(spectrum, 0, lastSpectrum, 0, spectrum.length);
        System.arraycopy(fft.getSpectrum(), 0, spectrum, 0, spectrum.length);

        float flux = 0;
        for (int i = 0; i < spectrum.length; i++)
            flux += (spectrum[i] - lastSpectrum[i]);
        spectralFlux.add(flux);
    }

My company needed a way for me to analyze some audio to see if some expected hold music had happened. So first I generated a WAV file for an example that did have the hold music. Then I captured some audio of one of thee examples that did not have the hold music. Now all that is left is to average up the spectral flux of the wav and I'm set.

我的公司需要一种方法让我分析一些音频,看看是否发生了一些预期的保持音乐。所以首先我生成了一个 WAV 文件作为一个例子,它确实有保持音乐。然后我捕获了其中一个没有保持音乐的示例的音频。现在剩下的就是平均 wav 的频谱通量,我就设置好了。

Note: I could not have simply taken amplitudes... but the fourier transformation has frequencies that I could correctly use to make my comparison.

注意:我不能简单地取振幅……但傅立叶变换具有我可以正确使用的频率来进行比较。

I love math.

我爱数学。