在 Java 中读取 MIDI 消息:缺少音符关闭事件?

Posted

技术标签:

【中文标题】在 Java 中读取 MIDI 消息:缺少音符关闭事件?【英文标题】:Reading MIDI messages in Java: missing note-off event? 【发布时间】:2020-02-21 00:44:14 【问题描述】:
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 是模型中的一个类。首先,该方法将列表过滤为仅音符开和音符关事件。然后,对于每个事件,如果该事件是一个 note-on,它会尝试将它与相应的 note-off 配对并实例化一个 Note。

我一直在使用仅包含一个音符的 MIDI 文件对其进行测试。正如预期的那样,调试器告诉我过滤列表noteEvents 中有两个元素,但它们在某种程度上都是note-on 事件(它们具有相同的状态字节),显然该方法因此不起作用。该方法是否有问题,或者Java如何将文件转换为事件,或者midi文件只是坏了?

【问题讨论】:

【参考方案1】:

MIDI Specification 说:

MIDI 提供了两种大致等效的关闭音符(声音)的方法。可以通过为相同的音符编号和通道发送 Note-Off 消息,或者通过为该音符和通道发送一个力度值为零的 Note-On 消息来关闭一个音符。使用“Note-On at zero velocity”的好处是可以避免在使用 Running Status 时发送额外的状态字节。

由于这种效率,发送速度值为零的 Note-On 消息是最常用的方法。

【讨论】:

好的,非常感谢。我会尝试看看这是否是问题所在。应该是吧。

以上是关于在 Java 中读取 MIDI 消息:缺少音符关闭事件?的主要内容,如果未能解决你的问题,请参考以下文章

使用 AudioKit 从 MIDI 文件中读取音符

使用 NAudio 从 MIDI 文件中读取音符

在 Java 中播放时将 midi 文件输出到控制台

从 MIDI 中提取音符开始

C++ 中的 MIDI 音符消息

如何使用 NAudio 读取 MIDI 音符?