views:

102

answers:

2

Hello,

I'm writing a Windows program using C++ and the Windows API, and, am trying to queue MIDI messages in a MIDI stream, but am receiving a strange error when I try to do so. If I use midiOutShortMsg to send a non-queued MIDI message to the stream, it works correctly. However, midiStreamOut always returns error code 68, which is #defined to MCIERR_WAVE_OUTPUTUNSPECIFIED. midiOutGetErrorText gives the following description of the error:

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

I am using Windows 7 (64-bit) and have tried opening the MIDI stream with device IDs of both MIDI_MAPPER and all four MIDI output devices on my system, and still receive the exact same error message.

Here is the code to open the MIDI stream:

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

Here is the code to send the MIDI message:

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 ) );

How can I resolve this problem?

+1  A: 

Configuring the MIDI mapper is described in this KB article.

Hans Passant
Thanks for your answer. However, that article is for Windows 3.1. As I said, I'm running Windows 7, and sending a short MIDI message works fine; MIDI works fine on my system. That's why the error message being produced is strange; it's a Windows 3.1 error message and doesn't really make much sense.I've solved the problem already, now, so I will post the solution later on today.
Sam
A: 

The problem was that I was using the entire event structure as the buffer for the MIDI stream. It turns out that the fourth member of the structure, dwParms, should actually be omitted from short messages. To correct the code in the posted question, two of the lines of code could be changed to the following:

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

When adding multiple events to the stream, it's actually a lot easier to just use an array of DWORDs rather than even bothering with the MIDIEVENT structures.

For anyone else doing MIDI programming using the Windows API, beware that some of the MSDN documentation is misleading, inadequate or completely wrong.

The documentation for the MIDIEVENT structure says the following:

dwParms

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

This is ambiguous because it is not clear that "use" is intended to mean "include" rather than "specify".

Here are two other flaws in the documentation that programmers need to be aware of:

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.

When the header files are checked, the MEVT_F_ preprocessor definitions actually specify complete DWORDs rather than just the individual flags, so in my code in the question, the line specifying this member should have been as follows:

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

In addition to this, it has also turned out that the memory containing the MIDIHDR structure should be retained until the buffer has finished playing, so it should be allocated on the heap rather than the stack for most implementations.

Sam