Ищу программу верификации миди файла на соответствие стандарту

>Quiet Snow<

Member
10 Мар 2014
38
23
8

Приветствую товарищи софтоведы! В общем кратко суть вопроса в следующем:
Сам кодер и пишу прогу для вскрытия и парсинга событий из midi файла. Так вот столкнулся с тем,
что некоторые нюансы(midi события) не описаны в документации (сверяюсь с несколькими
источниками тут тут и тут. Прога бисквита для подсистемы adlib(да такая древность)
по последней ссылке - работает идеально, но в ней мало что понятно(сколько не пытался разобрать её
на молекулы - не удалось), поэтому пишу парсинг с нуля, вроде бы всё работает, но попадаются события,
которые фиг знает как интерпретировать (не указано что за событие, каков его размер в байтиках, параметры
и т.д), прога не может распознать это нормально и дальнейшее распознавание рушится. И вот начал
сомневаться, что некоторые midi файлы являются стандартом. Поэтому основная суть темы: прошу знатоков
подсказать программу, которая бы анализировала *.mid файл на соответствие стандарту midi, самому самому
общему и простому, который поддерживается большинством устройств.

А собственно моей целью является выдирать ноты(нажал кнопочку\отпустил, время, номер ноты, велосити,
панораму) и их параметры из любого midi файла. Может быть кто работал в этом направлении и сможет
подсказать более конкретно, буду рад любым комментариям и обсуждению.
 
Попробуйте для начала отсечь sysex-блоки, которые входят в миди-протокол, но не являются "стандартными".
У этих блоков началом явлется байт <11110000> (в двоичном коде), концом байт <11110111>. Т.е удаляйте из рассмотрения эти байты и то, что между ними. То что останется, будет, скорее всего, более точно соответствовать вашим источникам документации
 
  • Like
Реакции: >Quiet Snow<
Попробуйте для начала отсечь sysex-блоки

Что-то мне подсказывает, что найденный мною "мусор" в Midi файле не sysex. Приведу
конкретный пример, у меня есть midi файл, в котором всего две ноты, забил его через
какую-то Freeware прогу на Java(уже не помню, т.к. удалил её). Так вот в этом midi
файле всего 2 трека, на треке №2 куча непонятных данных с точки зрения документации:

Посмотреть вложение 81280

И получается что прога с лёгкостью может парсить некоторые "толстые" midi файлы,
а простейший файл из двух нот даже и не понятно как обрабатывать. Такие пироги...
В доке большинство известных длин команд указано и перебить их в код не проблема.
Т.е. тут либо какая-то нестандартность либо что-то жёстко не понимаю.

Пишу всё это на FreeBASIC в режиме FBLite, юзаю FBIDE, компилирую в режиме консоли.
Приложил исходник и midi файл. Пытаюсь максимально упростить код, сделать в
процедурном стиле, бисквит что-то там наворотил много слишком, но у него конечно
прога работает идеально и легко "перемалывает" все эти кривые файлы, хотя вроде бы
нет там ничего сверхъестественного и его парсинг тоже где-то чуть больше 300 строк
занимает.
 

Вложения

Выложите только миди-файл в формате rar.
Пока вот такие замечания.
Set BPM у Вас посчитано неверно. MPQN=X(09 27 C0) = dec(600000)

MICROSECONDS_PER_MINUTE = 60000000
BPM = MICROSECONDS_PER_MINUTE / MPQN = 60000000/600000=100

Дальше The event delta time is defined by a variable-length value.
Это означает не фиксированную длину, а переменную, т.е.
если знаковый(левый) бит = 1, то добавляется следующий байт,
и так до тех пор пока знаковый бит не будет = 0.
В Вашем случае, например встречается 81 00, и в десятичную систему немного хитро переводится:
Сначала убираются знаковые биты из каждого байта,
т.е в 16-ричной системе 81=01, А1=21, С3=43, 7F=7F, 00=00 и т.д.
затем байты нумеруются !!!справа налево!!! 0-1-2-...
переводятся в десятичную систему,
умножаются каждый на 128(dec) в степени своего номера,
затем суммируются.
81 00 =00*128^0 + 1*128^1 = 128 (dec)

Ещё замечание, Вы неверно интерпретируете Event Type Value.
B0 означает не 176, а B(hex)=11(dec), т.к. 0 - это MIDI Channel.
Delta Time Event Type Value MIDI Channel
variable-length 4 bits 4 bits

Самое тёмное место в Вашем примере это <00 20 00> похоже на какую-то ошибку,
т.к. 2 - отсутствующий в описании Event Type скорее всего с одним параметром.
Похоже на событие <Нота 20(hex)=32()dec=2*12+8=Соль# 3 октавы > с velocity=0
Как оно сюда затесалось,непонятно

Остальное вполне расшифровывается:

00 B0 00 00 - Controller 0xB controller number controller value
*** установка контроллера 0 в 0 - (0 (0x00) Bank Select)
00 C0 64 - Program Change 0xC program number
*** установка номера программы в банке в 64hex=128dec
00 90 47 64 - Note On 0x9 note number velocity
*** нажатие ноты(47hex=71dec=12*6-1 - B5 нота Си 5-й октавы) с velocity=64hex=100dec

**** Замечу, что Note On "взводится" и действует на следующие ноты, пока не произойдёт Note Off 0x8

81 00 47 00 - 8100=128тиков=1четверть,т.к. из заголовка Delta ticks=128
*** нота(47hex=B5) velocity 00 - это аналогично Note off(в Вашей документации этого нет)
00 48 64 - нажатие ноты(48hex=72dec=12*6 - С6 нота До 6-й октавы) с velocity=64hex=100dec через 0 тиков(сразу)
81 00 48 00 - 8100=128 тиков=1 четверть
*** нота(48hex=С6) velocity 00 - это аналогично Note off
83 00 FF 2F - 8300=3*128=3 четверти конец трека
*** Meta Event Type Length
*** 255 (0xFF) 47 (0x2F) 0
*** End Of Track Meta Event Values
 
Последнее редактирование:
  • Like
Реакции: >Quiet Snow<
Добрался до компа наконец.
Выложите только миди-файл в формате rar.

В архиве который приложил вторым постом этот миди файл есть, точнее там других миди файлов
и нету только этот. А зачем именно Rar? Неужели Zip не открывается? К сожалению Rar сделать не
получится(у меня 7Zip, пиратское ПО не юзаю), только один из следующих форматов: 7z, Bzip2,
Gzip, Tar, Wim, Xz, Zip.

Дальше The event delta time is defined by a variable-length value.
Это означает не фиксированную длину, а переменную

Этот нюанс учитывается.

Ещё замечание, Вы неверно интерпретируете Event Type Value.
B0 означает не 176, а B(hex)=11(dec), т.к. 0 - это MIDI Channel.

У меня в коде ещё кучи событий нет просто первоначально хочу перебить длины команд, чтобы
файлы парсились без проблем, а потом уже делать обработку всего этого.
Суть в том что у бисквита всё пашет и даже нотки отображаются(мол что эти 2 ноты были проиграны)
он сам писал что тестировал свою прогу на куче midi файлов, но мне например одного этого файла
хватило, чтобы понять что прога идеальна.
С битовыми операциями и пониманием интерпретации значений - проблем нет, проблемы с документацией.

Set BPM у Вас посчитано неверно.

Да это знаю что неверно. Сразу заметил, когда увидал что темп за 300. Пофиксю чуть позже,
не принципиально пока.

Самое тёмное место в Вашем примере это <00 20 00> похоже на какую-то ошибку

Если бы это была ошибка, прога бисквита бы не проигрывала файл. Тут что то иное.
Сижу вот читаю документацию MMA, наверное надо просто начать делать реверс его проги,
но там конечно жуть.

81 00 47 00 - 8100=128тиков=1четверть,т.к. из заголовка Delta ticks=128
*** нота(47hex=B5) velocity 00 - это аналогично Note off(в Вашей документации этого нет)
00 48 64 - нажатие ноты(48hex=72dec=12*6 - С6 нота До 6-й октавы) с velocity=64hex=100dec через 0 тиков(сразу)
81 00 48 00 - 8100=128 тиков=1 четверть
*** нота(48hex=С6) velocity 00 - это аналогично Note off
83 00 FF 2F - 8300=3*128=3 четверти конец трека
*** Meta Event Type Length
*** 255 (0xFF) 47 (0x2F) 0
*** End Of Track Meta Event Values
Чуть позже проанализирую это, надо через прогу гонять, так мало понятного.
Нужно больше отладочной информации. Может быть в этом куске и нет проблем.
 
Последнее редактирование:
*** А зачем именно Rar? Неужели Zip не открывается?
Можно и Zip, но только миди-файл, чо-то антивирус ругается


*** Дальше The event delta time is defined by a variable-length value.
*** Этот нюанс учитывается.
00 47 00 00 48 64 81 00 48 00 83
тогда почему это у Вас одним куском, а не 3-мя событиями?


*** Set BPM у Вас посчитано неверно.
*** Да это знаю что неверно. не принципиально пока.
Согласен


*** Самое тёмное место в Вашем примере это <00 20 00> похоже на какую-то ошибку
*** Если бы это была ошибка, прога бисквита бы не проигрывала файл. Тут что то иное.
Это ошибка в смысле появления этого, а не в смысле интерпретации.
Не должна сниматься ненажатая нота.

*** Чуть позже проанализирую это, надо через прогу гонять, так мало понятного.
Задавайте вопросы, смогу-отвечу.
 
  • Like
Реакции: >Quiet Snow<
Интересно, зачем такие мучения, если миди файл можно импортировать в любую DAW и там выдрать все что угодно.
 
Интересно, зачем такие мучения, если миди файл можно импортировать в любую DAW и там выдрать
все что угодно.
а зачем это ТС не совсем понятно.

Читать тут много, для терпеливых, но в первом посте всё разъясняется.
http://iforum.pro/proekty-na-basic-...ki-planirovanie-proekta-realizaciya-1384.html

Говоря простым языком, делал GPL проект, в определённой фазе он остановился, но т.к. я осознаю что без
поддержки Midi это вообще мало кому нужно(в midi огромное количество нотного материала),
пытаюсь освоить этот протокол. Проект сложный, а я не такой уж способный прогер как оказалось,
говоря мягко. Поэтому не знаю, что из этого выйдет, но пока есть желание и возможности как говорится
набираюсь опыта и знаний, ковыряюсь в тех подзадачах, которые необходимы. Хорошо , когда есть
работающая прога, написанная своими руками - уже проще становится видно что да как, можно
задокументировать, расставить коментарии, выложить куда то чтобы народ юзал. Всё ж сейчас буржуйское
фиг подлезешь куда без переводчика.

Думаю, всё это нужно только при отсутствии DAW

DAW то есть, давным давно полностью освоил FL Studio c 5 по 9-ку, но уже так скажем определённый
срок я не пользуюсь варезом вообще, просто захотелось стать нормальным честным человеком.
Кроме того есть Ableton Live 8 самый самый базовый(лицуха), шёл в комплекте с Midi клавой, я хоть и
почитал к нему мануалы и посмотрел видео, которые мне на почту сыпят, но особо не раскушал, короче
говоря не удобен он для меня(изредка включаю фортепиано и подклады оттуда).
А идея реализации чего-то простого посещала уже давно, это преследует несколько целей сразу и не
относится к проф. муз. индустрии.

тогда почему это у Вас одним куском, а не 3-мя событиями?

Просто прога уже не смогла распознать и я пометил это как неизвестный кусок. В MIDI командах то
я пока "ласось" и на глазок эти HEX-ы не могу разбить на команды, хотя вроде бы по проге бисквита
видно что там да как, где отсекаются sysex-ы где обычные события, где мета команды.

Задавайте вопросы, смогу-отвечу.

Да спрашивать не обдумав тоже как-то нелепо получится. Смущают только эти первые отмеченные
мной 3 байта. А ошибок в файле быть вроде бы не должно, т.к. он не захвачен откуда то с устройства,
а создан программой. В любом случае спасибо за помощь, второй кусок вы разобрали и мне надо просто
на свежую голову сесть и проанализировать.

Можно и Zip, но только миди-файл, чо-то антивирус ругается

ok вложил, антивирус ругается на мою прогу, т.к. в ней есть команда SLEEP(отдача времени процессору+
ожидание кнопки). Мне говорили о подобных вещах. В проге естественно никаких вредоносов нет,
рядом исходник, можно скомпилировать на FB, вот сборка Станислава Будинова:
FBEdit + компилятор FreeBASIC
, которой я сам пользуюсь(Информация). Там ничего сложного нет.
 

Вложения

  • Midi
    Midi
    214 байт · Просмотры: 1
KARMA (Kay Algorithmic Realtime Music Architecture) является уникальной технологией алгоритмического создания музыкальных эффектов, генерирующей MIDI-данные. Эта технология - результат семилетних разработок - имеет пять патентов США за различные части процесса, и ряд других международных патентов.
А здесь человек только начинает, может у него это займёт 1 год и получится хотя бы обалденный арпеджиатор, основанный на некоей уникальной(именно его) технологии. Для этого надо как минимум уверенно разобраться в миди-протоколе, что ТС и начинает делать.
Теперь по делу ТС. В Вашей документации указано

<MIDI-event> ::= <status-byte> <data-byte>
*<status-byte> ::= [\x80-\xFF]<data-byte> ::= [\x00-\x7F]

Хочу добавить
<status-byte> ::= [\x00-\x7F] означает что это Note (номер=<status-byte>) 00=До 0-й октавы(C0), 7F=соль 10-й(G10)
и тогда
<data-byte> ::= [\x00-\x7F] это Velocity
Именно это и означают первые Ваши "непонятные" 3 байта <00 20 00>
да и следующие тоже <00 C0 64>
Естественно 1-байт <00>в обоих случаях это <
event delta time>
Во втором выделенном Вами куске, советую добавить слева 1 байт = <81>,
ибо здесь <81 00> это <
event delta time>
 
Последнее редактирование:
Хочу добавить
<status-byte> ::= [\x00-\x7F] означает что это Note (номер=<status-byte>)

Фишка в том, что это не может быть номер ноты, потому что в файле всего 2 ноты которые имеют номера
71(47h) и 72(48h). Первое событие note on соответствует первой ноте, вторая нота должна идти через
определённое время(дельта должна пройти). А как парсить это дело не понятно, т.к. не получается
однозначно охарактеризовать каждый эвент. Часть эвентов нужно отбросить(но чтобы отбросить нужно
знать либо длины эвентов либо методику их пропуска), а часть обработать по документации, т.е.
ID события, в котором анализируются отдельные биты, и дальше в зависимости от этого уже парсится
опр. способом, всё это в доке прописано.

Вот открыл в LMMS-е, всё стоит так как ставил в другой проге:

kkk.JPG

ибо здесь <81 00> это <event delta time>

Да верно 1 байт упустил.

По сути должно быть что то в духе:
Включить ноту 71
Дельта +
Выключить ноту 71
Включить ноту 72
Дельта +
Выключить ноту 72
Конец​
Всё это на одном канале, с одинаковой силой звукоизвлечения(velocity) и панорамой(panning).
 
Последнее редактирование:
Фишка в том, что это не может быть номер ноты, потому что в файле всего 2 ноты которые имеют номера
71(47h) и 72(48h). Первое событие note on соответствует первой ноте, вторая нота должна идти через
определённое время(дельта должна пройти).

По сути должно быть что то в духе:
Включить ноту 71
Дельта +
Выключить ноту 71
Включить ноту 72
Дельта +
Выключить ноту 72
Конец​

Всё это на одном канале, с одинаковой силой звукоизвлечения(velocity) и панорамой(panning).
Как раз всё не совсем так. Ноты включаются и выключаются не одним способом кодирования. Например
Включение нот
1 вариант: 00 90 47 64 08 90 48 64 - включить ноту 47 с velocity=64 через 8 тиков включить ноту 48 с velocity=64
2 вариант: 00 90 47 64 08 48 64 - это то же самое, но для второй ноты не указывается 90=9(NoteOn)0(channel)

Если ноты с разных миди-каналов, 2 вариант не пройдёт, надо будет сделать так
00 90 47 64 08 93 48 64 у 1-й ноты и 2- ноты разные каналы - 0 и 3

также не пройдёт 2-й вариант, если между двумя этими нотами будет какое-то другое миди-событие, например вкл/выкл педали сустейна

Выключение нот
1 вариант: 00 80 47 vv - выключить ноту 47, vv - любое velocity(в Вашей документации сказано, что от vv зависит оттенок послезвучия)
2 вариант: 00 47 00 - выключает ноту, если между вкл/выкл ноты нет других событий, кроме нот
3 вариант: 00 90 47 00 - выключает ноту, если между нотами были другие события

Я всё это гонял на миди-файлах из Сонара, вариант <00 80 47 vv> пока не всретился ни разу.

А в Вашем миди-файле 00 20 00 снимается не нажатая нота,
у неё нет события нажатия, нет момента нажатия, следовательно и какой-то длины звучания,
видимо программа, которая его создала с "умничала" и в LMMS-е эту ноту не видно

А панорама тут вообще не причём, это совершенно отдельная песня контроллера A(hex)=10(dec).
 
Последнее редактирование:
  • Like
Реакции: >Quiet Snow<
Включение нот
1 вариант: 00 90 47 64 08 90 48 64 - включить ноту 47 с velocity=64 через 8 тиков включить ноту 48 с velocity=64
2 вариант: 00 90 47 64 08 48 64 - это то же самое, но для второй ноты не указывается 90=9(NoteOn)0(channel)

Выключение нот
1 вариант: 00 80 47 vv - выключить ноту 47, vv - любое velocity(в Вашей документации сказано, что от vv зависит оттенок послезвучия)
2 вариант: 00 47 00 - выключает ноту, если между вкл/выкл ноты нет других событий, кроме нот
3 вариант: 00 90 47 00 - выключает ноту, если между нотами были другие события

:wacko3: Жестковато...))) И сильно похоже на правду, я вот пока вы это ещё не написали сидел расшифровывал
всё получилось так, как вы говорите, ошибся только в одном байте, сейчас поправил, вроде более менее начинаю
втыкать, но всё равно определённые непонятки имеются и не даёт покоя этот 00 20 00. Также не даёт покоя что
чётко не указано в документации мол что события для нот прописываются без ID события. Может быть где-то в
MMA документации сказано, я конечно почитываю(переводчик Dicter сильно помогает), но там всё инглиш и дофига
больно всяких мелких дополнений, которые добавляли по мере развития интерфейса MIDI.

