问题
I am building an android application that displays the Frequency of a sustained note with the FFT algorithm. I am using Jtransform methods. My issue currently is that I can't display the frequency on screen. The following code is the fft freqency calculation and the AsynchTask which should display the frequency in a text box
import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;
public class Tuning extends Activity implements OnClickListener{
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
private DoubleFFT_1D fft; // The fft double array
int blockSize = 1024; // deal with this many samples at a time
int sampleRate = 44100; // 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
// On Start Up
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.tuning);
tv = (TextView) findViewById(R.id.lbl1);
}
// The Record and analysis class
private class RecordAudio extends AsyncTask<Void, Double, Void>{
@Override
protected Void doInBackground(Void... params){
/*Calculates the fft and frequency of the input*/
try{
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[] audioDataDoubles = new double[(blockSize*2)]; // Same values as above, as doubles
double[] re = new double[blockSize];
double[] im = new double[blockSize];
double[] magnitude = new double[blockSize];
audioRecord.startRecording(); // Start working
fft = new DoubleFFT_1D(blockSize);
while(started){
/* Reads the data from the microphone. it takes in data
* to the size of the window "blockSize". The data is then
* given in to audioRecord. The int returned is the number
* of bytes that were read*/
int bufferReadResult = audioRecord.read(buffer, 0, blockSize);
// Read in the data from the mic to the array
for(int i = 0; i < blockSize && i < bufferReadResult; i++) {
/* dividing the short by 32768.0 gives us the
* result in a range -1.0 to 1.0.
* Data for the compextForward is given back
* as two numbers in sequence. Therefore audioDataDoubles
* needs to be twice as large*/
audioDataDoubles[2*i] = (double) buffer[i]/32768.0; // signed 16 bit
audioDataDoubles[(2*i)+1] = 0.0;
}
//audiodataDoubles now holds data to work with
fft.complexForward(audioDataDoubles);
// Calculate the Real and imaginary and Magnitude.
for(int i = 0; i < blockSize; i++){
// real is stored in first part of array
re[i] = audioDataDoubles[i*2];
// imaginary is stored in the sequential part
im[i] = audioDataDoubles[(i*2)+1];
// magnitude is calculated by the square root of (imaginary^2 + real^2)
magnitude[i] = Math.sqrt((re[i] * re[i]) + (im[i]*im[i]));
}
double peak = -1.0;
// Get the largest magnitude peak
for(int i = 0; i < blockSize; i++){
if(peak < magnitude[i])
peak = magnitude[i];
}
// calculated the frequency
frequency = (sampleRate * peak)/blockSize;
/* calls onProgressUpdate
* publishes the frequency
*/
publishProgress(frequency);
}
} catch(Throwable t){
Log.e("AudioRecord", "Recording Failed");
}
return null;
}
// This should display the Frequency
protected void onProgressUpdate(Double value){
//print the frequency
setContentView(R.layout.tuning);
String info = Double.toString(value);
//TextView doubleView = (TextView) findViewById(R.id.DoubleView);
tv.setText(info);
}
// For the click of the button
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();
}
}
I have checked other similar questions and I can't find the fault in my code.
EDIT: added onClick()
to code. I know that the frequency is being calculated, and according to Eclipse, at no point is the onProgressUpdate()
being called.
回答1:
In addition to what Alexei said, in his answer, I think you have also incorrectly coded the method signature of onProgressUpdate()
:
protected void onProgressUpdate(Double value){
This means that your version of onProgressUpdate()
is actually not overriding anything from AsyncTask, and will never be called.
So, including the point about not calling setContentView()
repeatedly, your final method should look like this:
protected void onProgressUpdate(Double... frequencies){
//print the frequency
String info = Double.toString(frequencies[0]);
tv.setText(info);
}
回答2:
SetContentView in onProgressUpdate is an error. You really do not want to change layout xml
回答3:
Try replace
protected void onProgressUpdate(Double value){
//print the frequency
setContentView(R.layout.tuning);
String info = Double.toString(value);
with
protected void onProgressUpdate(Double... value){
//print the frequency
String info = Double.toString(value[0]);
For others not having jtransforms.jar, refer to http://sourceforge.net/projects/jtransforms/
来源:https://stackoverflow.com/questions/16652999/displaying-a-double-frequency-that-is-updated-constantly-while-recording-with