Get wav audio frequency using FFT and complex class

They asked a lot about this, but I'm still stuck about implementing the FFT class on Android, I need to process my audio data using FFT ...

I already read almost the same question here How can I get frequency data from PCM using FFT and here How can I get frequency from FFT result ? and more questions, but still haven't found the answer, even after I tried the answers given ...

The FFT class that I use: http://www.cs.princeton.edu/introcs/97data/FFT.java

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

Here is my code

import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.widget.Button; public class Latihan extends Activity{ private static final int RECORDER_BPP = 16; private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav"; private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder"; private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw"; 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; short[] audioData; private AudioRecord recorder = null; private int bufferSize = 0; private Thread recordingThread = null; private boolean isRecording = false; Complex[] fftTempArray; Complex[] fftArray; int[] bufferData; int bytesRecorded; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.p1); setButtonHandlers(); enableButtons(false); bufferSize = AudioRecord.getMinBufferSize (RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING)*3; audioData = new short [bufferSize]; //short array that pcm data is put into. } private void setButtonHandlers() { ((Button)findViewById(R.id.btStart)).setOnClickListener(btnClick); ((Button)findViewById(R.id.btStop)).setOnClickListener(btnClick); } private void enableButton(int id,boolean isEnable){ ((Button)findViewById(id)).setEnabled(isEnable); } private void enableButtons(boolean isRecording) { enableButton(R.id.btStart,!isRecording); enableButton(R.id.btStop,isRecording); } private String getFilename(){ String filepath = Environment.getExternalStorageDirectory().getPath(); File file = new File(filepath,AUDIO_RECORDER_FOLDER); if(!file.exists()){ file.mkdirs(); } return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV); } public void convert(){ } public void calculate(){ Complex[] fftTempArray = new Complex[bufferSize]; for (int i=0; i<bufferSize; i++) { fftTempArray[i] = new Complex(audioData[i], 0); } Complex[] fftArray = FFT.fft(fftTempArray); double[] micBufferData = new double[bufferSize]; final int bytesPerSample = 2; final double amplification = 100.0; for (int index = 0, floatIndex = 0; index < bytesRecorded - bytesPerSample + 1; index += bytesPerSample, floatIndex++) { double sample = 0; for (int b = 0; b < bytesPerSample; b++) { int v = bufferData[index + b]; if (b < bytesPerSample - 1 || bytesPerSample == 1) { v &= 0xFF; } sample += v << (b * 8); } double sample32 = amplification * (sample / 32768.0); micBufferData[floatIndex] = sample32; } } private String getTempFilename(){ String filepath = Environment.getExternalStorageDirectory().getPath(); File file = new File(filepath,AUDIO_RECORDER_FOLDER); if(!file.exists()){ file.mkdirs(); } File tempFile = new File(filepath,AUDIO_RECORDER_TEMP_FILE); if(tempFile.exists()) tempFile.delete(); return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE); } private void startRecording(){ recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize); recorder.startRecording(); isRecording = true; recordingThread = new Thread(new Runnable() { public void run() { writeAudioDataToFile(); } },"AudioRecorder Thread"); recordingThread.start(); } private void writeAudioDataToFile(){ byte data[] = new byte[bufferSize]; String filename = getTempFilename(); FileOutputStream os = null; try { os = new FileOutputStream(filename); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } int read = 0; if(null != os){ while(isRecording){ read = recorder.read(data, 0, bufferSize); if(AudioRecord.ERROR_INVALID_OPERATION != read){ try { os.write(data); } catch (IOException e) { e.printStackTrace(); } } } try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } private void stopRecording(){ if(null != recorder){ isRecording = false; recorder.stop(); recorder.release(); recorder = null; recordingThread = null; } copyWaveFile(getTempFilename(),getFilename()); // deleteTempFile(); } private void deleteTempFile() { File file = new File(getTempFilename()); file.delete(); } private void copyWaveFile(String inFilename,String outFilename){ FileInputStream in = null; FileOutputStream out = null; long totalAudioLen = 0; long totalDataLen = totalAudioLen + 36; long longSampleRate = RECORDER_SAMPLERATE; int channels = 2; long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8; byte[] data = new byte[bufferSize]; try { in = new FileInputStream(inFilename); out = new FileOutputStream(outFilename); totalAudioLen = in.getChannel().size(); totalDataLen = totalAudioLen + 36; AppLog.logString("File size: " + totalDataLen); WriteWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate); while(in.read(data) != -1){ out.write(data); } in.close(); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void WriteWaveFileHeader( FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate, int channels, long byteRate) throws IOException { //another code } private View.OnClickListener btnClick = new View.OnClickListener() { public void onClick(View v) { switch(v.getId()){ case R.id.btStart:{ AppLog.logString("Start Recording"); enableButtons(true); startRecording(); break; } case R.id.btStop:{ AppLog.logString("Stop Recording"); enableButtons(false); stopRecording(); calculate(); break; } } } }; } 

I assume that the audioData array contains raw audio data, but my code catches the exception and returns "N is not a power of 2"

Is there something wrong with my code? How do I pass it to the FFT.java class and get fftResult ??

Or is there another way to convert data in the time domain into frequency data that is simpler?

It has been several months since I got stuck with this ... My project too compares 2 * .wav audio files, any help would be appreciated ... :)

+8
source share
2 answers

I already found the answer ... :)

I am creating a method to calculate the value of an array from audio ...

 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); // --> Here I use FFT class 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; } 

Then I called it in the Write Audio class ..

 private void writeAudioDataToFile(){ byte data[] = new byte[bufferSize]; String filename = getTempFilename(); FileOutputStream os = null; try { os = new FileOutputStream(filename); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } int read = 0; if(null != os){ while(isRecording){ read = recorder.read(data, 0, bufferSize); if(read > 0){ absNormalizedSignal = calculateFFT(data); // --> HERE ^__^ } if(AudioRecord.ERROR_INVALID_OPERATION != read){ try { os.write(data); } catch (IOException e) { e.printStackTrace(); } } } try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } 
+7
source

It seems your immediate problem: "N is not a force of 2." In this case, N probably refers to the size of the data you enter into your FFT. Most FFT algorithms work only on data blocks whose size is 2.

Are you trying to immediately put the entire file in the FFT? If so, you may need to read more reference materials to understand what you are doing. Maybe start here: http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html

0
source

Source: https://habr.com/ru/post/949094/


All Articles