我正在用Java编写MIDI文件阅读器(主要是作为练习,可能用于Android项目,因为它不包括javax.sound.midi库)。我正在遵循this规范。
我在我的项目中很好地实现了规范细节,实际读数逐个事件地进行。在文件上打开InputStream
,并且传递相同的对象以解析各种事件对象,使得当事件解析自身时,流被定位在下一个事件处。这一切都很精彩。
我的第一个测试文件只是一个带有在Sonar 8中创建的空数据轨道的速度图。速度轨迹被完美地解析。空轨道在其块标识符和轨道名称之后具有以下数据:
00 B0 07 47 00 0A 40 00 FF 2F 00
成功解析了第一个字节。 00
= delta时间为0,B0
=通道0上的控制器事件,07
=主音量控制,47
=音量值为71。
下一个字节令我困惑。 00 0A 40
最可能的情况是它是一个值为64的Pan事件。0A
是一种Controller事件,我期望在事件前面跟B0
一样。但由于它之前没有已知的事件标识符字节,我的读者无法解析此事件。
所以我想我的问题是如何解释这类事件?在文件格式中是否可以将Controller事件与单个B0
标识符串在一起?另外,如果我在文件中遇到无法识别的事件类型,如果我不知道该事件应该是什么,是否真的有办法知道我可以跳过多少数据?我希望能够跳过未知事件,以便我的读者不会失败,但如果我无法识别事件,我不知道如何跳过它。希望能对这些具体案例有所了解。
答案 0 :(得分:4)
这称为运行状态。它是MIDI规范的一部分。你正在做的事情是正确的。对不起,您必须通过逆向工程MIDI数据流来解决这个问题。 Here is a longer explanation of running status.
并且,是的,具有速度0的Note On事件是Note Off。实际的Note Off事件具有相关的速度,但几乎没有设备实现Note Off velocity,因此在零速度下看Note On更为常见。
答案 1 :(得分:0)
我会回答我自己的问题,以防有人遇到类似的问题。 (但不太可能)
我的上述评论似乎成立了。在读取第一个识别的事件之后,如果后续事件没有事件标识符,则可以将其视为与前一事件相同的事件类型。
所以在我的例子中:
00 B0 07 47 00 0A 40 00 FF 2F 00
也可以解释为两个连续的Controller事件。所以这确实是一个音量事件07
,后面跟着一个事件0A
,当然还有一个事件结束事件FF 2F 00
。
我的代码中的解决方案是记住看到的最后一个标识符,如果流中的下一个字节不是有效标识符,则下一个字节块被解释为与前一个事件相同的事件类型。似乎有意义,更重要的是,我的读者成功完成了。