Jar not reading audio files from inside the jar file - java

Okay, I've been at this for hours, I've checked other questions for help and I've tried all of the suggestions but none seem to work.
I am packaging a folder (called "audio") into my project with a bunch of .wav files in it. I am trying to reference those files, however they never get referenced inside the JAR, only outside in a separate folder called "audio".
try {
Clip clip = AudioSystem.getClip();
InputStream inn = this.getClass().getClassLoader().getResourceAsStream("/audio/" + rangod + ".wav");
AudioInputStream inputStream = AudioSystem.getAudioInputStream(inn);
clip.open(inputStream);
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(-10.0f);
clip.start();
} catch (Exception e1) {
e1.printStackTrace();
}
The problem child seems to be
InputStream inn = this.getClass().getClassLoader().getResourceAsStream("/audio/" + rangod + ".wav");
From what I've seen on other questions similar to this, having the "/" in front of "audio" is supposed to reference the audio folder INSIDE my jar file where as removing the "/" from in front of "audio" is supposed to reference the audio folder in the same directory as my jar file (ie: /desktop/audio)
Both methods seem to reference the same folder outside of my jar, and neither the one inside my jar.
My hierarchy is this:
audio
----[audio files]
net
----fragbashers
--------rgp
------------[class files]

I fixed the issue, it was a really easy fix that I was overlooking. All my WAV files were saved in all lower case and I hadn't been converting the picked characters string to lowercase, so it didn't think the file existed.

Related

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.

Jar won't play sounds from resources folder loaded through getClass()

I have this directory structure:
root
resources
.png files
Music.mid
Sound.wav
src
.java files
and I play the sounds from the resources folder using this code
public void play() {
try {
URL defaultSound = getClass().getResource(filename);
AudioInputStream audioInputStream =
AudioSystem.getAudioInputStream(defaultSound);
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start( );
while (clip.isRunning()) {}
}
catch (Exception e) {
e.printStackTrace();
}
}
I pass to it filenames = /resources/Music.mid and /resources/Sound.wav.
It works fine when I run it in IDE, but when I package it into jar (all music files are inside the jar, I checked) it doesn't play sound and throws exception:
FileNotFoundException: syntax error in file name, directory name or disk name.
Why does this happen and how do I fix it?
getClass() returns a URL and not a File object. It does that because classloaders (which is what .getResource uses) are an abstract concept, and 'a resource' can be anything. It does not have to be a file. It can be an entry in a jar file (which is really a zip). It can be an entry in a jmod file (which is a custom container format introduced with JDK9). It can be a blob in a database column. A file on a webdav server. Or even generated on the fly every time you ask for the resource. Anything goes.
Clearly, your audio player library is obsolete or crappy. It DOES allow you to pass a URL to it, but the audio player library you're using will just crash out if that URL is anything except one that represents an actual file on disk.
When running in the IDE, it IS a file on disk. When running as a jar, it is as valid a resource as anything a classloader produces, but due to the failure of this player library to deal with any URL (other than file:// URLs), it crashes.
There are only two solutions:
Get a better library.
Find a temp dir, unpack the resource into it, then hand the temp file (or possibly a URL representing this temp file) to your library.
Option #2 is quite hairy. You need to find a location with write access, and you need to take care of deleting the file after. It's also a waste of disk cycles. But if you must, you can, of course, do so:
public void play() throws Exception {
File f = File.createTempFile("Sound.wav");
f.deleteOnExit();
try (InputStream in = YourPlayer.class.getResourceAsStream("/resources/Sound.wav");
OutputStream out = new FileOutputStream(f)) {
in.transferTo(out);
}
AudioInputStream audioInputStream =
AudioSystem.getAudioInputStream(f.toURI().toURL());
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start( );
while (clip.isRunning()) {}
}
NB: getClass().getResource() is slightly wrong; the right syntax is ClassThisCodeIsIn.class.getResource. Usually both work, but there are cases where the latter works but the former doesn't (such as when you're subclassing). It's a good habit to never write code that is strictly inferior to something that's just as simple, even if in this particular case it probably doesn't matter.

Audio resources wont play after export to jar

