Hi!
I’ve been extremely successful in making a 2D RPG using some of Bucky’s Java Game Development tutorials from TheNewBoston, and generally just pushing my own envelope. Now I’ve run into a problem I CANNOT solve. I’ve tried for days now, and when you see what the problem is, you will understand my frustration on the matter.
I’ve tried to implement a simple MIDIPlayer (class-code supplied at the bottom). The thing works great, until I export to .jar, then no sound plays, but the game keeps chugging away. So, I read up on it, and apparently there’s some problem with soundbanks, so I installed Java’s deluxe soundbank, to no avail.
NOW, finally I’ve made it work…but ONLY if the MIDI-files are in the same folder as the .jar file, or a folder in that directory. So I read up on THAT, and it seems you’re not supposed to use the standard filepath-method when loading streams (mainly audio) from a .jar file. ONLY if you’re referencing an actual file in the folder of the .jar, as per example:
getSequence(“SomeMIDIfile.mid”);
or in a dedicated folder next to it, as per example:
getSequence(“music/SomeMIDIfile.mid”);
In fact, you’re supposed to reference it using the URL class, and possibly converting that to a URI, and then use the path you can get from there. So I tried that in MANY different forms, and the weirdest thing happens!
The first couple of tries, I got a nullpointer exception, because I was trying to find the correct path-syntax, and when I finally got it, it gave me an error, stating: "Java cannot find the file at the specified location: " and then proceeds to write the correct path, just to mock me
SO, I’m not getting a nullpointer, because it does find the file…but it doesn’t find the file…
The file has been imported into my project on the path: src/snm/music/midis/SomeMIDI.mid
These are the methods I’ve tried to use to get a usable path (tried ALL of them with every single combination of directories in the path above), and they all end up giving me that terrible error-message when I hit the right “spot”.
getSequence(getClass().getResource("/snm/music/midis/SomeMIDIfile.mid").getPath());
getSequence(getClass().getClassLoader().getResource("/snm/music/midis/SomeMIDIfile.mid").getPath());
URL url = new URL("/snm/music/midis/SomeMIDIfile.mid");
getSequence(url.getPath());
As I said, I’ve also tried to convert the URL to a URI to circumvent the %20’s which appear in place of spaces when getting a file-path. I’ve ALSO tried to rewrite the MIDIPlayer so getSequence doesn’t work with File(), but with FileInputStream() instead, still to no avail. It is the same thing with wav-files. Haven’t tried MP3s, but logically it should be the same.
I’m at wit’s end…and I have exhausted Google. They called me and told me to stop searching for JAVA +MIDI +ARGH over and over again…something about their revenues.
PLEASE, can anyone cast some light on this subject?
package snm.music.midiplayer;
import java.io.File;
import java.io.IOException;
import javax.sound.midi.*;
public class MidiPlayer implements MetaEventListener {
// Midi meta event
public static final int END_OF_TRACK_MESSAGE = 47;
private Sequencer sequencer;
private boolean loop;
private boolean paused;
// load 2 pieces of music
// This commented out one doesn't give a nullpointer exception, because the path IS right,
// but it doesn't play anything...The two underneath it, play the MIDI happily when
// executing the .jar file, but only if the .mid is in the same folder.
//private Sequence worldMusic = getSequence(getClass().getResourceAsStream("/snm/music/midiplayer/MainTheme.mid"));
private Sequence worldMusic = getSequence("MainTheme.mid");
private Sequence fightMusic = getSequence("Fighting.mid");
/**
Creates a new MidiPlayer object.
*/
public MidiPlayer() {
try {
sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.addMetaEventListener(this);
}
catch ( MidiUnavailableException ex) {
sequencer = null;
}
}
/**
Loads a sequence from the file system. Returns null if
an error occurs.
*/
public Sequence getSequence(String filename) {
try {
return MidiSystem.getSequence(new File(filename));
}
catch (InvalidMidiDataException ex) {
ex.printStackTrace();
return null;
}
catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
public void playFight(){
play(fightMusic, true);
}
public void playWorldmap(){
play(worldMusic, true);
}
/**
Plays a sequence, optionally looping. This method returns
immediately. The sequence is not played if it is invalid.
*/
public void play(Sequence sequence, boolean loop) {
if (sequencer != null && sequence != null) {
try {
sequencer.setSequence(sequence);
sequencer.start();
this.loop = loop;
}
catch (InvalidMidiDataException ex) {
ex.printStackTrace();
}
}
}
/**
This method is called by the sound system when a meta
event occurs. In this case, when the end-of-track meta
event is received, the sequence is restarted if
looping is on.
*/
public void meta(MetaMessage event) {
if (event.getType() == END_OF_TRACK_MESSAGE) {
if (sequencer != null && sequencer.isOpen() && loop) {
sequencer.start();
}
}
}
/**
Stops the sequencer and resets its position to 0.
*/
public void stop() {
if (sequencer != null && sequencer.isOpen()) {
sequencer.stop();
sequencer.setMicrosecondPosition(0);
}
}
/**
Closes the sequencer.
*/
public void close() {
if (sequencer != null && sequencer.isOpen()) {
sequencer.close();
}
}
/**
Gets the sequencer.
*/
public Sequencer getSequencer() {
return sequencer;
}
/**
Sets the paused state. Music may not immediately pause.
*/
public void setPaused(boolean paused) {
if (this.paused != paused && sequencer != null) {
this.paused = paused;
if (paused) {
sequencer.stop();
}
else {
sequencer.start();
}
}
}
/**
Returns the paused state.
*/
public boolean isPaused() {
return paused;
}
}