ANDROID:如何在播放音频文件的 for 循环中添加延迟?

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

单击特定按钮后,我想要它让我的音频播放十五次,并且每次都让进度条递增。我还曾设想在每次播放音频之间有一个延迟。

目前发生的情况是,所有的哔哔声都会毫不延迟地连续播放,之后,进度条会立即增加到最大值。以某种方式使用 Handler 无法延迟音频播放。

我是应用程序开发的初学者,所以请原谅伪劣代码:

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

这是延迟代码:

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

播放音频的函数是

    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();

}

将音轨模式从 BLOCKING 更改为 NON-BLOCKING 会导致音频只播放一次,并且进度条仍会立即充满。

要解决您的问题,您可以像这样使用 AsynkTask<>:

在您的 Activity 中创建 AsynkTask<> 的子类来处理延迟的操作和进度条的更新。

然后在您的 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);
    }
}