Получилась такая бадяга:
──────────Track 1────────────────────────────────────────────────────────────
00 FF 51 03 09 27 C0 - Дельта 0, Мета событие(255), номер метасобытия 81(51h), байт длины, 3 байта - темп
00 FF 2F 00 - Дельта 0, конец трека
──────────Track 2────────────────────────────────────────────────────────────
00 B0 00 00 - дельта 0, Изменение контроллера 0 (выбор банка)
00 20 00 - дельта 0, фиг знает что за событие
00 C0 64 - дельта 0, выбор программы(инструмент, патч)
00 90 47 64 - дельта 0, включить ноту 9h(вкл) 0h(канал), 71(47h), velocity - 100(64h)

81 00 47 00 - дельта 128, ID события нет (предположим выключить ноту), нота 71(47h)

00 48 64 - дельта 0, ID события нет (предположим включить ноту), нота 48

81 00 48 00 - дельта 128, события нет (предположим выключить ноту), нота 48

83 00 FF 2F 00 - Дельта 384, Мета событие(255), номер метасобытия 47(2Fh) - конец трека.

Самое печальное, что доселе не ясно как отсекать кривые варианты(учитывая, что вариантов
взведения\гашения ноты может быть много), придётся изобретать всякую фигню.
Также непонятна деталь: почему если юзается такая запись, используется первое событие
стандартное, хотя могло быть точно так же без идентификатора события, всё таки если верить
данной логике - экономится целый байт.
 
Также не даёт покоя что
чётко не указано в документации мол что события для нот прописываются без ID события. Может быть где-то в
MMA документации сказано
Именно ord(stause-byte)<=$7F и является ID события-Note (ord функция в Паскале, Вы должны знать)
Дальше потом подробнее отвечу, вчера у друга был ДР, тяжело пока...
 
(ord функция в Паскале, Вы должны знать)

На Паскале не писал с 2008 года, всё забыто уже, но есть School Pack и Free Pascal Compiler,
так что схавать код на Паскале думаю смогу, если он не нашпигован ООП-шкой. Естественно
первым делом искал коды на Паскале, но что-то там не густо было, встретился только порт
какой-то проги с ассемблера и там ещё похлеще, чем у бисквита. Впрочем, конечно искал не
углублённо, что-то всё таки midi-шное должно быть как на FPC так и на обычном турбопасе.
Просто очень напряжно рыть тонны сообщений у буржуев, в поиске этого добра.

Сейчас правда скорее всего отвечать не получится т.к. за 3 дня надо 2 винды поставить(в т.ч.
на моём компе), но тема по разбору MIDI очень актуальна и если у кого есть идеи - пишите,
мозговать вместе продуктивнее.
 

Сейчас просматривают