6

我正在 iPad 上处理 Midi,一切正常,我可以记录所有进入的内容,一切都按预期工作。但是,在尝试接收长消息(即 Sysex)时,我只能得到一个最大 256 字节的数据包,之后什么也没有。

使用 Apple 提供的代码:

MIDIPacket *packet = &packetList->packet[0];
for (int i = 0; i > packetList->numPackets; ++i) {
    // ...
    packet = MIDIPacketNext (packet);
}

packetList->numPackets始终为 1。在我收到第一条消息后,在发送“新”sysex 消息之前不会调用其他回调方法。我不认为我的 MIDI 处理方法会被完整的 packetList 调用(可能是任何大小)。我原以为我会以流的形式接收数据。这个对吗?

在挖掘之后,我唯一能找到的是: http: //lists.apple.com/archives/coreaudio-api/2010/May/msg00189.html,其中提到了完全相同的事情,但没有太大帮助。我知道我可能需要实现缓冲,但我什至看不到前 256 个字节之后的任何内容,所以我不知道从哪里开始。

4

3 回答 3

4

我的直觉是,系统要么将整个 sysex 消息塞入一个数据包,要么将其分解为多个数据包。根据CoreMidi文档,dataMIDIPacket 结构的字段有一些有趣的属性:

可变长度的 MIDI 消息流。不允许运行状态。在系统专有消息的情况下,一个数据包可能只包含一条消息或一条消息的一部分,没有其他 MIDI 事件。

数据包中的 MIDI 消息必须始终完整,系统专有除外。

(这被声明为 256 字节的长度,因此客户端不必在简单的情况下创建自定义数据结构。)

所以基本上,您应该查看声明的length字段,MIDIPacket看看它是否大于 256。根据规范,256 字节只是标准分配,但如果需要,该数组可以容纳更多。您可能会发现整个消息都被塞进了那个数组。

否则,系统似乎将 sysex 消息分解为多个数据包。由于规范说不允许运行状态,所以它必须发送多个数据包,每个数据包都有一个前导0xF0字节。然后,您需要创建自己的内部缓冲区来存储这些消息的内容,根据需要剥离状态字节或标头,并将数据附加到缓冲区,直到您读取0xF7表示序列结束的字节。

于 2010-12-29T15:45:27.893 回答
3

我在 iOS 上遇到了类似的问题。你是对的 MIDI 数据包编号始终为 1。

就我而言,当接收到具有相同时间戳的多个 MIDI 事件(同时接收到的 MIDI 事件)时,iOS 不会像预期的那样将这些多个 MIDI 事件拆分为多个数据包。

但是,幸运的是没有丢失任何东西!实际上,您将收到一个包含多个事件的单个数据包,而不是接收具有正确字节数的多个数据包,并且字节数将相应增加。

所以在这里你要做的是:

在您的 MIDI IN 回调中,解析收到的所有数据包(对于 iOS,始终为 1),然后对于收到的每个数据包,您必须检查数据包的长度以及 MIDI 状态,然后循环进入该数据包以检索当前的所有 MIDI 事件包。

例如,如果数据包包含 9 个字节,并且 MIDI 状态是一个音符开(3 个字节消息),这意味着您当前的数据包包含多个音符开,那么您必须解析第一个音符开(字节 0 到 2 ) 然后从字节 3 开始检查以下 MIDI 状态,依此类推..

希望这可以帮助 ...

杰罗姆

于 2014-01-17T10:17:38.463 回答
1

在 GitHub 项目的这个文件中,有一个关于如何遍历 MIDI 数据包的很好的参考:https ://github.com/krevis/MIDIApps/blob/master/Frameworks/SnoizeMIDI/SMMessageParser.m

(不是我的,但它帮助我解决了让我进入这个线程的问题)

于 2014-02-26T14:06:22.073 回答