Problema usando fluxos MIDI no Windows
Pergunta
Estou escrevendo um programa Windows usando o C ++ e a API do Windows e estou tentando fazer fila de mensagens MIDI em um fluxo MIDI, mas estou recebendo um erro estranho quando tento fazê -lo. Se eu usar midiOutShortMsg
Para enviar uma mensagem MIDI não para o fluxo, ele funciona corretamente. No entanto, midiStreamOut
sempre retorna o código de erro 68, que é #define
d para MCIERR_WAVE_OUTPUTUNSPECIFIED
. midiOutGetErrorText
fornece a seguinte descrição do erro:
A configuração atual do MIDI do MIDI refere -se a um dispositivo MIDI que não está instalado no sistema. Use MIDI Mapper para editar a configuração.
Estou usando o Windows 7 (64 bits) e tentei abrir o fluxo MIDI com IDs de dispositivo de Midi_mapper e todos os quatro dispositivos de saída MIDI no meu sistema e ainda recebo exatamente a mesma mensagem de erro.
Aqui está o código para abrir o fluxo MIDI:
UINT device_id = MIDI_MAPPER; //Also tried 0, 1, 2 and 3
midiStreamOpen( &midi, &device_id, 1, ( DWORD_PTR )hwnd, 0, CALLBACK_WINDOW );
Aqui está o código para enviar a mensagem 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 ) );
Como posso resolver esse problema?
Solução
O problema era que eu estava usando toda a estrutura do evento como buffer do fluxo MIDI. Acontece que o quarto membro da estrutura, dwParms
, deve realmente ser omitido de mensagens curtas. Para corrigir o código na pergunta publicada, duas das linhas de código podem ser alteradas para o seguinte:
header.dwBufferLength = sizeof( *event ) - sizeof( event->dwParms );
header.dwBytesRecorded = sizeof( *event ) - sizeof( event->dwParms );
Ao adicionar vários eventos ao fluxo, é realmente muito mais fácil usar uma matriz de DWORD
s em vez de se incomodar com o MIDIEVENT
estruturas.
Para qualquer outra pessoa que faça programação MIDI usando a API do Windows, tenha cuidado que parte da documentação do MSDN seja enganosa, inadequada ou completamente errada.
A documentação para o MIDIEVENT
estrutura diz o seguinte:
dwparms
Se o dwevent especificar mevt_f_short, não use este membro no buffer de fluxo.
Isso é ambíguo porque não está claro que "uso" se destina a significar "incluir" em vez de "especificar".
Aqui estão duas outras falhas na documentação que os programadores precisam estar cientes de:
Dwevent
Código do evento e parâmetros de evento ou comprimento. [...] O byte alto deste membro contém sinalizadores e um código de evento. O sinalizador mevt_f_long ou mevt_f_short deve ser especificado. O sinalizador mevt_f_callback é opcional.
Quando os arquivos do cabeçalho são verificados, o MEVT_F_
Definições de pré -processador realmente especificam completo DWORD
S, em vez de apenas as bandeiras individuais; portanto, no meu código, a linha especificando esse membro deveria ter sido a seguinte:
event->dwEvent = MEVT_F_SHORT | MEVT_SHORTMSG << 24 | ( msg & 0x00FFFFFF );
Além disso, também aconteceu que a memória que contém a estrutura MIDIHDR deve ser mantida até que o buffer termine de reproduzir, para que seja alocado na pilha, em vez da pilha para a maioria das implementações.