Reputation: 103
I have a stereo AudioInputStream
and I want to split it into two mono AudioInputStream
s, one for the left and one for the right channel of the stereo stream. How do I do that?
Note: I've already tested the answers from the following question but nothing worked for me (that's why I'm asking again).
How to split a Wav file into channels in java?
Here is what I'm trying to get working (it's mostly from the link above). In the following code, while loop runs infinitely. readsize
is always 4 (or whatever sampleInBytes * 2
is), it never becomes -1 (which means it's the end of stream) so it never breaks.
AudioInputStream originalAudioInputStream = null;
try {
originalAudioInputStream = AudioSystem.getAudioInputStream(audiofile);
} catch (UnsupportedAudioFileException e) {
//file not supported
} catch (IOException e) {
//error
}
//read file and convert it to PCM SIGNED big endian
AudioFormat destaf = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
originalAudioInputStream.getFormat().getSampleRate(),
originalAudioInputStream.getFormat().getSampleSizeInBits(),
originalAudioInputStream.getFormat().getChannels(),
originalAudioInputStream.getFormat().getSampleSizeInBits() / 8 * originalAudioInputStream.getFormat().getChannels(),
originalAudioInputStream.getFormat().getSampleRate(), true);
AudioInputStream signedBigEndianInputStream = AudioSystem.getAudioInputStream(destaf, originalAudioInputStream);
//split stereo AudioInputStream
ByteArrayOutputStream leftbaos = new ByteArrayOutputStream();
ByteArrayOutputStream rightbaos = new ByteArrayOutputStream();
byte[] bytes = new byte[(signedBigEndianInputStream.getFormat().getSampleSizeInBits()/8)*2];
while (true) {
int readsize = 0;
try {
readsize = signedBigEndianInputStream.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
if(readsize==-1){
break;
}
rightbaos.write(bytes,0,bytes.length/2);
leftbaos.write(bytes,bytes.length/2,bytes.length/2);
}
byte[] leftData = leftbaos.toByteArray();
byte[] rightData = rightbaos.toByteArray();
AudioFormat outFormat = new AudioFormat(signedBigEndianInputStream.getFormat().getEncoding(),signedBigEndianInputStream.getFormat().getSampleRate(),signedBigEndianInputStream.getFormat().getSampleSizeInBits(),1,signedBigEndianInputStream.getFormat().getFrameSize()/2, signedBigEndianInputStream.getFormat().getFrameRate(),signedBigEndianInputStream.getFormat().isBigEndian());
ByteArrayInputStream leftbais = new ByteArrayInputStream(leftData);
AudioInputStream leftoutputAIS = new AudioInputStream(leftbais, outFormat, leftData.length / outFormat.getFrameSize());
ByteArrayInputStream rightbais = new ByteArrayInputStream(rightData);
AudioInputStream rightoutputAIS = new AudioInputStream(rightbais, outFormat, rightData.length / outFormat.getFrameSize());
//close inputstreams
try {
rightoutputAIS.close();
leftoutputAIS.close();
rightbais.close();
leftbais.close();
rightbaos.close();
leftbaos.close();
signedBigEndianInputStream.close();
originalAudioInputStream.close();
} catch (IOException e) {
//error
}
Thanks!
Upvotes: 1
Views: 764
Reputation: 5310
You assume that the audio is stored in two blocks:
Instead, audio is usually stored in an interleaved fashion.
That is:
In order to separate the two streams you'll have to do something like this:
// just to show which types are used
// i.e., initialization is not shown
AudioFormat destaf;
ByteArrayOutputStream leftbaos;
ByteArrayOutputStream rightbaos;
AudioInputStream signedBigEndianInputStream;
byte[] bytes;
[...]
final int bytesPerSample = destaf.getSampleSizeInBits() / 8;
final int channels = 2;
while (true) {
int readsize = 0;
try {
readsize = signedBigEndianInputStream.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
if (readsize==-1){
break;
}
for (int sample=0; sample<readsize/channels/bytesPerSample;sample++) {
final int offset = sample * bytesPerSample * channels;
leftbaos.write(bytes, offset, bytesPerSample);
rightbaos.write(bytes, offset + bytesPerSample, bytesPerSample);
}
}
[...]
Upvotes: 1