Проблема заключалась в том, что я использовал всю структуру событий в качестве буфера для потока MIDI. Оказывается, что четвертый член структуры, dwParms
, должен быть фактически исключен из коротких сообщений. Чтобы исправить код в опубликованном вопросе, две строки кода можно изменить на следующее:
header.dwBufferLength = sizeof( *event ) - sizeof( event->dwParms );
header.dwBytesRecorded = sizeof( *event ) - sizeof( event->dwParms );
При добавлении нескольких событий в поток на самом деле намного проще просто использовать массив DWORD
s, а не даже работать со структурами MIDIEVENT
.
Всем, кто занимается программированием MIDI с использованием Windows API, следует помнить, что некоторые документы MSDN вводят в заблуждение, неадекватны или полностью неверны.
Документация для структуры MIDIEVENT
гласит следующее:
dwParms
Если dwEvent указывает MEVT_F_SHORT, не используйте этот элемент в буфере потока.
Это неоднозначно, поскольку неясно, что «использование» предназначено для обозначения «включать», а не «указывать».
Вот два других недостатка в документации, о которых должны знать программисты:
dwEvent
Код события и параметры или длина события. [...] Старший байт этого члена содержит флаги и код события. Необходимо указать флаг MEVT_F_LONG или MEVT_F_SHORT. Флаг MEVT_F_CALLBACK является необязательным.
Когда проверяются заголовочные файлы, определения препроцессора MEVT_F_
фактически указывают полные DWORD
s, а не только отдельные флаги, поэтому в моем коде в вопросе строка, указывающая этот элемент, должна была выглядеть следующим образом:
event->dwEvent = MEVT_F_SHORT | MEVT_SHORTMSG << 24 | ( msg & 0x00FFFFFF );
В дополнение к этому, оказалось также, что память, содержащая структуру MIDIHDR, должна сохраняться до завершения воспроизведения буфера, поэтому для большинства реализаций она должна быть размещена в куче, а не в стеке.