Noob123
Noob123

Reputation: 23

Reading MIDI messages in Java: missing note-off event?

private static List<Note> midiEventsToNotes(List<MidiEvent> midiEvents) {
        List<Note> output = new ArrayList<>();
        Predicate<MidiEvent> noteEvent = me -> me.getMessage().getStatus() >> REST_OF_STATUS_BYTE == NOTE_ON
                || me.getMessage().getStatus() >> REST_OF_STATUS_BYTE == NOTE_OFF;
        List<MidiEvent> noteEvents = midiEvents.stream().filter(noteEvent).collect(Collectors.toList());
        for (int i = 0; i < noteEvents.size(); i++) {
            int eventType = noteEvents.get(i).getMessage().getStatus() >> REST_OF_STATUS_BYTE;
            if (eventType == NOTE_ON) {
                byte pitch = noteEvents.get(i).getMessage().getMessage()[1];
                int startBeat = (int) (noteEvents.get(i).getTick() / ticksPerBeat);
                for (MidiEvent ne: noteEvents) {
                    int pairType =  ne.getMessage().getStatus() >> REST_OF_STATUS_BYTE;
                    byte pitch2 = ne.getMessage().getMessage()[1];
                    if (pairType == NOTE_OFF && pitch == pitch2) {
                        int value = (int) (ne.getTick() / ticksPerBeat - startBeat);
                        int pianoKey = pitch - MIDI_A0_VALUE;
                        output.add(new Note(startBeat, value, pianoKey));
                        break;
                    }
                }
            }
        }
        return output;
    }

I'm trying to read a MIDI file (convert data in the file to data that is handled by my application's model). Here's the method in question. It takes a list of MidiEvent, which should just be a list of all MidiEvent in the file's sequence. The method should output a list of Note, Note being a class in the model. First the method filters the list down to only note-on and note-off events. Then, for each event, if the event is a note-on, it tries to pair it with the corresponding note-off and instantiate a Note.

I've been testing it with midi files containing only one note. As expected, the debugger tells me that there are two elements in the filtered list noteEvents, but they are somehow both note-on events (they have the same status byte), and obviously the method doesn't work because of that. Is there something wrong with the method, or is it how Java is converting the file to events, or are the midi files just bad?

Upvotes: 2

Views: 398

Answers (1)

CL.
CL.

Reputation: 180300

The MIDI Specification says:

MIDI provides two roughly equivalent means of turning off a note (voice). A note may be turned off either by sending a Note-Off message for the same note number and channel, or by sending a Note-On message for that note and channel with a velocity value of zero. The advantage to using "Note-On at zero velocity" is that it can avoid sending additional status bytes when Running Status is employed.

Due to this efficiency, sending Note-On messages with velocity values of zero is the most commonly used method.

Upvotes: 3

Related Questions