Obtenga audio wav de frecuencia usando FFT y clase Compleja
Se le ha preguntado mucho, pero todavía me quedé con FFT implementar la clase en Android Tengo que procesar mis datos de audio usando FFT …
Ya he leído casi la misma pregunta aquí ¿Cómo puedo obtener datos de frecuencia de PCM utilizando FFT y aquí Cómo obtener la frecuencia de fft resultado? Y más preguntas pero todavía no encuentro ninguna respuesta incluso después de que probé las respuestas dadas …
- Obtener la frecuencia de un archivo de audio en cada 1/4 segundos en android
- Nexus 5 gps tasa de actualización
- ¿Alguna librería AFSK para Android? (Para la entrada de datos a través de la toma de auriculares Android)
- Android AudioRecord preguntas?
- ¿Cuál es la forma más confiable para determinar la frecuencia de reloj de la CPU de los teléfonos Android?
Clase de FFT que estoy usando: http://www.cs.princeton.edu/introcs/97data/FFT.java
La clase compleja para ir con ella: http://introcs.cs.princeton.edu/java/97data/Complex.java.html
Aquí está mi código
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; } } } }; }
Supongo que la matriz audioData contiene los datos de audio sin formato, pero mi código captura la excepción y devuelve "N no es una potencia de 2"
¿Es algo malo con mi código? ¿Cómo puedo pasar a FFT.java clase y obtener el fftResult?
¿O hay otra manera de convertir datos de dominio de tiempo a datos de frecuencia que más fácil?
Han pasado unos meses desde que me quedé atascado con esto … Mi proyecto es demasiado comparar 2 audio de archivos * .wav, Cualquier ayuda sería apreciada … 🙂
- FSK modulación y reproducción sine Tone en Android
- Android obtener frecuencias de sonido en tiempo real?
- Reproducir tono estéreo en Android
- ¿Cómo obtener sólo frecuencia de audio y decibles del proyecto FFTBasedSpectrumAnalyzer?
- Cómo utilizar el filtro Band Pass (18Khz a 22Khz) en Android
Ya encontré la respuesta … 🙂
Creo el método para calcular el valor del arsenal del 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; }
Entonces lo llamé en clase Escribir Audio ..
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(); } } }
Suena como su problema inmediato es "N no es un poder de 2." En este caso, N probablemente se refiere al tamaño de los datos que está poniendo en su FFT. La mayoría de los algoritmos FFT sólo funcionan en bloques de datos que tienen un tamaño que es una potencia de 2.
¿Está tratando de poner todo el archivo en una FFT a la vez? Si es así, puede que tenga que leer más material de fondo para entender lo que está haciendo. Tal vez empezar aquí: http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html