Java sound | UnsupportedAudioFileException - java

Hääwuo,
I'm trying to implement Pong.
Now I want to play sound, but it throws an exception (UnsupportedAudioFileException).
What did I wrong?
AudioInputStream ainBalk;
Clip clip;
//Constructor beginning
public Playboard() {
try {
Clip clip = AudioSystem.getClip();
ainBalk = AudioSystem.getAudioInputStream(Playboard.class.getClassLoader().getResourceAsStream("Balk.wav")); // Exception!
} catch (Exception e1) {
e1.printStackTrace();
}
...
Thanks for your help

From the Java doc:
An UnsupportedAudioFileException is an exception indicating that an operation failed because a file did not contain valid data of a recognized file type and format.
UnsupportedAudioFileException.html
Different audio software does sometimes produce very different and sometimes incompatible .wav files. So chances are, that the Java AudioSystem is not compatible to the specific wav file you want to open. You could try to convert the file to aiff or you can open the file in a different audio editor/converter and save it as a new file.

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.

Playing a song in java [duplicate]

This question already has an answer here:
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file when loading wav file
(1 answer)
Closed 8 years ago.
I want to play a audio clip from my computer while a game is playing. But i can only use very very short sounds. Is there any similar way to playing songs like i play sound effects?
Im using swing graphics for the game if that matters.
The error i get when i try to use a song
"javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file"
public static void main(String args[]) {
Sound s = new Sound();
s.playSound("C:/Users/isac/Desktop/banjos.wav");
}
}
public void playSound(String file) {
try {
AudioInputStream audio = AudioSystem.getAudioInputStream(new File(
file));
Clip clip = AudioSystem.getClip();
clip.open(audio);
clip.start();
}
catch (UnsupportedAudioFileException uae) {
System.out.println(uae);
} catch (IOException ioe) {
System.out.println(ioe);
} catch (LineUnavailableException lua) {
System.out.println(lua);
}
}
}
The error message you are getting indicates the problem is probably with the format of the file, not its length.
You can check the format of an audio file by looking at it's properties--usually requires a right click on Windows. The properties that matter may be on an "Advanced" tab. Java can read many formats, but where I've most often seen it hang up is with the following:
a person tries to load a .mp3 or .ogg or other form of compression but hasn't implemented any libraries that can decompress those files (not your situation, since your banjo.wav is a wav).
the .wav is not the standard "CD Quality" format (44100 fps, 16-bit encoding, stereo) but rather something like 24-bit or 32-bit encoding or 48000 or 96000 fps.
Current DAWs often make it easy to record in formats that are superior to "CD Quality" but Java doesn't support them yet.
For the most part, you can convert audio files that are not readable with Java to one that is with Audacity (free), if you aren't working from another home studio program. Be careful where you obtain Audacity as some sites that provide it (other than the official site) will include adware or malware or viruses.
As a side note, for a longer file, it would be better to load into a SourceDataLine for playback instead of a Clip. With a SourceDataLine, you don't have to wait for the entire file to load before it will start playing back, and it won't take up anywhere near as much RAM. The Java Tutorials has a section for Java Sound and a page there specifically on playback.

Where do the *.wav files need to live in the directory?

