Проблема с использованием потоков MIDI в Windows - PullRequest
2 голосов
/ 21 января 2010

Я пишу программу для Windows, используя C ++ и Windows API, и пытаюсь поставить в очередь MIDI-сообщения в потоке MIDI, но получаю странную ошибку при попытке сделать это. Если я использую midiOutShortMsg для отправки сообщения MIDI без очереди, оно работает правильно. Однако midiStreamOut всегда возвращает код ошибки 68, от #define d до 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 ) );

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

1 Ответ

2 голосов
/ 22 января 2010

Проблема заключалась в том, что я использовал всю структуру событий в качестве буфера для потока 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, должна сохраняться до завершения воспроизведения буфера, поэтому для большинства реализаций она должна быть размещена в куче, а не в стеке.

...