MIDIPacketList, numPackets всегда 1

Я обрабатываю Midi на iPad, и все работает нормально, и я могу регистрировать все, что приходит, и все работает как положено. Однако, пытаясь получить длинные сообщения (например, Sysex), я могу получить только один пакет с максимум 256 байтами и ничего после этого.

Используя код, предоставленный Apple:

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

packetList->numPackets всегда 1. После того, как я получаю это первое сообщение, никакие другие методы обратного вызова не вызываются, пока не будет отправлено "новое" sysex-сообщение. Я не думаю, что мой метод обработки MIDI будет вызван с полным packageList (который может быть любого размера). Я бы подумал, что получу данные в виде потока. Это правильно?

После того, как я покопался, единственное, что я смог найти, было следующее: http://lists.apple.com/archives/coreaudio-api/2010/May/msg00189.html, в котором упоминается то же самое, но это не сильно помогло. Я понимаю, что мне, вероятно, нужно реализовать буферизацию, но я не вижу ничего, кроме первых 256 байтов, поэтому я не уверен, с чего начать.

3 ответа

Мне кажется, что система либо собирает все сообщения sysex в один пакет, либо разбивает его на несколько пакетов. Согласно документации CoreMidi, data Поле структуры MIDIPacket обладает рядом интересных свойств:

Поток MIDI-сообщений переменной длины. Статус работы не разрешен. В случае системных исключительных сообщений пакет может содержать только одно сообщение или его часть без других событий MIDI.

MIDI-сообщения в пакете всегда должны быть полными, кроме системных.

(Длина объявлена ​​равной 256 байтам, поэтому клиентам не нужно создавать собственные структуры данных в простых ситуациях.)

В общем, вы должны смотреть на length поле MIDIPacket и посмотрите, будет ли он больше 256. Согласно спецификации, 256 байтов - это просто стандартное распределение, но этот массив может содержать больше при необходимости. Вы можете обнаружить, что все сообщение помещено в этот массив.

В противном случае кажется, что система разбивает сообщения sysex на несколько пакетов. Так как в спецификации сказано, что статус выполнения не разрешен, то он должен будет отправить несколько пакетов, каждый с ведущим 0xF0 байт. Затем вам нужно будет создать свой собственный внутренний буфер для хранения содержимого этих сообщений, по мере необходимости удаляя байты состояния или заголовок, и добавляя данные в буфер, пока вы не прочитаете 0xF7 байт, который обозначает конец последовательности.

У меня была похожая проблема на iOS. Вы правы, количество MIDI-пакетов всегда равно 1.

В моем случае, при получении нескольких событий MIDI с одной и той же временной меткой (события MIDI, принимаемые одновременно), iOS не разделяет эти несколько событий MIDI на несколько пакетов, как ожидалось.

Но, к счастью, ничего не потеряно! Действительно, вместо того, чтобы получать несколько пакетов с их правильным количеством байтов, вы получите один пакет с несколькими событиями в нем, и число байтов будет соответственно увеличено.

Итак, вот что вам нужно сделать:

При обратном вызове MIDI IN проанализируйте все полученные пакеты (всегда 1 для iOS), затем для каждого полученного пакета необходимо проверить длину пакета, а также состояние MIDI, а затем выполнить цикл в этот пакет, чтобы получить все события MIDI в текущем пакет.

Например, если пакет содержит 9 байтов, а статус MIDI - это нота ON (3-байтовое сообщение), это означает, что ваш текущий пакет содержит более одной ON, тогда вы должны проанализировать первую ON (байты от 0 до 2).) затем проверьте следующий статус MIDI из байта 3 и т. д.

Надеюсь это поможет...

Джером

В этом файле проекта GitHub есть хорошая справка о том, как пройти через MIDI-пакет: https://github.com/krevis/MIDIApps/blob/master/Frameworks/SnoizeMIDI/SMMessageParser.m

(Не мое, но это помогло мне решить проблемы, которые привели меня к этой теме)

Другие вопросы по тегам