2010-01-21 4 views
2

J'écris un programme Windows utilisant C++ et l'API Windows, et j'essaie de mettre en file d'attente des messages MIDI dans un flux MIDI, mais je reçois une erreur étrange lorsque j'essaie de le faire. Si j'utilise midiOutShortMsg pour envoyer un message MIDI non-mis en file d'attente au flux, cela fonctionne correctement. Cependant, midiStreamOut renvoie toujours le code d'erreur 68, qui est #define d à MCIERR_WAVE_OUTPUTUNSPECIFIED. midiOutGetErrorText donne la description suivante de l'erreur:Problème lors de l'utilisation de flux MIDI dans Windows

The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup.

J'utilise Windows 7 (64 bits) et ont essayé d'ouvrir le flux MIDI avec des ID de périphériques des deux MIDI_MAPPER et les quatre périphériques de sortie MIDI sur mon système, et reçoivent toujours exactement le même message d'erreur.

Voici le code pour ouvrir le flux MIDI:

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

Voici le code pour envoyer le message 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)); 

Comment puis-je résoudre ce problème?

Répondre

2

Le problème était que j'utilisais toute la structure d'événement comme tampon pour le flux MIDI. Il s'avère que le quatrième membre de la structure, dwParms, devrait effectivement être omis des messages courts. Pour corriger le code de la question posée, deux des lignes de code pourrait être changé à ce qui suit:

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

Lors de l'ajout de plusieurs événements au cours d'eau, il est en fait beaucoup plus facile à utiliser tout un éventail de DWORD s plutôt que de s'embêter avec les structures MIDIEVENT. Pour toute personne effectuant une programmation MIDI à l'aide de l'API Windows, sachez qu'une partie de la documentation MSDN est trompeuse, inadéquate ou totalement erronée.

La documentation de la structure MIDIEVENT dit le texte suivant:

dwParms

If dwEvent specifies MEVT_F_SHORT, do not use this member in the stream buffer.

Ceci est ambigu car il est clair que « utilisation », on entend « inclure » plutôt que « préciser ».

Voici deux autres failles dans la documentation que les programmeurs doivent être conscients de:

dwEvent

Event code and event parameters or length. [...] The high byte of this member contains flags and an event code. Either the MEVT_F_LONG or MEVT_F_SHORT flag must be specified. The MEVT_F_CALLBACK flag is optional.

Lorsque les fichiers d'en-tête sont vérifiés, les MEVT_F_ définitions de préprocesseur précisent réellement complète DWORD s plutôt que les drapeaux individuels, donc dans mon code dans la question, la ligne spécifiant ce membre aurait dû être comme suit:

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

en plus de cela, il est également avéré que la mémoire contenant le MIDIHD La structure R doit être conservée jusqu'à la fin de la lecture de la mémoire tampon. Elle doit donc être allouée sur le tas plutôt que sur la pile pour la plupart des implémentations.

Questions connexes