问题描述
我正在构建一个使用 FFT 算法显示持续音符频率的 android 应用程序.我正在使用 Jtransform 方法.我目前的问题是我无法在屏幕上显示频率.以下代码是 fft 频率计算和应在文本框中显示频率的 AsynchTask
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:将 onClick()
添加到代码中.我知道正在计算频率,并且根据 Eclipse,在任何时候都不会调用 onProgressUpdate()
.
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.
推荐答案
除了 Alexei 所说的,在他的回答中,我认为你也错误地编码了onProgressUpdate()
的方法签名:
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){
这意味着您的 onProgressUpdate()
版本实际上并没有覆盖任何内容 来自 AsyncTask,并且永远不会被调用.
This means that your version of onProgressUpdate()
is actually not overriding anything from AsyncTask, and will never be called.
所以,包括关于不要重复调用setContentView()
的点,你的最终方法应该是这样的:
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);
}
这篇关于显示在使用 Android 录制时不断更新的双倍(频率)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!