0

Apologies if this has been asked before, but I was unable to find an answer that worked for us. I am also a beginner so please bear with me.

Essentially, after jarring our code the audio stopped working.

clip = AudioSystem.getClip();
             File file = new File(musicLocation);
             clip.open(AudioSystem.getAudioInputStream(file.getAbsoluteFile()));
             clip.start();

I have tried using getResourceAsStream and getResource as apparently files don't work properly when jarred but it still does not work even in Intellij.

My code is located in the src folder and the music location is being passed to the code like so:

filepath = "src/Images/music/click.wav"; 
musicObject.playMusic(filepath);

Images are working properly in the jar file.

Edit: it appear that the jar file is unable to take the audio files, which are within another folder that is otherwise being accessed, because the file size of the jar does not change after the deletion of the .wav files.

Edit 2:

public class Music {
    Clip loop;
    void loopMusic(String musicLocation) {
        try {
            loop = AudioSystem.getClip();
            InputStream is = getClass().getResourceAsStream(musicLocation);
            AudioInputStream audioS = AudioSystem.getAudioInputStream(is);
            loop = AudioSystem.getClip();
            loop.open(audioS);
            loop.start();
            loop.loop(Clip.LOOP_CONTINUOUSLY);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    void stopLoop(){
        if (loop != null) {
            loop.stop();
            loop.close();
        }
        loop=null;
    }
}

This is the coe we are attempting to use. The musicLocation String is passed in the format of: /folder/file.wav After manually putting the .wav files into the jar through winrar, it still is unable to load the music in the jar file.

Edit 3:Attempting to use URL Class, receiving NullPointerException

URL musicLocation = this.getClass().getResource("/Images/music/battle.wav");
AudioInputStream inputStream = AudioSystem.getAudioInputStream(musicLocation);

When passed into the AudioInputStream as a file with the "src" before the location name, it does not pass a null.

Edit 4: Attempting to use URL Class with the file inside of folder in Music class package

URL musicLocation = this.getClass().getResource("audio/battle.wav");
AudioInputStream inputStream = AudioSystem.getAudioInputStream(musicLocation);

With the audio folder above being inside the classes (containing all the .java files) package, this returns a NullPointerException. After adding a "Classes/" to the front, hovering over the string in my IDE allows me to "see" that the file is correctly being sourced if you will but it still returns a NullPointerException to the .wav file.

Edit 5: Receiving this error after implementing Phil's code

Exception in thread "main" java.lang.ExceptionInInitializerError
    at Classes.Frame.<init>(Frame.java:15)
    at Classes.GraphicsRunner.main(GraphicsRunner.java:15)
Caused by: java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:222)
    at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1032)
    at Classes.Music.<init>(Music.java:16)
    at Classes.Panel.<clinit>(Panel.java:24)
    ... 2 more

Edit 6: Displaying class that resulted in error above

package Classes;

import javax.sound.sampled.*;
import javax.swing.*;
import java.io.*;
import java.net.URL;

public class Music {
    Clip clip;

