在 Java 中读取 MIDI 消息:缺少音符关闭事件?
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;
}
我正在尝试读取 MIDI 文件(将文件中的数据转换为由我的应用程序模型处理的数据)。这是有问题的方法。它需要一个 MidiEvent 列表,它应该只是文件序列中所有 MidiEvent 的列表。该方法应该输出一个 Note 列表,Note 在模型中是一个 class。首先,该方法将列表过滤为仅音符开启和音符关闭事件。然后,对于每个事件,如果事件是音符开,它会尝试将其与相应的音符关配对并实例化一个音符。
我一直在用只包含一个音符的 MIDI 文件对其进行测试。正如预期的那样,调试器告诉我过滤列表 noteEvents
中有两个元素,但不知何故它们都是音符事件(它们具有相同的状态字节),显然该方法不起作用,因为那。方法有问题吗,或者 Java 是如何将文件转换为事件的,还是 midi 文件不好?
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.
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;
}
我正在尝试读取 MIDI 文件(将文件中的数据转换为由我的应用程序模型处理的数据)。这是有问题的方法。它需要一个 MidiEvent 列表,它应该只是文件序列中所有 MidiEvent 的列表。该方法应该输出一个 Note 列表,Note 在模型中是一个 class。首先,该方法将列表过滤为仅音符开启和音符关闭事件。然后,对于每个事件,如果事件是音符开,它会尝试将其与相应的音符关配对并实例化一个音符。
我一直在用只包含一个音符的 MIDI 文件对其进行测试。正如预期的那样,调试器告诉我过滤列表 noteEvents
中有两个元素,但不知何故它们都是音符事件(它们具有相同的状态字节),显然该方法不起作用,因为那。方法有问题吗,或者 Java 是如何将文件转换为事件的,还是 midi 文件不好?
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.