Welcome to JiKe DevOps Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
254 views
in Technique[技术] by (71.8m points)

java - How do you play a long AudioClip in(&from) JAR(background music)?

I'm doing a pet project (a kind of game). And I ran into a problem: when the application is called from the console with the command:

C:java -jar MyGame.jar

short sounds are played, but long ones are not. All sounds are inside the JAR in the "/assets" folder.

The path to the audio looks like this:

C:MyGame.jarassetsackground_music.wav

Such as a shot or a jump are played. For long audio data, only the first 0.5 seconds are played.

For example: if you load the sound with 0.834 sec length, then it loops (background music), the sound is played in a loop! (WAV file, 0.843 sec, 48 KB). But if you load a WAV file for 2 seconds and a size of 115 KB, only 0.5-1 seconds are played. If you load a WAV background music file for 15 seconds (or 7 seconds) and a size of 110 - 2000 KB and more, the same 0.5 seconds will be played. EVERY 15 (or 7) seconds (if you say "play in a loop").

That is, the file is loaded, its length is loaded, markers are placed at the beginning and at the end, but I only hear the first 0.5 seconds of audio (every "x" -sec, where "x" is the length of the clip).

Audio upload method:

public static InputStream uploadAudio (String path){
    InputStream sourceSound = null;
    try{

        final File jarFile = new File(ResourceLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath());
        if(jarFile.isFile()) {  // Run with JAR file

            final JarFile jar = new JarFile(jarFile);


            InputStream fileInputStreamReader =(jar.getInputStream(jar.getEntry(path)));
            byte[] byteArray = new byte[fileInputStreamReader.available()];
            fileInputStreamReader.read(byteArray);

            InputStream newInputStreamFromArray =  new BufferedInputStream(new ByteArrayInputStream(byteArray));

            sourceSound = newInputStreamFromArray;
            jar.close();

        } else { // Run with IDE

            URL url = ResourceLoader.class.getResource( "../" + path);
            InputStream fileInputStreamReader = new BufferedInputStream(new FileInputStream(url.getPath()));
            sourceSound = fileInputStreamReader;
        }

    }catch (IOException e){
        e.printStackTrace();
    }
    return sourceSound;
}

Part of the audio playback class:

public class Sound implements AutoCloseable {
private boolean released = false;
private AudioInputStream stream = null;
private Clip clip = null;
private FloatControl volumeControl = null;
private boolean playing = false;

public Sound(InputStream inputStream) {
    try {
        stream = AudioSystem.getAudioInputStream(inputStream);
        clip = AudioSystem.getClip();
        clip.open(stream);
        clip.addLineListener(new Listener());
        volumeControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
        released = true;
    } catch (IOException | UnsupportedAudioFileException | LineUnavailableException exc) {
        exc.printStackTrace();
        released = false;

        close();
    }
}


public void playLoop(boolean breakOld){
    if (released) {
        if (breakOld) {
            clip.stop();
            clip.loop(Clip.LOOP_CONTINUOUSLY);
            playing = true;
        } else if (!isPlaying()) {
            clip.loop(Clip.LOOP_CONTINUOUSLY);
            playing = true;
        }
    }

}
public void playLoop(){
    playLoop(true);
}

No error's. The program works. The background sound is played in a loop, but only 0.5 sec of the clip. Short sounds (shot or jump sound) are played. Everything works in the IDE: short sounds and full background music.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

Please log in or register to answer this question.

1 Answer

0 votes
by (71.8m points)

Problem solved! (may not be the best way). My problem is that I took the method

 public static Image uploadImage (String path)

and rewrote part of it for audio. In the method for images, there is a string for unpacking the JAR.

  InputStream fileInputStreamReader = (jar.getInputStream (jar.getEntry (path)));

Next, I wrote the code for audio. It didn't work directly: it was not the same for

 InputStream sourceSound = new BufferedInputStream (fileInputStreamReader);
 ... ...
return sourceSound;

Next step - I added:

            InputStream fileInputStreamReader =(jar.getInputStream(jar.getEntry(path)));
            byte[] byteArray = new byte[fileInputStreamReader.available()];
            fileInputStreamReader.read(byteArray);

            InputStream newInputStreamFromArray =  new BufferedInputStream(
                                      new ByteArrayInputStream(byteArray));

            sourceSound = newInputStreamFromArray;

And it worked! (I thought so). After posting the question here, I started to think that not all inputStream are written in byte[] byteArray. I made a copy of the byteArray and wrote it to a file "H:/1.wav".

And this is what I saw in the file:

RIFFp[) WAVEfmt      D?  ±   data?Z) ?1V?E?R??V??H .
.....................................................................................
.....................................................................................

And etс. The data was cut off. There was no content.

Working code for images:

 BufferedImage sourceImage = null;
                InputStream fileInputStreamReader = jar.getInputStream(jar.getJarEntry(path));
                sourceImage = ImageIO.read(fileInputStreamReader);//magic ImageIO.read () !!!!

Likewise does not work for audio:

InputStream fileInputStreamReader =(jar.getInputStream(jar.getEntry(path)));
            byte[] byteArray = new byte[fileInputStreamReader.available()];
            fileInputStreamReader.read(byteArray);

I guess I didn’t learn Java well =) So I solved the problem now like this:

        InputStream fileInputStreamReader =(jar.getInputStream(jar.getEntry(path)));
        byte[] byteArray = new byte[fileInputStreamReader.available()];

        int i = 0;
        int byteRead;
        while ((byteRead = fileInputStreamReader.read()) != -1) {
            byteArray[i] = (byte) byteRead;
            i++;
        }

        InputStream newInputStreamFromArray =  new BufferedInputStream(new ByteArrayInputStream(byteArray));

Long and short audios are now read from the JAR normally.

If someone knows how to do it better - I will be glad to hear the answer.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to JiKe DevOps Community for programmer and developer-Open, Learning and Share
...