Java - Trouble combining more than 2 .wav files

2019-05-27 10:18发布

问题:

for a project I'm working on, I want to be able to concatenate multiple .wav files.

Through my research I was able to come up with this code:

File sample1 = new File("F:\\Programming\\Resources\\Java_Sound\\trumpet1.wav");
File sample2 = new File("F:\\Programming\\Resources\\Java_Sound\\trumpet2.wav");

File fileOut = new File("F:\\Programming\\Resources\\Java_Sound\\Test.wav");

AudioInputStream audio1 = AudioSystem.getAudioInputStream(sample1);
AudioInputStream audio2 = AudioSystem.getAudioInputStream(sample2);

AudioInputStream audioBuild = new AudioInputStream(new SequenceInputStream(audio1, audio2), audio1.getFormat(), audio1.getFrameLength() + audio2.getFrameLength());

//for(int i = 0; i < 5; i++){
//    audioBuild = new AudioInputStream(new SequenceInputStream(audioBuild, audio2), audioBuild.getFormat(), audioBuild.getFrameLength() + audio2.getFrameLength());
//}

AudioSystem.write(audioBuild, AudioFileFormat.Type.WAVE, fileOut);

it works fine for combining two .wav files, however when I uncomment the for loop the produced .wav file only plays audio for the first concatenation. The audio track appears to end early, as wmp's duration bar only goes about 1\5 of the way across the screen.

I've assumed that the problem is with the header in the created .wav file. I've researched many different web pages discussing how a header in constructed, but all of them had slightly different definitions, but all said the header should be in hex. When converting the stream (not the audio stream, a standard FileInputStream) the headers I had were in decimal. Additionally, after the RIFF part, and before the WAVE part, is supposed to be the size of the whole file, not including the first 8 bytes. However some of mine included hyphens. To be honest I have no clue what those mean. Ignoring them however, the size of the test file after uncommenting the code above is still a larger number.

So after researching both how to concatenate multiple audio files, and how to create\manage .wav headers, I still have no clue why the rest of my audio isn't playing, if it even exists. Any help is greatly appreciated. Thanks in advance.

回答1:

It might be because the input streams cannot be read more than once. Once you read an input stream, it will be at its end and attempt to read further will read no more bytes from that stream.

This should work with a slight modification, keep creating new audio input streams in your loop:

File sample1 = new File("f1.wav");
File sample2 = new File("f2.wav");

File fileOut = new File("combined.wav");

AudioInputStream audio1 = AudioSystem.getAudioInputStream(sample1);
AudioInputStream audio2 = AudioSystem.getAudioInputStream(sample2);

AudioInputStream audioBuild = new AudioInputStream(new SequenceInputStream(audio1, audio2), audio1.getFormat(), audio1.getFrameLength() + audio2.getFrameLength());

for(int i = 0; i < 5; i++)
{
    audioBuild = new AudioInputStream(new SequenceInputStream(audioBuild, /* keep creating new input streams */ AudioSystem.getAudioInputStream(sample2)), audioBuild.getFormat(), audioBuild.getFrameLength() + audio2.getFrameLength());
}

AudioSystem.write(audioBuild, AudioFileFormat.Type.WAVE, fileOut);

Also, ensure your audio formats for the files are exactly the same. That is, same sample rate, same channel count, same bits per sample. Otherwise you'll need additional code to do sample conversion.



回答2:

This is what I used to join any amount of wave files. I looped through a list of the string values for the wave file paths, and each time I join the previous resulting AudioInputStream with the next clip.

List<String> paths;
AudioInputStream clip1 = null;
for (String path : paths)
{
    if(clip1 == null)
    {
        clip1 = AudioSystem.getAudioInputStream(new File(path));
        continue;
    }
    AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(path));
    AudioInputStream appendedFiles = new AudioInputStream(
            new SequenceInputStream(clip1, clip2),     
            clip1.getFormat(), 
            clip1.getFrameLength() + clip2.getFrameLength());
    clip1 = appendedFiles;
}
AudioSystem.write(clip1, AudioFileFormat.Type.WAVE, new File("exported.wav"));