ANDROID: How would I add a delay in a for loop which plays an audiofile?

时间:2018-04-18 11:08:00

标签: android audiotrack

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.

1 个答案:

答案 0 :(得分:0)

要解决您的问题,您可以使用AsynkTask&lt;&gt;像这样:

创建AsynkTask的子类&lt;&gt;在您的Activity中处理延迟操作和进度条的更新。

然后在你的click1() - 方法中,你只需要创建一个AsyncTask子类的新实例并执行它。您可以在调用execute()时给它循环次数。以下代码应该有效:

...
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);
    }
}