I am trying to
My problem is that the second recorded file (2.) and the first recorded file (1.) are not synchronous. Once I mix them together I hear a delay that I did not record. To test my app, I said 'Test 1 2 3' into the microphone. In the second recording I said 'Test 1 2 3' at the same time. However after mixing (overlaying) my 2 files, I get a delay.
What did I do wrong?
final Thread recordingThread = new Thread(new Runnable() {
final int SAMPLING_RATE = 44100;
final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
final int CHANNEL_IN_CONFIG = AudioFormat.CHANNEL_IN_MONO;
final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLING_RATE, CHANNEL_IN_CONFIG, AUDIO_FORMAT);
final String AUDIO_RECORDING_FILE_NAME = project.getPath()+"/track"+String.valueOf(project.getTrackNumber())+".raw";
final int playbackBufferSize = AudioTrack.getMinBufferSize(SAMPLING_RATE, CHANNEL_IN_CONFIG, AUDIO_FORMAT);
@Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
Log.d("Record", "[Starting recording]");
byte audioData[] = new byte[BUFFER_SIZE];
boolean playSound = true;
ByteArrayOutputStream playbackOutput = new ByteArrayOutputStream();
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(project.getPath()+"/output.wav"));
} catch (FileNotFoundException e) {
playSound = false;
}
int playbackRead = 1;
byte[] playbackBuffer = new byte[BUFFER_SIZE];
AudioRecord recorder = new AudioRecord(AUDIO_SOURCE,
SAMPLING_RATE, CHANNEL_IN_CONFIG,
AUDIO_FORMAT, BUFFER_SIZE);
AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLING_RATE, AudioFormat.CHANNEL_OUT_MONO, AUDIO_FORMAT, playbackBufferSize, AudioTrack.MODE_STREAM);
player.play();
recorder.startRecording();
String filePath = AUDIO_RECORDING_FILE_NAME;
BufferedOutputStream os = null;
try {
os = new BufferedOutputStream(new FileOutputStream(filePath));
} catch (FileNotFoundException e) {
Log.e("Record", "File not found for recording ", e);
}
while (!mStop) {
int status = recorder.read(audioData, 0, audioData.length);
if (status == AudioRecord.ERROR_INVALID_OPERATION ||
status == AudioRecord.ERROR_BAD_VALUE) {
Log.e("Record", "Error reading audio data!");
return;
}
try {
os.write(audioData, 0, audioData.length);
if (playSound) {
try {
if (playbackRead > 0) {
playbackRead = in.read(playbackBuffer);
}
if (playbackRead > 0){
player.write(playbackBuffer, 0, playbackBuffer.length);
}
} catch (IOException e) {
Toast.makeText(MainActivity.this, "ERROR!", Toast.LENGTH_SHORT).show();
return;
}
}
} catch (IOException e) {
Log.e("Record", "Error saving recording ", e);
return;
}
}
try {
os.close();
recorder.stop();
recorder.release();
player.stop();
player.release();
Log.v("Record", "Recording done…");
mStop = false;
File out = new File(project.getPath()+"/output.wav");
if (!out.exists()) {
out.createNewFile();
SoundUtils.rawToWave(new File(AUDIO_RECORDING_FILE_NAME), out, SAMPLING_RATE);
} else {
mixSound(project.getPath()+"/track1.raw", project.getPath()+"/track2.raw", project.getPath()+"/track3.raw", project.getPath()+"/track4.raw");
}
} catch (IOException e) {
Log.e("Record", "Error when releasing", e);
}
}
});
Explanation:
(- Once there is nothing to play anymore, playbackRead is -1)
After that I try to mix my recordings. However my second recording is having a delay which I did not record.
What am I doing wrong? How do I (almost) completely correctly synchronize AudioRecord and AudioTrack so that when I say something it is played back at the position of the background recording as it was when I recorded it?
Finally I found a very exect solution and I would like to share it with everyone facing this problem in the future. I printed out every short
value of the pcm data I was recording. It looked like this:
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ..., 0.0025, 0.0026, 0.0163, 0.0123, ...
As you can see, there are many zero's at the beginning of the recording. But in a normal quite environment there is always a (very quite) noise in the background. It can't be exactly 0.
I thought, that maybe, this range, where all the 0's are is the time from the start of the recording till the first sound acutally receives the file.
=> This is the delay
In the second recording (while playing the previous recording as a background sound) I removed the starting 0's from the whole data so that the sound starts immediately. I then mixed both recordings together and they are very exactly synchronized.
I do not know whether this is a way how the delay could be removed in all situations but I tried it on several phones and it worked well. I am happy that I was able to solve my problem.
Long story short: To remove the delay, remove all the 0's that are in the front of your sound data.