I am working on sound code for a game. And I was using the following code:
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
/**
* This enum encapsulates all the sound effects of a game, so as to separate the sound playing
* codes from the game codes.
* 1. Define all your sound effect names and the associated wave file.
* 2. To play a specific sound, simply invoke SoundEffect.SOUND_NAME.play().
* 3. You might optionally invoke the static method SoundEffect.init() to pre-load all the
* sound files, so that the play is not paused while loading the file for the first time.
* 4. You can use the static variable SoundEffect.volume to mute the sound.
*/
public enum SoundEffect {
EXPLODE("explode.wav"), // explosion
GONG("gong.wav"), // gong
SHOOT("shoot.wav"); // bullet
// Nested class for specifying volume
public static enum Volume {
MUTE, LOW, MEDIUM, HIGH
}
public static Volume volume = Volume.LOW;
// Each sound effect has its own clip, loaded with its own sound file.
private Clip clip;
// Constructor to construct each element of the enum with its own sound file.
SoundEffect(String soundFileName) {
try {
// Use URL (instead of File) to read from disk and JAR.
URL url = this.getClass().getClassLoader().getResource(soundFileName);
// Set up an audio input stream piped from the sound file.
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
// Get a clip resource.
clip = AudioSystem.getClip();
// Open audio clip and load samples from the audio input stream.
clip.open(audioInputStream);
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
// Play or Re-play the sound effect from the beginning, by rewinding.
public void play() {
if (volume != Volume.MUTE) {
if (clip.isRunning())
clip.stop(); // Stop the player if it is still running
clip.setFramePosition(0); // rewind to the beginning
clip.start(); // Start playing
}
}
// Optional static method to pre-load all the sound files.
static void init() {
values(); // calls the constructor for all the elements
}
}
Now when I replace one of the listed *.wav files from the code with my own or even name one of my own to the file name listed from the above code. I receive the follow error:
Exception in thread "main" java.lang.ExceptionInInitializerError
at soundTest.main(soundTest.java:19)
Caused by: java.lang.NullPointerException
at com.sun.media.sound.StandardMidiFileReader.getSequence(Unknown Source)
at javax.sound.midi.MidiSystem.getSequence(Unknown Source)
at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown Source)
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at SoundEffect.<init>(sfx.java:75)
at SoundEffect.<clinit>(sfx.java:55)
From following the stack URL url is null going in, which is telling me the *.wav file itself is not being read.
I have tried the following lines and yes the *.wav file was present (I am aware that I cannot have three items named the same, I've used one played with it, then commented it out and try again with another one, I just removed the "//" to make is easier to read):
TEST("file://C:/shoot.wav");
TEST("/soundTest/shoot.wav");
TEST("shoot.wav");
As well as, placing a copy of the file in the directory with the package (default), in the src folder, and of course in the root (c:).
How I am envoking the enum is in my main statement where it is all the standard java, main code but with:
SoundEffect.SHOOT.play();
Where exactly does the *.wav file need to be at int he directory? Or if there is another issue I am missing please point it out. I am also using the Eclipse IDE "Kepler," on Windows 8.1. I would like to note the posted code is all I have thus far.
There is some discussion in the comments that Eclipse might be the problem. I seriously doubt Eclipse is the problem. I have loaded hundreds of audio files using Eclipse. Usually I put the files in a sub-directory "audio" that is one level below the calling code, and use the relative address form: "audio/mySound.wav".
Here is how I load my URL:
URL url = this.getClass().getResource("audio/" & fileName);
I am puzzled as to why there are MIDI references in your stack trace. MIDI has nothing to do with loading .wav files, and really should not be involved at all. Are you sure this is the correct stack trace? Why are we seeing references to MIDI?
Sometimes an unrecognizable .wav file format will throw unexpected errors. The most common .wav is 16-bit encoding, 44100 bps, stereo, little-endian. Are your .wav files of this format?
There are some aspects of your code that I haven't seen implemented in this manner, particularly the use of ENUMS. I'll take your word all that has been tested and verified. I tend to just name individual sound objects (using a wrapper for wav files with Clip or SourceDataLine for playback) and use them that way. Could be what you have with that is a good organizational tool, but I'm not clear if it is working as intended.
For example, with Static use of SoundEffect, as in SoundEffect.SHOOT.play(), are you sure it is pointing to the shoot.wav? Have you written a test to verify this? Combining ENUMS and static invocations--it's getting a little tricky for me to follow.

Including all libraries, audio, etc. of a Java program in one JAR file

I am using Netbeans and I am trying to figure out how I can put all of my libraries, music, images, etc. in one JAR file for distribution. I think I have the libraries figured out, but the audio, images, and other such files are giving me trouble.
In my current project I have an audio file that I want to embed in the JAR file too. First I tried one-jar but after a couple of hours I gave up on it. I put the audio file into the JAR file just fine, but I cannot access it from my program. I know I need to use getResourceAsStream as suggested here but I am unclear what I do after I get the input stream. The only way I can see to make it work is to use use the InputStream and create a whole new file (seen below... and it works), but creating a new file seems like a waste (and I don't want people to see an audio file appear when my program is running). Is there no way to directly access the audio file while it is still contained in the .JAR file?
File file = new File("myAudio.wav");
InputStream stream = mypackage.MyApp.class.getResourceAsStream("audio/myAudio.wav");
try {
OutputStream out = new FileOutputStream(file);
byte buf[] = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
inputStream.close();
} catch (IOException e) {
}
EDIT:
The internal structure of my JAR file Contains 1.) a library package (Jama), 2.) my package which is the direct parent of my class files and a folder called "audio" which contains myAudio.wav, and 3.) a META-INF folder which contains my manifest.mf.
EDIT
Audio stream is read something like this. I have tried to use the InputStream directly but I have not had success. I want to point out again that I already have it when I create a new audio file from the input stream of the audio file contained JAR file, but like I said before, it seems like a waste to create a big audio file every time a program is run when the file already exists in the JAR. This file recreation is what I am trying to avoid.
AudioInputStream stream;
Clip music;
try {
stream = AudioSystem.getAudioInputStream(file);
} catch (IOException e) {
} catch (UnsupportedAudioFileException e) {
}
try {
music = AudioSystem.getClip();
} catch (LineUnavailableException e) {
}
try {
start();
} catch (Exception e) {
}
public void start() throws Exception {
music.open((AudioInputStream) stream);
music.start();
music.loop(Clip.LOOP_CONTINUOUSLY);
}
Doesn't AudioSystem.getAudioInputStream(stream); work for you?

Categories

Resources