3

我一直在试图弄清楚 MIDI 解析的神秘领域,但我没有运气。我要做的就是按照它们发生的顺序获取音符值( 60= C4, = C5 等)。72

我的代码如下。它所做的只是非常简单地以字节数组的形式打开一个文件,然后以十六进制读取所有内容:

byte[] MIDI = File.ReadAllBytes("TestMIDI.mid");
foreach (var element in MIDI) {
    string b = Convert.ToString(element,16);
    Debug.WriteLine(b);
}

所有 TestMIDI.mid 包含的是 C5 上的一个音符。 这是它的十六进制转储。使用此信息,我试图找到 Note On (0x9或只是9在转储中) 的简单十六进制值,但没有任何值。我可以找到一些72,但有 3 个,这对我来说没有任何意义(注意,注意,然后呢?)。

这是我第一次尝试将 MIDI 解析为文件并使用十六进制转储(他们甚至叫它吗?),所以如果我的方向完全错误,我很抱歉。 我所需要的只是得到播放的音符,以及按什么顺序播放。我根本不需要时间或任何花哨的东西。 这背后的原因(如果重要的话)是生成不同语言的新代码以在扬声器中播放,这与beep*nix 上的命令非常相似。正因为如此,我不想使用任何框架,1)我没有编程,真的没有学到任何东西,2)做的远远超过我需要的,使框架比我的实际代码更重.

4

2 回答 2

3

要做到这一点,您至少需要一个 MIDI 解析器的外观。搜索 0x9 事件是一个好的开始,但如果速度字段为 0,0x9 也是一个 Note-Off 事件。0x9 也可以出现在其他事件(元事件、MPQN 事件、增量时间等)中,所以你会得到误报。所以,你需要一些真正知道 MIDI 文件格式的东西才能准确地做到这一点。

寻找一个库,编写自己的库,或者移植一个开源库。如果你想看的话,我的是 Java。

于 2012-11-06T01:47:26.800 回答
3

接受的答案不是问题的解决方案。它在一般情况下不起作用。我将提供此代码不起作用或失败的几种情况。这些案例的顺序对应于它们的概率——最可能的案例排在第一位。

  • 误报。MIDI 文件包含许多数据结构,您可以在其中找到值为 144 的字节。这些结构不是 Note On 事件。对于真正的 MIDI 文件,您会得到一堆“音符”,它们不是音符,而是文件中的随机值。
  • 0 以外的频道。大多数现代 MIDI 文件都包含几个轨道块。每个都保存特定 MIDI 通道(从 0 到 15)的事件。144(或十六进制的 90)表示通道 0 的 Note On 事件。因此您将错过很多其他通道的 Note On 事件。
  • Running status. MIDI files actively use concept of running status. This technique allows don't store status bytes of consecutive events of the same type. It means that status byte 144 can be written only once for the first Note On event and you will not find it further in the file.
  • 144 is the last byte in a file. MIDI file can end with this value. For example if a custom chunk is the last chunk in the file or track chunk doesn't end with End of Track event (which is corruption according to MIDI file specification but possible scenario in real world). In this case you' ll get IndexOutOfRangeException on MIDI[i+1].

因此,您永远不应该搜索特定值来查找 MIDI 文件中的某些语义数据结构。您必须使用 Internet 上可用的 .NET 库之一。例如,对于DryWetMIDI,您可以使用以下代码:

IEnumerable<Note> notes = MidiFile.Read(filePath)
                                  .GetNotes();
于 2017-05-25T10:05:28.387 回答