How to export .wav files within your jar file [duplicate] - java

Sound does not play when I run the JAR, but it does when I run it in eclipse.
Here is where I load the clips: (the files are loaded from the directory of the jar, Not from within the jar)
public void init(){
System.out.println("grabbing Music");
String currentDir = new File("").getAbsolutePath();
name=new File(currentDir+"\\music\\").list();
clip=new Clip[name.length];
soundFile=new File[name.length];
for(int x=0;x<name.length;x++){
System.out.println(currentDir+"\\music\\"+name[x]);
try {
soundFile[x]= new File(currentDir+"\\music\\"+name[x]);
AudioInputStream sound = AudioSystem.getAudioInputStream(soundFile[x]);
DataLine.Info info= new DataLine.Info(Clip.class, sound.getFormat());
clip[x] = (Clip) AudioSystem.getLine(info);
clip[x].open(sound);
clip[x].addLineListener(new LineListener(){
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
event.getLine().close();
}
}
});
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
}
}
}
I do not get any errors when running it in Eclipse. There should be no possibility of an invalid directory error, so what is wrong?
-When the jar is run in CMD i get no errors nor stacktraces, so it IS loading the files, it just isnt running it when the clip.start() is called. So the way im loading the files in is not compatible with runnable jars.
edit: I feel like I am loading the audio wrong, hence why I pasted the code I used to load the files in. In my searches I haven't seen anyone use File to load in a sound file. Wonder if that is the problem?
-Also switching to embedded resources ALSO does not work.

The reason your sound is not playing because it is most likely not being compiled into your runnable jar and thus cannot be found. The best way to have it compile into a runnable jar is to create a source folder in eclipse, and then add your sound file in there. It will then be compiled into your jar

I struggled with this as well. You need to use
getClass().getSystemResource("pathToResourceFromClass")
For example, if your project structure is like the following:
-ProjectName
-----src
----------SomeClass.java
-----images
----------SomeImage.png
Then from SomeClass.java, you would use
getClass().getSystemResource("images/SomeImage.png")
to obtain the URL object which references that file. You could then pass that URL object to the constructor of ImageIcon if you want.
Note that getClass().getResource() does not work for images or sound files in a jar file!!! I've spent many hours on this, and getResource() does not work. You have to use getSystemResource(..) for resources within a jar file.
Let me know if you have any questions about this. I'd be glad to clarify any confusing points.

Related

file not found or syntax incorrect when using Main.class.getResource("notification.wav").getFile()

I am trying to play a .wav file but having trouble doing so with a relative path function.
public class Main {
public static void main(String[] args) {
playSound();
}
public static void playSound() {
try {
File file = new File(Main.class.getResource("notification.wav").getFile());
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
} catch(Exception ex) {
System.out.println("Error playing sound.");
ex.printStackTrace();
}
}
}
If I run the code above in IntelliJ, I receive the error:
java.io.FileNotFoundException: C:\Users\Dominik\Documents\IntelliJ%20Projects\nbbot\out\production\nbbot\com\company\notification.wav (The system cannot find the path specified)
If I run my built .jar application, I receive the error:
java.io.FileNotFoundException: file:\C:\Users\Dominik\Documents\IntelliJ%20Projects\nbbot\nbbot_jar\nbbot.jar!\com\company\notification.wav (The filename, directory name, or volume label syntax is incorrect) in Java?
The .wav file an the Main class, where I run the code snipped are in the same folder:
nbbot > src > com > company > Main.java; notification.wav
It's strange, because the paths are correct and there should be no problem to just read the file.
I also tried Main.class.getClass().getResource("notification.wav").getFile(); and .getPath() but no luck either. If I just use new File("notification.wav") and put the .wav the project folder nbbot the audio plays as intendet, but only in the IDE.
Your plan is broken. resources aren't usually files. Calling .getFile() on a resource is usually going to get you broken code. For example, when pack up your app into a jar, boom, breaks. a java.io.File object can only represent an actual file.
Just about every API also lets you pass a URL or an InputStream instead of a File, use those - those are abstractions that apply to all resources.
getAudioInputStream is just such a method, fortunately. It has overrides for em. Write this:
try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(
Main.class.getResource("notification.wav"))) {
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
}
This will probably fix this problem and will definitely mean that your code will continue to work once your files are packed up into a jar.
NB: InputStreams are resources that must be closed, hence, you need to use try-with-resources, or your app will eventually hard-crash due to running out of OS handles after playing enough audio.

