Recently i have an audio project in Audacity with multiple tracks in it. It has vocals separate and instruments separate.
I have exported each track as a WAV(16bit) file. I have 5 files for 5 tracks. All the files are more than 300MB and lengths of 25 minutes.
I was trying to play them simultaneously using mediaplayer:
I have created Mediaplayer instances mp1, mp2, mp3, mp4 and mp5 for each file
I try to play them simultaneously by:
Default Way to start all media players:
mp1.start()
mp2.start()
mp3.start()
mp4.start()
mp5.start()
What i observed is there is some gaps in between.
I could have mixed them in audacity and played as a single file. the reason i want them to be played seperately is i want to control the volume of each track in android.
I reasearched a lot on net regarding this:
I thought the problem is in .start() commands not starting simultaneously.
Methods 1: Asyntask Method to start all mp simultaneously:
SO i have tried using Asyntask and created 5 separate threads like below:
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);
Method 2: using 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();
}
}
then play them using
syncedCommand(mp1,mp2,mp3,mp4,mp5);
In both the above methods stil there is some latency among the tracks, there is some gaps in between.
Later i have read in another post that its not possible:
syncing multiple audio tracks on android
The problem is that each MediaPlayer represents a separate stream, which may start at different times. Even if you call start on all of them at the same time (which is impossible), there's no way to guarantee that the OS will load and actually start each one at the same time.
As far as I know, Android offers no way to synchronize multiple streams. Even with operating systems that do offer this capability, it's extremely cumbersome, and usually not 100% accurate.
The correct solution is to open a single stream, eg using the audio track interface, and do the MP3 decoding and mixing yourself before sending the data to the stream.
The solution its mentioning is to decode, mix and encode. I am new to do this method using Audio Track. I can still figure out how to do it. BUt will it allow me
1. to change volume of tracks on fly like media player changes volume of each track. Or i have to fix the parameters first and then mix, play and check whether its suitable to my needs
2. Can i seek to particular time and start playing.