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
(Не мое, но это помогло мне решить проблемы, которые привели меня к этой теме)