I have an app that has a ball running across the screen. When the ball is halfway the application records some audio, computes the FFT and does some extra analysis.
This is handled by Asynctask, however the animation still briefly stutters.
Does anyone have any suggestions on how to make it run smoother?
Thanks
code below:
import com.ben.applicationLayer.GameView;
import dataObjectLayer.Sprite;
import dataObjectLayer.MusicalNote;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.media.AudioFormat;
import android.os.AsyncTask;
public class recorderThread extends AsyncTask<Sprite, Void, Integer> {
short[] audioData;
int bufferSize;
Sprite ballComp;
@Override
protected Integer doInBackground(Sprite... ball) {
MusicalNote note = ball[0].expectedNote;
ballComp = ball[0];
boolean recorded = false;
double frequency;
int sampleRate = 8192;
AudioRecord recorder = instatiateRecorder(sampleRate);
double[] magnitude = new double[1024];
double[] audioDataDoubles = new double[2048];
while (!recorded) { //loop until recording is running
if (recorder.getState()==android.media.AudioRecord.STATE_INITIALIZED)
// check to see if the recorder has initialized yet.
{
if (recorder.getRecordingState()==android.media.AudioRecord.RECORDSTATE_STOPPED)
recorder.startRecording();
//check to see if the Recorder has stopped or is not recording, and make it record.
else {
double max_index;
recorder.read(audioData,0,bufferSize);
//read the PCM audio data into the audioData array
computeFFT(audioDataDoubles, magnitude);
max_index = getLargestPeakIndex(magnitude);
frequency = getFrequencyFromIndex(max_index, sampleRate);
//checks if correct frequency, assigns number
int correctNo = correctNumber(frequency, note);
checkIfMultipleNotes(correctNo, max_index, frequency, sampleRate, magnitude, note);
if (audioDataIsNotEmpty())
recorded = true;
if (correctNo!=1)
return correctNo;
}
}
else
{
recorded = false;
recorder = instatiateRecorder(sampleRate);
}
}
if (recorder.getState()==android.media.AudioRecord.RECORDSTATE_RECORDING)
{
killRecorder(recorder);
}
return 1;
}
private void killRecorder(AudioRecord recorder) {
recorder.stop(); //stop the recorder before ending the thread
recorder.release(); //release the recorders resources
recorder=null; //set the recorder to be garbage collected
}
@Override
protected void onPostExecute(Integer result) {
(result == 2)
GameView.score++;
}
private AudioRecord instatiateRecorder(int sampleRate) {
bufferSize= AudioRecord.getMinBufferSize(sampleRate,AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_16BIT)*2;
//get the buffer size to use with this audio record
AudioRecord recorder = new AudioRecord (AudioSource.MIC,sampleRate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,bufferSize); //instantiate the AudioRecorder
audioData = new short [bufferSize]; //short array that pcm data is put into.
return recorder;
}
}
As Mohammed says, it's hard to guess what the problem might be without seeing the code. With that in mind...
It sounds like your
AsyncTask
might be blocking other threads from executing. Make sure you have some calls toThread.sleep()
in there to give the scheduler chance to switch back to the UI thread (Thread.yield()
is also an option, but be aware there are some gotchas with yield).without code it will be hard to guess with can optimize, but I will tell you what I did with more than 1 million operations in loading .. • If you have problem with performance, try : 1-check your data type of variables and set lower in case you are sure variable doesn't need more byte, i.e. for size you short instead of int.
2-check your code and try to get all results can be stored for next launch, and call them next time instead of calculating them again.
• But if your problem that animation is slow and you have no problem with memory, so try reduce period of animation or increase units of movements.
by the way how do you implement the animation? frame-by-frame animation, or layout animation, or view animation ?
Using an Asynctask is along the lines of what you want to do. However, I would suggest using a thread-pool. You can then put your animation in as a task, add your audio recording as a task, the FFT as another task, and your additional analysis as a task.
The brief stutter is likely the result of allocating resources for the recording in the animation thread. Using a pool means you won't have to pause while creating the thread to run your audio tasks. Obviously, some code would be handy to fully understand your problem.
Take a look at:
ScheduledThreadPoolExecutor http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html
or
ThreadPoolExecutor http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html
A very simple example of what you might want to do:
In your activity you can define this to start up the tasks
Ball.java
Recording.java