Вопрос

Я пишу программу Windows, используя C ++ и API Windows, и пытаюсь стоять в очереди MIDI -сообщения в потоке MIDI, но получаю странную ошибку, когда пытаюсь это сделать. Если я использую midiOutShortMsg Чтобы отправить не обездоленное сообщение MIDI в поток, оно работает правильно. Однако, midiStreamOut всегда возвращает код ошибки 68, который #defineD к MCIERR_WAVE_OUTPUTUNSPECIFIED. midiOutGetErrorText дает следующее описание ошибки:

Текущая настройка MIDI Mapper относится к устройству MIDI, которое не установлено в системе. Используйте Midi Mapper, чтобы редактировать настройку.

Я использую Windows 7 (64-бит) и попытался открыть поток MIDI с идентификаторами устройства как MIDI_MAPPER, так и всех четырех устройств MIDI вывода в моей системе, и все еще получаю одинаковое сообщение об ошибке.

Вот код, чтобы открыть поток MIDI:

UINT device_id = MIDI_MAPPER; //Also tried 0, 1, 2 and 3
midiStreamOpen( &midi, &device_id, 1, ( DWORD_PTR )hwnd, 0, CALLBACK_WINDOW );

Вот код, чтобы отправить сообщение MIDI:

MIDIHDR header;
MIDIEVENT *event;

event = ( MIDIEVENT * )malloc( sizeof( *event ) );
event->dwDeltaTime = delta_time;
event->dwStreamID = 0;
event->dwEvent = ( MEVT_F_SHORT | MEVT_SHORTMSG ) << 24 | ( msg & 0x00FFFFFF );

header.lpData = ( LPSTR )event;
header.dwBufferLength = sizeof( *event );
header.dwBytesRecorded = sizeof( *event );
header.dwUser = 0;
header.dwFlags = 0;
header.dwOffset = 0;

midiOutPrepareHeader( ( HMIDIOUT )midi, &header, sizeof( header ) );
midiStreamOut( midi, &header, sizeof( header ) );

Как я могу решить эту проблему?

Это было полезно?

Решение

Проблема заключалась в том, что я использовал всю структуру событий в качестве буфера для потока MIDI. Оказывается, четвертый член структуры, dwParms, на самом деле должно быть опущено из коротких сообщений. Чтобы исправить код в опубликованном вопросе, две строки кода могут быть изменены на следующее:

header.dwBufferLength = sizeof( *event ) - sizeof( event->dwParms );
header.dwBytesRecorded = sizeof( *event ) - sizeof( event->dwParms );

При добавлении нескольких событий в поток на самом деле намного проще использовать массив DWORDS вместо того, чтобы даже беспокоиться о MIDIEVENT структуры.

Для тех, кто занимается программированием MIDI, используя API Windows, остерегайтесь, что часть документации MSDN вводит в заблуждение, неадекватно или совершенно неправильно.

Документация для MIDIEVENT Структура говорит следующее:

DWPARMS

Если DWEVENT указывает MEVT_F_SHORT, не используйте этот член в буфере потока.

Это неоднозначно, потому что неясно, что «использование» предназначено для обозначения «включать», а не «указать».

Вот два других недостатка в документации, о которых должны знать программисты:

Dwevent

Код события и параметры или длину события. [...] Высокий байт этого участника содержит флаги и код события. Либо должен быть указан флаг MEVT_F_LONG или MEVT_F_SHORT. Флаг MEVT_F_CALLBACK не является обязательным.

Когда файлы заголовков проверяются, MEVT_F_ Определения препроцессора фактически указывают комплекс DWORDS, а не только отдельные флаги, поэтому в моем коде в вопросе строка, указанная на этом участнике, должна была быть следующей:

event->dwEvent = MEVT_F_SHORT | MEVT_SHORTMSG << 24 | ( msg & 0x00FFFFFF );

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top