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

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.

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.

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.

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.

Playing audio in java using Sun.audio

I want just to perform a simple task. (I'm a java newbie). I want to play an audio clip when a button is clicked.
here's the part of my code(which I did exactly by copying a tutorial from Youtube.)
private void btnPlayActionPerformed(java.awt.event.ActionEvent evt) {
InputStream in;
try{
in=new FileInputStream(new File("C:\\Users\\Matt\\Documents\\dong.wav"));
AudioStream timeupsound=new AudioStream(in);
AudioPlayer.player.start(timeupsound);
}
catch(Exception e){
JOptionPane.showMessageDialog(null, e);
}
}
But the problem is, this doesn't work.
It throws and IOException saying: "could not create audio stream from input stream".
My question is, what am I doing wrong? (as I clearly saw this code work in that youtube video, and I've used the same code. Please help. and once again, I'm a newbie);
The sun package classes should be causing some informative warnings at compile time. Heed them. Don't use classes in that package hierarchy. They are undocumented, are not guaranteed from one Java version to the next, and will probably not be available in a non-Oracle JRE at all.
Instead use the Java Sound based Clip to play audio. See the info. page for working examples.
Note
It might be the WAV is encoded in a format that Java Sound does not support. Media formats are typically 'container formats' that might be encoded using any number of different Codecs. It is likely that WAV is using a more compressive Codec such as MP3 or OGG internally.
I don't know of a Service Provider Interface for the OGG format, but if they are encoded as MP3, you might be able to get it working using the MP3 SPI. See the info. page linked above for details.
Tip
Also change code of the form:
catch (Exception e) { ..
To
catch (Exception e) {
e.printStackTrace(); // very informative! ...

Categories

Resources