最近我在 Audacity 有一个音频项目,其中有多个曲目。它有分开的人声和分开的乐器。
我已将每个曲目导出为 WAV(16 位)文件。我有 5 个文件,5 个曲目。所有文件都超过300MB,长度为25分钟。
我试图使用媒体播放器同时播放它们:
我为每个文件创建了 Mediaplayer 实例 mp1、mp2、mp3、mp4 和 mp5
我尝试通过以下方式同时播放它们:
启动所有媒体播放器的默认方式:
mp1.start()
mp2.start()
mp3.start()
mp4.start()
mp5.start()
我观察到两者之间存在一些差距。
我可以大胆地将它们混合并作为单个文件播放。我希望它们单独播放的原因是我想控制android中每个曲目的音量。
我在网上对此进行了很多研究:
我认为问题在于 .start() 命令没有同时启动。
方法一:Asynctask 同时启动所有mp的方法:
所以我尝试使用 Asynctask 并创建 5 个单独的线程,如下所示:
class PlayThread extends AsyncTask<MediaPlayer, Void, Void>
{
@Override
protected Void doInBackground(MediaPlayer... player) {
player[0].start();
return null;
}
}
then did
PlayThread[] playThreads = new PlayThread[5];
for (int i = 0; i < 5; i++)
playThreads[i] = new PlayThread();
playThreads[0].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mp1);
playThreads[1].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mp2);
playThreads[2].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mp3);
playThreads[3].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mp4);
playThreads[4].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mp5);
方法2:使用CyclicBarrier
public void syncedCommand(
MediaPlayer player1,
MediaPlayer player2,
MediaPlayer player3,
MediaPlayer player4,
MediaPlayer player5
) {
final CyclicBarrier commandBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
L.m("ALL threads done");
}
});
new Thread(new SyncedCommandService(commandBarrier, player1)).start();
new Thread(new SyncedCommandService(commandBarrier, player2)).start();
new Thread(new SyncedCommandService(commandBarrier, player3)).start();
new Thread(new SyncedCommandService(commandBarrier, player4)).start();
new Thread(new SyncedCommandService(commandBarrier, player5)).start();
}
private class SyncedCommandService implements Runnable {
private final CyclicBarrier mCommandBarrier;
private MediaPlayer mMediaPlayer;
private int lengthseek;
public SyncedCommandService(CyclicBarrier barrier, MediaPlayer player) {
mCommandBarrier = barrier;
mMediaPlayer = player;
}
@Override public void run() {
try {
L.m("Waiting for thread");
mCommandBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
mMediaPlayer.start();
}
}
然后使用它们来播放
syncedCommand(mp1,mp2,mp3,mp4,mp5);
在上述两种方法中,轨道之间仍然存在一些延迟,轨道之间存在一些间隙。
后来我在另一篇文章中读到这是不可能的:
在 Android 上同步多个音轨 https://stackoverflow.com/questions/18549445/syncing-multiple-audio-tracks-on-android
问题是每个 MediaPlayer 代表一个单独的流,
这可能会在不同的时间开始。即使你在所有的
他们同时(这是不可能的),没有办法
保证操作系统将加载并实际启动每个操作系统
同时。
据我所知,Android 没有提供同步多个的方法
溪流。即使操作系统确实提供了此功能,
它非常麻烦,而且通常不是 100% 准确。
正确的解决方案是打开单个流,例如使用音频
Track接口,之前自己做MP3解码混音
将数据发送到流。
它提到的解决方案是解码、混合和编码。我是使用音轨执行此方法的新手。我仍然能弄清楚该怎么做。但这会让我
1.动态更改曲目的音量,就像媒体播放器更改每个曲目的音量一样。或者我必须先修复参数,然后混合、播放并检查它是否适合我的需要
2.我可以寻找特定的时间并开始玩吗?