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);
}
}
单击特定按钮后,我想要它让我的音频播放十五次,并且每次都让进度条递增。我还曾设想在每次播放音频之间有一个延迟。
目前发生的情况是,所有的哔哔声都会毫不延迟地连续播放,之后,进度条会立即增加到最大值。以某种方式使用 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);
}
}