我有许多简短的音频片段,应该以最小的延迟顺序播放。
如何有效地排队这些声音?
我可以通过两种方式看到它的工作原理:使用 aMediaPlayer
或 aSoundPool
媒体播放器
您可以将MediaPlayer.OnCompletionListener与文件列表结合使用,以简单地侦听完成并播放下一个。总的来说,这工作得很好,我用它来播放非常短的剪辑(< 1s)序列而没有问题。
声池
另一种方法是使用SoundPool类和一个处理程序来简单地提前排队播放事件。这假设您知道每个剪辑的长度,但根据格式,您应该能够找到它。
您选择哪种解决方案取决于许多因素:文件的数量、文件的长度、文件的格式、从哪里获取文件、列表的固定或可变程度等。
就我个人而言,我会选择这样做,MediaPlayer
因为这更容易实现,并且可能会满足您的需求。
一种方法是将它们连接成一个音频文件,然后为其创建一个 MediaPlayer 并设置一个 OnSeekCompleteListener。以您喜欢的任何顺序查找 tern 中的每个片段,然后在 onSeekComplete() 中播放它们。它的时间不准确,而且 MediaPlayer 使用起来很敏感,所以它可能不是你的最佳选择,但它对我的目的来说已经足够了。
这是我的代码:
private MediaPlayer MP = new MediaPlayer();
@Override
public void onCreate(Bundle savedInstanceState) {
//...
FileDescriptor fd = getResources().openRawResourceFd(R.raw.pronounciations).getFileDescriptor();
try {
setVolumeControlStream(AudioManager.STREAM_MUSIC); // Lets the user control the volume.
MP.setDataSource(fd);
MP.setLooping(false);
MP.prepare();
MP.start(); // HACK! Some playing seems required before seeking will work.
Thread.sleep(60); // Really need something like MediaPlayer.bufferFully().
MP.pause();
MP.setOnErrorListener(new OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
});
MP.setOnSeekCompleteListener(new OnSeekCompleteListener() {
public void onSeekComplete(MediaPlayer mp) {
// The clip is queued up and read to play.
// I needed to do this in a background thread for UI purposes.
// You may not need to.
new Thread() {
@Override
public void run() {
MP.start();
try {
Thread.sleep(soundRanges[curWordID][1]);
} catch(InterruptedException e) {}
MP.pause();
}
}.start();
}
});
} catch(Throwable t) {}
}
private void playCurrentWord() {
if(soundRanges != null && !MP.isPlaying() && !silentMode) {
try {
MP.seekTo(soundRanges[curWordID][0]);
}
catch(Throwable t) {}
}
}
您可能需要使用外部声音编辑工具连接您的剪辑。我使用 Audacity 查找和编辑保存在文件中的剪辑开头和长度。
soundRanges[curWordID][0] 是声音文件中剪辑开头的偏移量,soundRanges[curWordID][1] 是它的长度。