Terminate Java Midi output
I wrote this short program to learn the javax.sound.midi system. This is using Java 6. The output is as expected (a series of System.out.println() strings that are triggered by Sequencer events) but the problem is, after the last sound effect, the program stays in a loop and doesn't terminate as expected.
Can anyone tell how to fix this? Thanks for your help:
import开发者_JAVA技巧 javax.sound.midi.MidiEvent;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.ControllerEventListener;
import javax.sound.midi.Sequencer;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiUnavailableException;
class MySound {
public static MidiEvent makeEvent(int comd, int chan, int one,
int two, int tick) {
MidiEvent event = null;
try {
ShortMessage a = new ShortMessage();
a.setMessage(comd, chan, one, two);
event = new MidiEvent(a, tick);
} catch (InvalidMidiDataException imde) {
imde.printStackTrace();
}
return event;
}
}
class MyControllerListener implements ControllerEventListener {
public void controlChange(ShortMessage event) {
System.out.println("la");
}
}
class SoundEffects {
public static void main(String[] args) {
try {
Sequencer seq = MidiSystem.getSequencer();
seq.open();
int[] events = { 127 };
MyControllerListener mcl = new MyControllerListener();
seq.addControllerEventListener(mcl, events);
Sequence s = new Sequence(Sequence.PPQ, 4);
Track t = s.createTrack();
for (int i = 5; i < 60; i += 4) {
t.add(MySound.makeEvent(144, 1, i, 100, i));
t.add(MySound.makeEvent(176, 1, 127, 0, i));
t.add(MySound.makeEvent(128, 1, i, 100, i + 2));
}
seq.setSequence(s);
seq.setTempoInBPM(220);
seq.start();
} catch (InvalidMidiDataException imde) {
imde.printStackTrace();
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
}
You need to call seq.close() once the track has finished playing. The way to do that is to add a meta message listener, and invoke close() when you encounter a message of type 0x2F (which is the non-optional meta message "end of track"). Your code would look something like this:
seq.addMetaEventListener(new MetaEventListener() {
@Override
public void meta(MetaMessage metaMsg) {
if (metaMsg.getType() == 0x2F) {
seq.close();
}
}
});
Note that you would need to add the final
modifier to seq
in order to refer to it in the anonymous Interface implementation.
Hope that helps.
精彩评论