We are trying to code a simple guitar hero clone for university using javax.sound.midi.
Currently we can play back a midi file with a sequencer and log the midi event that is currently played. However, we want to display the upcoming event (more specifically, the the data bytes in the MIDI message that indicate the note).
We are currently using a Sequencer to play the sounds and a Receiver and that logs the sound to the console. However, it logs it the exact moment the sound is played, not the upcoming sound.
In Sequencer class:
public void startSequencer() {
try {
sequencer.open();
Thread.sleep(2000);
sequencer.setTempoInBPM(BPM);
InputStream is = new BufferedInputStream(new FileInputStream(song));
sequencer.setSequence(is);
sequencer.getTransmitter().setReceiver(receiver);
sequencer.start();
while (sequencer.isRunning()) {
Thread.sleep(100);
}
sequencer.close();
System.out.println(receiver.getNoteOnAmount());
} catch (MidiUnavailableException | InterruptedException | IOException | InvalidMidiDataException e) {
throw new RuntimeException(e);
}
}
In Receiver class:
public void send(MidiMessage message, long timeStamp) {
//If the Status is NOTE_ON (144), process the note
if (message.getStatus() == 144) {
System,out.println(message.getMessage()[1]);
}
Retrieve the
Sequence
from theSequencer
usingSequencer.getSequence()
.All the
MidiEvents
from the Midi file are stored in one or moreTrack
instances within theSequence
. AMidiEvent
is aMidiMessage
with a tick position.MidiEvents
are ordered by tick position.So in your
Receiver.send(MidiMessage)
method, search the tracks to find theMidiEvent
which corresponds to the receivedMidiMessage
.If you have only one track and find the corresponding
MidiEvent
at indexmeIndex
/tickmeTick
, then the nextMidiEvents
to be played are atmeIndex+1
,meIndex+2
etc. If you have several tracks, you also need to search other tracks forMidiEvents
whose tick position is right aftermeTick
.Of course there is plenty of room for optimization (e.g. preprocess
Tracks
in advance), so that you don't spend time reparsing all the Tracks each time you receive a note.