Trouble with .wav playing in jar file created from Intellij IDEA

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!
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.

Proper packaging of runnable Jar project in netbeans

So my task is to create a small program that displays a list of media files and run these media files with default OS media player separately.
My current solution was to create a package that holds all media files, something like:
-com.media
|_a.mp4
|_b.mp4
The following code copies to a temp dir the selected mp4, then runs the default os media player:
public File copyTempMedia(File tempAppFolder, String videoName) {
URL f = getClass().getResource(String.format("%s/%s", Constants.MEDIA_LOCATION, videoName));
File from = new File(f.getPath());
File to = new File(tempAppFolder.getAbsolutePath());
try {
FileUtils.copyFileToDirectory(from, to);
} catch (IOException ex) {
Logger.getLogger(MediGUIModel.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Temp video copied: " + to.getAbsolutePath() + "/" + to.getName());
return to;
}
public void triggerMediaPlayer(String fileLocation) {
System.out.println("Triggering media player: " + fileLocation);
try {
if (OPERATIN_SYSTEM.contains("Linux")) {
Runtime.getRuntime().exec("sh -c " + fileLocation);
} else if (OPERATIN_SYSTEM.contains("Windows")) {
Runtime.getRuntime().exec("cmd /c " + fileLocation);
}
} catch (IOException ex) {
Logger.getLogger(MediGUIModel.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
When I run the program through Netbeans it works as espected, but when I do a clean/build the run the .jar created from the build, the media file doesn't seem to be read, so my questions are:
Why does it work through Netbeans and not through build .jar ?
Is this the best solution to this problem ?
Should I package the media differently ?
Thanks in advance.
Edit
So after running through console instead of double clicking jar, is get a null pointer exception in the line where I read the file:
URL f = getClass().getResource(String.format("%s/%s", Constants.MEDIA_LOCATION, videoName));
Why does it work in Netebeans but not on build/jar ?
Is there another place in the jar I could place the media files, so that they are read with no problem through getResource or getResourceAsStream ?
When you run the project in NetBeans, it isn't running the executable jar like java -jar yourproject.jar. Instead it sets the classpath to build/classes sort of like java -cp build/classes com.media.YourMainClass. This means your video files are actual files located in yourproject/build/classes/com/media, and they can be accessed as normal files in the filesystem and copied like a normal file. When you run from the jar, the files are packed in the jar file and can't be copied using simple file copy commands.
Instead of getting the URL by calling getClass().getResource(), try getting an InputStream by calling getClass().getResourceAsStream(). You can then write a simple loop to copy the bytes from the input stream to your temporary file.
This snippet may be helpful:
BufferedInputStream result = (BufferedInputStream) getClass().getResourceAsStream("/com/media/a.mp4");
byte[] bytes = new byte[4098];
try {
result.read(bytes);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new String(bytes));
You'll need to read the bytes in a loop or something but that should work without needing a separate jar.
I think it's not a good idea to put your media files in the jar because you need to rebuild the project if you want to change one and the jar size will grow.
Use:
File from = new File(String.format("%s/%s", Constants.MEDIA_LOCATION,videoName));
To load your files from the same folder as the jar.
If you want to keep the medias in the jar, create a Maven project and put the mp4 in src/main/resources.
Use maven to create a fat jar and the src/main/resources will be included in the jar.
See 'maven-shade-plugin' to configure the pom.xml and https://www.mkyong.com/maven/create-a-fat-jar-file-maven-shade-plugin/
Then you can use the others maven's great properties!
See Reading a resource file from within jar
Edit
After some tries, i can't get it right with 'getResource' from the jar.
The path you get from within the jar is like:file:/C:/.../JavaApplication4/dist/JavaApplication4.jar!/test.txt
and not recognized as a valid filesystem path.
You can use 'getResourceAsStream' and copy the file from the jar to the local folder.
InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();
Ok so I found a solution:
Create a separate project with media.*.mp4.
Export as Jar library.
Import library to desktop app.
Make sure library is in classpath.
This solution works for me...
If anyone has a better solution, happy to hear, hopefully before bounty is up :)

file not found exception while trying to read file in netbeans

I am making an simple application to play sounds in Java. I am able to do that when I keep the audio files in D: disk. Here is the code
in = new FileInputStream("D:\\"+selectedSounds[position]+".wav");
//Some code for playing audio
Then I placed the audio files in same package where the Jframe class is present. But when I run it prompts fileNotFound exception. Can some one tell me why this is happening.
in = new FileInputStream(selectedSounds[position]+".wav");
// I have also tried
new FileInputStream("./"+selectedSounds[position]+".wav");
Here is the file path
Your wave file, contained within the "Source Packages" won't be accessible once the program is packaged as a Jar, as the files will be embedded within the Jar itself and no longer accessible as files.
Instead, you should be using Class#getResourceAsStream, for example...
try (InputStream in = getClass().getResourceAsStream("/PlayAudio/" + selectedSounds[position]+".wav")) {
// You now have an InputStream to your resource, have fun
} catch (IOException | NullPointerException exp) {
exp.printStackTrace();
}

No Player Exception With Jar

I was trying to use MP3s instead of wavs and it works fine in NetBeans, but when I build it and try to run the jar there's no sound and I get the NoPlayerException.
background = ImageIO.read(getClass().getResourceAsStream("/background1.png"));
sun = ImageIO.read(getClass().getResourceAsStream("/sun.png"));
cloud = ImageIO.read(getClass().getResourceAsStream("/cloud.png"));
pause = ImageIO.read(getClass().getResourceAsStream("/pause.png"));
soldierchant = AudioSystem.getAudioInputStream(getClass().getResource("/SoldiersChant.wav"));
thebreach = AudioSystem.getAudioInputStream(getClass().getResource("/TheBreach.wav"));
forever = AudioSystem.getAudioInputStream(getClass().getResource("/Forever.wav"));
Format input1 = new AudioFormat(AudioFormat.MPEGLAYER3);
Format input2 = new AudioFormat(AudioFormat.MPEG);
Format output = new AudioFormat(AudioFormat.LINEAR);
PlugInManager.addPlugIn("com.sun.media.codec.audio.mp3.JavaDecoder", new Format[]{input1, input2}, new Format[]{output}, PlugInManager.CODEC);
try {
Player player = Manager.createPlayer(new MediaLocator(getClass().getResource("/TheBreach.mp3").toURI().toURL()));
player.start();
} catch (IOException ex) {
ex.printStackTrace();
}catch (java.net.URISyntaxException x) {
x.printStackTrace();
}catch (javax.media.NoPlayerException c) {
c.printStackTrace();
}
As you can see I'm getting the file from using getResource just like the images and wav that work both in NetBeans and jar. Could this be the problem com.sun.media.codec.audio.mp3.JavaDecoder
I'm grabbing at straws at this point. I've tried putting the MP3 in every folder and doing no / and the full directory.
This is my Exception's getMessage:
Cannot find a Player for jar:file:/C:/Users/Patrick/Documents/NetBeansProjects/PatBuild8FX/dist/PatBuild8FX.jar!/TheBreach.mp3
I think it is Manager.createPlayer because when I just create the file alone its fine, but when I try to create a player with it, it doesn't work.
File m = new File("file:/C:/Users/Patrick/Documents/NetBeansProjects/PatBuild8FX/dist/PatBuild8FX.jar/TheBreach.mp3");
System.out.println(m);
System.out.println(Manager.createPlayer(m.toURI().toURL()));
file:\C:\Users\Patrick\Documents\NetBeansProjects\PatBuild8FX\dist\PatBuild8FX.jar\TheBreach.mp3
java.io.IOException: File Not Found
java.io.IOException: File Not Found
Exception in thread "main" javax.media.NoPlayerException: Error instantiating class: com.sun.media.protocol.file.DataSource : java.io.IOException: File Not Found
at javax.media.Manager.createPlayerForContent(Manager.java:1362)
at javax.media.Manager.createPlayer(Manager.java:417)
at javax.media.Manager.createPlayer(Manager.java:332)
at Build8.PanGame.<init>(PanGame.java:75)
at Build8.Main.main(Main.java:30)
Did you package the 'TheBreach.mp3' file into your jar file? The exception message above suggests that the resource is being accessed from your jar file.
My suggestions:
if you haven't already done so, package the .mp3 file into the jar file (this makes it easier for you to move the single jar file without having to copy the .mp3 file along with it, and also the mp3 file should now be accessible from the jar file), or
if you prefer to have the .mp3 file where it is, then try using a java.io.File class to load the mp3 file before passing to the MediaLocator constructor. Hence, you'd then have something like:
new MediaLocator(new File("file:///C:\\full_path_to_the_file\\TheBreach.mp3").toURL())
finally, the documentation for MediaLocator.createPlayer() explaining issues with creating players should be handy. You can find it here
Good luck!

Categories

Resources