After a particular button is clicked, I want to have it so that my audio would play fifteen times, and have the progress bar increment each time. I had also envisioned having a delay in between each time the audio plays.
What's currently happening is that all of the beeps play back to back without delay, and after that, the progress bar gets incremented right to max straight away. Using Handler somehow doesn't manage to delay the audio playing.
I'm a beginner in app development, so excuse the shoddy code:
public void click1(View view) throws IOException {
int i;
// ProgressBar1.setProgress(0);
for (i = 1; i < 16; i = i + 1)
{
int secs = 2; // Delay in seconds
Utils.delay(secs, new Utils.DelayCallback() {
@Override
public void afterDelay() throws IOException {
// Do something after delay
PlayShortAudioFileViaAudioTrack(500, 1);
ProgressBar1.incrementProgressBy(1);
}
});
}
}
Here's the delay code:
public class Utils {
public interface DelayCallback{
void afterDelay() throws IOException;
}
public static void delay(int secs, final DelayCallback delayCallback){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
try {
delayCallback.afterDelay();
} catch (IOException e) {
e.printStackTrace();
}
}
}, secs * 1000); // afterDelay will be executed after (secs*1000) milliseconds.
}
}
The function that plays audio is
public void PlayShortAudioFileViaAudioTrack(int f, double duration) throws IOException
{ int sampleRate = 48000; // Samples per second
//double duration = 2.0;
long numFrames = (long)(duration * sampleRate);
long frameCounter = 0;
int intSize = android.media.AudioTrack.getMinBufferSize(48000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_FLOAT);
AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
AudioFormat.ENCODING_PCM_FLOAT, intSize, AudioTrack.MODE_STREAM);
float[] buffer = new float[intSize];
while (frameCounter < numFrames)
{
long remaining = numFrames - frameCounter;
int toWrite = (remaining > intSize) ? intSize : (int) remaining;
for (int s=0 ; s<toWrite ; s++, frameCounter++)
{
buffer[s] = (float)Math.sin(2.0 * Math.PI * f * frameCounter / sampleRate);
// buffer[1][s] = Math.sin(2.0 * Math.PI * 500 * frameCounter / sampleRate);
}
if (at!=null) {
// Write the byte array to the track
at.play();
at.write(buffer, 0, intSize, AudioTrack.WRITE_BLOCKING);
}
else
Log.d("TCAudio", "audio track is not initialised ");
}
at.stop();
at.release();
}
Changing the audiotrack mode to NON-BLOCKING from BLOCKING results in the audio just playing once, and the progress bar still shooting up to full immediately.
To solve your problem, you can use AsynkTask<> like this:
Create a subclass of AsynkTask<> in your Activity to handle the delayed action and the updates of the progressbar.
Then in your click1()-method you just have to create a new instance of your AsyncTask subclass and execute it. You can give it the number of cycles on the call of execute(). The following code should work:
...
ProgressBar1.setMax(16); // to get 16 cycles like in your example
...
public void click1(View view) throws IOException {
int max = ProgressBar1.getMax();
new MyTask().execute(max);
}
class MyTask extends AsyncTask<Integer, Integer, Void> {
@Override
protected Void doInBackground(Integer... params) {
for (int i=0 ; i <= params[0]; i++) {
try {
Thread.sleep(secs * 1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPreExecute() {
//do something before execution
}
@Override
protected void onProgressUpdate(Integer... values) {
//do your delayed stuff
PlayShortAudioFileViaAudioTrack(500, 1);
ProgressBar1.incrementProgressBy(1);
}
}