I am trying to obtain frequency from a Microphone using FFT. Which is given here- http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29
The FFT function takes in three parameters, the real, imaginary and a boolean value. The real and the imaginary portions are obtained from the recorded buffer.
The FFT function returns an array, from which the index of the largest magnitude is calculated. This is used to get the frequency.
But when i run the application I am not getting the desired frequency values. Is there something wrong with my sampling rate/buffersize/blocksize? Or is there something wrong with the calculation itself.
public class MainActivity extends Activity {
int audioSource = MediaRecorder.AudioSource.MIC; // Audio source is the device MIC
int channelConfig = AudioFormat.CHANNEL_IN_MONO; // Recording in mono
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // Records in 16bit
int blockSize = 1024; // deal with this many samples at a time
int sampleRate = 8000; // Sample rate in Hz
public double frequency = 0.0; // the frequency given
RecordAudio recordTask; // Creates a Record Audio command
TextView tv; // Creates a text view for the frequency
boolean started = false;
Button startStopButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
startStopButton = (Button) findViewById(R.id.button1);
startStopButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View v){
if (started) {
started = false;
startStopButton.setText("Start");
recordTask.cancel(true);
}
else{
started = true;
startStopButton.setText("Stop");
recordTask = new RecordAudio();
recordTask.execute();
}
}
});
}
private class RecordAudio extends AsyncTask<Void, Double, Void> {
@Override
protected Void doInBackground(Void... params) {
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding); // Gets the minimum buffer needed
AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize); // The RAW PCM sample recording
short[] buffer = new short[blockSize]; // Save the raw PCM samples as short bytes
double[] re = new double[blockSize];
double[] im = new double[blockSize];
double[] magnitude = new double[blockSize];
try {
audioRecord.startRecording(); //Start
} catch (Throwable t) {
}
while (started) {
int bufferReadResult = audioRecord.read(buffer, 0, blockSize);
for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
re[i] =((double) buffer[i] / 32768.0); // signed 16 bit
im[i]=0;
}
double[] newArray = new double[blockSize*2];
newArray = FFTbase.fft(re, im,true);
double real;
double imag;
for(int i=0;i<(newArray.length/2)-1;i++)
{
real=newArray[2*i];
imag=newArray[2*i+1];
magnitude[i]=Math.sqrt(real*real+imag*imag);
}
double MaxMagn=-1.0;
int index=0;
for (int i = 0; i < (magnitude.length); i++) {
if (magnitude[i]>MaxMagn)
{
MaxMagn = magnitude[i];
index=i;
}
}
publishProgress((double)(index * sampleRate)/blockSize);
}
return null;
}
@Override
protected void onProgressUpdate(Double... values) {
TextView display = (TextView) findViewById(R.id.textView1);
display.setText(String.valueOf(values[0]));
}
}
This is the zero crossing method which i tried. But this also did not give me the desired frequency.
public class MainActivity extends Activity {
int audioSource = MediaRecorder.AudioSource.MIC; // Audio source is the device MIC
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO; // Recording in mono
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // Records in 16bit
int blockSize = 256; // deal with this many samples at a time
int sampleRate = 8000; // Sample rate in Hz
public double frequency = 0.0; // the frequency given
RecordAudio recordTask; // Creates a Record Audio command
TextView tv; // Creates a text view for the frequency
boolean started = false;
Button startStopButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
startStopButton = (Button) findViewById(R.id.button1);
startStopButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View v){
if (started) {
started = false;
startStopButton.setText("Start");
recordTask.cancel(true);
}
else{
started = true;
startStopButton.setText("Stop");
recordTask = new RecordAudio();
recordTask.execute();
}
}
});
}
private class RecordAudio extends AsyncTask<Void, Double, Void> {
@Override
protected Void doInBackground(Void... params) {
int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding); // Gets the minimum buffer needed
AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize); // The RAW PCM sample recording
short[] buffer = new short[blockSize]; // Save the raw PCM samples as short bytes
double[] re = new double[blockSize];
double[] im = new double[blockSize];
double[] magnitude = new double[blockSize];
try {
audioRecord.startRecording(); //Start
} catch (Throwable t) {
}
int sampling=0;
while (started) {
sampling++;
int bufferReadResult = audioRecord.read(buffer, 0, blockSize);
int numCrossing=0; //initialize your number of zero crossings to 0
int p=0;
for (p=0;p<bufferSize/4;p+=4) {
if (buffer[p]>0 && buffer[p+1]<=0) numCrossing++;
if (buffer[p]<0 && buffer[p+1]>=0) numCrossing++;
if (buffer[p+1]>0 && buffer[p+2]<=0) numCrossing++;
if (buffer[p+1]<0 && buffer[p+2]>=0) numCrossing++;
if (buffer[p+2]>0 && buffer[p+3]<=0) numCrossing++;
if (buffer[p+2]<0 && buffer[p+3]>=0) numCrossing++;
if (buffer[p+3]>0 && buffer[p+4]<=0) numCrossing++;
if (buffer[p+3]<0 && buffer[p+4]>=0) numCrossing++;
}//for p
for (p=(bufferSize/4)*4;p<bufferSize-1;p++) {
if (buffer[p]>0 && buffer[p+1]<=0) numCrossing++;
if (buffer[p]<0 && buffer[p+1]>=0) numCrossing++;
}
frequency=(sampleRate/bufferSize)*(numCrossing/2);
if(sampling>20){
//publishProgress((double)(index * sampleRate)/bufferSize);
publishProgress((double)frequency);
sampling=0;
}}
return null;
}