Okay, so I have a simple program that loads audio files and plays them.
I have this for loading my audio files
Clip c1 = null;
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(songPaths[k + 1]).getAbsoluteFile());
c1 = AudioSystem.getClip();
c1.open(audioInputStream);
} catch (Exception ex) {
System.out.println("Error with playing sound.");
ex.printStackTrace();
}
It runs fine in my intelliJ, and when I look to build artifacts and try to run the jar that's made it fails to load the resources. My songPaths array looks like this:
private final String[] songPaths = {"res/fcpOriginal.wav", "res/fcpRemix.wav",
"res/ibizaOriginal.wav", "res/ibizaRemix.wav",
"res/pohOriginal.wav", "res/pohRemix.wav",
"res/sugarOriginal.wav", "res/sugarRemix.wav",
"res/wavesOriginal.wav", "res/wavesRemix.wav"};
I'm not quite sure what's going on. Any help would be greatly appreciated.
So if I'm understanding your directory hierarchy correctly, you have the following:
src
out/artifacts/nameOfProject_jar.
res
You should put a copy of your res folder in to the nameOfProject_jar folder. Because the working directory for your application is now your nameOfProject_jar folder, so when you are using relative paths like you are, it will look for the res folder in nameOfProject_jar directory instead. :)
I figured it out. FOR ANY FUTURE RESEARCHERS!
I changed
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(songPaths[k + 1]).getAbsoluteFile());
to
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(getClass.getResource(songPaths[k + 1]));

url for audioInputStream seems empty

I am trying the following code to play an mp3. The file is in the correct folder. An exception is thrown when opening the file.
Any ideas what could be wrong?
When trying to print the url on the third line it gives me a null pointer exception.
I am compiling with 1.8 to a min compat version of 1.6. Could this be related?
AudioInputStream audioIn = null;
URL url = this.getClass().getResource("./data/1.wav");
System.out.print(url.getFile());
try {
audioIn = AudioSystem.getAudioInputStream(url);
//audioInputStream = AudioSystem.getAudioInputStream(this.getClass().getResource(soundFile));
}
catch(Exception ex) {System.out.print("exception opening file");}
try{
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
}
catch(Exception ex)
{
System.out.print("exception mediaplayer");
}
}
Instead of using a String var, you could use a Clip object. With Clip, it worked for me.
Oh I had to put the data folder in the src directory.
Still a problem though: when I compile as a jar file, it does not find the data folder. And I want the user to be able to put different things in there.
A URL can see into Jar, unlike a File address. So, you should be fine using the URL to obtain the file.
Two possible problems:
(1) if the file is an .mp3 and you are trying to load a .wav, there will of course be a mismatch as 1.mp3 <> 1.wav.
(2) putting the data into the src folder is not enough. It must also be in a subfolder of the folder that contains the "this" that you refer to. For example, if your code is in package "foo", the place to put the file would be src/foo/data/1.wav.
Do you have a library to decode the .mp3? If so, something like JavaZoom should work.

sound not playing in jar

I have packed all the class files and resources as a jar but on execution the sound files wont play. My package structure is:
+project
|_classes
|_ _*.class
|_resources
|_ _ *.jpg,*.wav
Code:
AudioInputStream inputStream = AudioSystem.getAudioInputStream(kidsClassRoom.class.getResourceAsStream("../resources/"+file));
getting a null when this line is executed!!
An alternate theory to those already presented. Often successful getResource() calls depend on the class loader instance that is called to locate them. For this reason, I would recommend to use an instance of a user defined object, from which to call getResource(). E.G.
// Sanity check
System.out.println("The value of 'file' is: " + file);
// Presuming kidsClassRoom1 is an instance of kidsClassRoom
AudioInputStream inputStream = AudioSystem.
getAudioInputStream(
kidsClassRoom1.
getClass().
getResourceAsStream("/resources/"+file));
You might also note that snippet uses the prefix of "/" for the resource. Contrary to what others are saying, I am confident that means 'from the root' of the resource path, in whatever Jar on the run-time class-path it is found. Leaving the '/' or '../' out will have the class loader searching for the resource in a sub-path of the class that this is occurring in.
Of course - make sure the Wav ends up in the Jar! Copy/rename the .jar to a .zip and double click it is the 'quick & dirty' way to examine the archive contents on Windows.
Create a package named resources as shown below
then
AudioSystem.getAudioInputStream(kidsClassRoom.class.getResourceAsStream("resources/"+file));
This is my function for playing a looping sound file in jars, it works fine for me.
It appears that getResourceAsStream() doesn't work with jars. however, getResource() does.
public synchronized void alarm() {
try {
crit = AudioSystem.getClip();
AudioInputStream inputStream1 = AudioSystem.getAudioInputStream(this.getClass().getResource("critical.wav"));
crit.open(inputStream1);
crit.loop(Clip.LOOP_CONTINUOUSLY);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
When you do getResourceAsStream, it is not relative to the current class, but the root of the archive. That is, first try to remove ../.
The important thing to note is that in the exported jar the resources are not stored as files (Read this somewhere, someone more knowledgeable please input). So it's best to get the resource as a URL Object first then pass that to the AudioInputStream Object.
URL url = YourClass.class.getResource(filename);
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
If the resource is in a subfolder, remember to add it to your filename path.

Categories

Resources