    // Constructor, create looping audio resource, hold in memory.
    public Music() {
        URL url = this.getClass().getResource("audio/battle.wav");
        AudioInputStream ais;
        try {
            ais = AudioSystem.getAudioInputStream(url);
            //line 16 above 
            DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
            clip = (Clip) AudioSystem.getLine(info);
            clip.open(ais);
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    public void play() {
        clip.setFramePosition(0);
        clip.loop(Clip.LOOP_CONTINUOUSLY);
    }
}

Edit 7: Phils identical set of code worked upon moving project to Eclipse. I'm still unsure of why it didn't work in Intellij but my problem was solved nonetheless. Thanks to everyone who offered their help!

user439021
  • 13
  • 3
  • 1
    Does this answer your question? [Get audio to play in JAR File](https://stackoverflow.com/questions/37648005/get-audio-to-play-in-jar-file) – Tom Dec 07 '20 at 00:22
  • Also suitable: [Music not playing in .JAR-file](//stackoverflow.com/q/50969615) – Tom Dec 07 '20 at 00:22
  • after implementing the getResourceAsStream and getAudioInputStream like aran below said, it still does not work. – user439021 Dec 07 '20 at 00:34

1 Answers1

0

The java.io.File object is not a good choice for addressing files that are packed in jars. I don't know the correct technical way to explain this, but in simple language, it can only address files that are in file folders. It has no ability to "see" within jar files.

For this reason, it's more usual to access the file by getting its URL using the Class.getResource method. A URL can identify a file that has been compressed and is located within a jar.

It is also possible to address and load a sound file in a jar using the .getResourceAsStream method. This method returns an InputStream, not a URL. But this is a dicier option. If you look at the API for the overloaded AudioSystem.getAudioInputStream, and compare the versions, you'll see that if the argument is an InputStream, the file will be subjected to tests to determine if "mark" and "reset" are supported. A sizable number of audio files fail these tests. For this reason, it's safer to use the method with a URL argument.

Problems can also arise in how the file name is provide in the getResource method, but usually if the name String works in the DAW it will also work in a jar (assuming you are obtaining a URL and not a File). The specifics about "relative" and "root" addressing aren't the easiest to explain. But we can go there if needed.

EDIT: Code example for troubleshooting.

public class Music {
    Clip clip;

    // Constructor, create looping audio resource, hold in memory.
    public Music() {
        URL url = this.getClass().getResource("audio/battle.wav");
        AudioInputStream ais;
        try {
            ais = AudioSystem.getAudioInputStream(url);
            DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
            clip = (Clip) AudioSystem.getLine(info);
            clip.open(ais);
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    public void play() {
        clip.setFramePosition(0);
        clip.loop(Clip.LOOP_CONTINUOUSLY);
    }    
}

The code assumes the following file folder structure:

/src/.../folderwithMusic/Music
/src/.../folderwithMusic/audio/battle.wav

Note that the file name is case sensitive. A null value for the URL indicates that the file is not at the expected location. First get this working in your IDE, and maybe prefer either your console or File Explorer to verify the file structure and file location.

If you try running the above and have problems, the exact code as entered and stack trace would be helpful.

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
  • @Tom, in the comments to the question, linked previous iterations of this question that include the recommendation to use `URL` instead of `File` as the argument in `AudioSystem.getAudioInputStream`. I've put this in as a more explicit answer as this solution might be easy to overlook in those questions, as there are many suggestions offered in those posts. – Phil Freihofner Dec 07 '20 at 09:54
  • Thank you for the response. Do you have any idea why there are issues with the .wav files not appearing in the jar file when opened with WinRar? Also, I have attempted to use the URL class, and edited with my code above – user439021 Dec 08 '20 at 01:29
  • This line confuses me: "After manually putting the .wav files into the jar through winrar". I'm not clear what exactly you are doing! Would you be willing to try the following? (It might not be the preferred project structure, but it will help with troubleshooting.) In the folder where "this" is located (Edit 3), create a subfolder named "audio". Place the audio file ("battle.wav") in that folder prior to jarring the project, make sure to refresh the project. Invoke this file using the Edit 3, URL-based code, with the string "audio/battle.wav". This should work both in IDE and after jarring. – Phil Freihofner Dec 08 '20 at 05:44
  • Receiving null pointer exception although file is correctly being sourced. Have edited with what I tried – user439021 Dec 08 '20 at 16:59
  • Edited above with the result. Your assumption in the folder structure is how I structured the path. – user439021 Dec 08 '20 at 22:19
  • Can you post the code you entered and indicate line 16? Just to confirm the file structure, "Music" wasn't referring to a file folder, but instead, to the Music.java class. Did you check for case-sensitive matching? No "/" at the start of the name? This doesn't work on your IDE? Very mystifying. I've never known this way of loading audio not to work. I do recall last week spending a couple hours due to mis-spelling "height' has 'heigth", but it doesn't seem like what you did would be very likely to be hiding any typos. I'm running out of ideas. – Phil Freihofner Dec 09 '20 at 05:16
  • Edited. It is right that Music is a class and not a file folder. – user439021 Dec 09 '20 at 23:33