Reputation: 19
I know this has been asked a ton of times but it's different in some scenarios so I can't figure it out. When I run my game in Eclipse, everything is going smoothly and the game runs perfectly but after I export it, it collapses. I can open the game and move around in the menu but no sounds are playing and after I hit play, the game just freezes and it gives me this error with cmd (I can paste any class necessary but hopefully just the Audio class is necessary):
java.io.IOException: mark/reset not supported
at java.util.zip.InflaterInputStream.reset(Unknown Source)
at java.io.FilterInputStream.reset(Unknown Source)
at com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown Source)
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at com.neet.Audio.JukeBox.load(JukeBox.java:26)
at com.neet.GameState.IntroState.<init>(IntroState.java:28)
at com.neet.GameState.GameStateManager.loadState(GameStateManager.java:48)
at com.neet.GameState.GameStateManager.setState(GameStateManager.java:72)
at com.neet.GameState.GameStateManager.<init>(GameStateManager.java:31)
at com.neet.Main.GamePanel.init(GamePanel.java:70)
at com.neet.Main.GamePanel.run(GamePanel.java:75)
at java.lang.Thread.run(Unknown Source)
And here is the Audio class: `
package com.neet.Audio;
import java.util.HashMap;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class JukeBox {
private static HashMap<String, Clip> clips;
private static int gap;
private static boolean mute = false;
public static void init() {
clips = new HashMap<String, Clip>();
gap = 0;
}
public static void load(String s, String n) {
if(clips.get(n) != null) return;
Clip clip;
try {
AudioInputStream ais =
AudioSystem.getAudioInputStream(
JukeBox.class.getResourceAsStream(s)
);
AudioFormat baseFormat = ais.getFormat();
AudioFormat decodeFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false
);
AudioInputStream dais = AudioSystem.getAudioInputStream(decodeFormat, ais);
clip = AudioSystem.getClip();
clip.open(dais);
clips.put(n, clip);
}
catch(Exception e) {
e.printStackTrace();
}
}
public static void play(String s) {
play(s, gap);
}
public static void play(String s, int i) {
if(mute) return;
Clip c = clips.get(s);
if(c == null) return;
if(c.isRunning()) c.stop();
c.setFramePosition(i);
while(!c.isRunning()) c.start();
}
public static void stop(String s) {
if(clips.get(s) == null) return;
if(clips.get(s).isRunning()) clips.get(s).stop();
}
public static void resume(String s) {
if(mute) return;
if(clips.get(s).isRunning()) return;
clips.get(s).start();
}
public static void loop(String s) {
loop(s, gap, gap, clips.get(s).getFrameLength() - 1);
}
public static void loop(String s, int frame) {
loop(s, frame, gap, clips.get(s).getFrameLength() - 1);
}
public static void loop(String s, int start, int end) {
loop(s, gap, start, end);
}
public static void loop(String s, int frame, int start, int end) {
stop(s);
if(mute) return;
clips.get(s).setLoopPoints(start, end);
clips.get(s).setFramePosition(frame);
clips.get(s).loop(Clip.LOOP_CONTINUOUSLY);
}
public static void setPosition(String s, int frame) {
clips.get(s).setFramePosition(frame);
}
public static int getFrames(String s) { return clips.get(s).getFrameLength(); }
public static int getPosition(String s) { return clips.get(s).getFramePosition(); }
public static void close(String s) {
stop(s);
clips.get(s).close();
}
}`
Upvotes: 2
Views: 4600
Reputation: 7910
@Jim Garrison gives a good analysis of the issues involved. But a cleaner solution is to use getResource()
instead of getResourceAsStream()
. With this, there is no need for a wrapping class.
In the Javadocs for AudioSystem.getAudioInputStream()
there are multiple entries, each with a different input parameter.
getAudioInputStream(File file)
A File
as an input is not a good choice, because files can't be specified within a jar.
getAudioInputStream(InputStream inputStream)
If an InputStream
is the argument, we have a warning that the mark
and reset
operations on the stream have to be supported (my highlight):
Obtains an audio input stream from the provided input stream. The stream must point to valid audio file data. The implementation of this method may require multiple parsers to examine the stream to determine whether they support it. These parsers must be able to mark the stream, read enough data to determine whether they support the stream, and reset the stream's read pointer to its original position. If the input stream does not support these operation, this method may fail with an IOException.
URL
as the argument, the comment is simply the following line, with no warnings about mark/reset.Obtains an audio input stream from the URL provided. The URL must point to valid audio file data.
Thus, for a wav
resource, the following should work:
URL url = Jukebox.class.getResource(s);
AudioInputStream = AudioSystem.getAudioInputStream(url);
I don't know how you were able to bring in mp3
files. They are not supported by javax.sound.sampled
. Perhaps they worked for you because you employed a library for decoding mp3
files as an intermediary step?
Upvotes: 1
Reputation: 86774
From the Javadoc (my hilighting):
public static AudioInputStream getAudioInputStream(InputStream stream) throws UnsupportedAudioFileException, IOException
Obtains an audio input stream from the provided input stream. The stream must point to valid audio file data. The implementation of this method may require multiple parsers to examine the stream to determine whether they support it. These parsers must be able to mark the stream, read enough data to determine whether they support the stream, and, if not, reset the stream's read pointer to its original position. If the input stream does not support these operation, this method may fail with an IOException.
You appear to be running from a jar file that contains both the code and the sound files. The InputStream
returned from getResourceAsStream()
will not work as it will be backed (or implemented) by a ZipInputStream
, which treats mark()
as a no-op, and throws an IOException
for reset()
.
To solve the problem you should only need to wrap the input stream in a BufferedInputStream
.
AudioInputStream ais =
AudioSystem.getAudioInputStream(
new BufferedInputStream(
JukeBox.class.getResourceAsStream(s)
)
};
Upvotes: 5
Reputation: 19
Thank you everyone for your help but I've figured out that only .mp3 files work and not anything else as it does not process and encode them properly. I knew it was something easy like that and I don't yet have the ability to make it take any kind of sound files so I'll just leave this here for people who have the same problem and haven't thought of the easiest answer which took me a long while to figure out. Thank you!
Upvotes: 0