Having this simple code which works (but just never ends until I terminated it with ^-c):
import javax.sound.midi.*;
public class Foo {
public void play(int instrument, int note) {
try {
Sequencer player = MidiSystem.getSequencer();
player.open();
Sequence seq = new Sequence(Sequence.PPQ, 4);
Track track = seq.createTrack();
ShortMessage first = new ShortMessage();
first.setMessage(192, 1, instrument, 0);
MidiEvent changeInstrument = new MidiEvent(first, 1);
track.add(changeInstrument);
ShortMessage a = new ShortMessage();
a.setMessage(144, 1, note, 100);
MidiEvent noteOn = new MidiEvent(a, 1); //fired on "tick 1"
track.add(noteOn);
ShortMessage b = new ShortMessage();
b.setMessage(128, 1, note, 100);
MidiEvent noteOff = new MidiEvent(b, 8); //fired on "tick 8"
track.add(noteOff);
player.setSequence(seq);
player.start();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Foo foo = new Foo();
foo.play(0, 42);
}
}
The noteOn
MidiEvent
is fired on 1 tick
(second argument to MidiEvent
constructor). The noteOff
MidiEvent
is fired on 8 tick
, which means. there should be 7 ticks span. But I can never see the end (end of program). When triggered from cmd, the prompt never returns back unless I forced the process to terminate (with <ctrl-c>
). Why is that? When is the end of Sequencer and thus end of the program?
EDIT:
It could be caused be opening the Sequencer, but not closing it. So I wanted to close it at the end, but it cannot follow immediately the player.start()
statement, otherwise it immediately ends. So there must be some delay. It is clunky solution though
...
player.setSequence(seq);
player.start();
TimeUnit.SECONDS.sleep(3);
player.close();
After which, the prompt gets back. But is there a better solution?
The Midi sequence is finished when Sequencer#isRunning() equals
false
. I think you should close the sequencer object before starting another sequence. Declaring the Sequence object as a class member can give a bit more flexability: