//server/stuff/MIDI programming>
Main

MIDI programming

MIDI device initialization
    #include <windows.h>
    #include <mmsystem.h>
    #pragma comment(lib, "winmm.lib")

    HMIDIOUT device;
    int midiport = 0;
    int flag = midiOutOpen(&device, midiport, 0, 0, CALLBACK_NULL);
    if (flag != MMSYSERR_NOERROR)
    {
        cout << "Error opening MIDI Output" << endl;
        return 0;
    }

MIDI device destruction
    midiOutReset(device);
    midiOutClose(device);

Bytes sent to a MIDI controller range between 0 and 255 (unsigned char). The difference between a MIDI command and data is the most significant bit of the btye. Zero signifies data, one signifies command. Thus, data is sent in the range from 0 to 127 and commands are sent in the range 128 to 255.

Command bytes are split into half. The most significant half contains the actual command and the second contains the MIDI channel it is targetted at. Example, 0x90 is the note on for the first MIDI channel, 0x91 for the second and so on.

MIDI commands: Note that 0x80 in hex is 128 in decimal. 0x80 to 0xE0 are directed at channels as the second four bits (0x0n where n is [0:F]) specify the channel to target. 0xF0 to 0xFF are not directed at any channel, they are system messages.

A MIDI command along with its associated MIDI data is a MIDI message. The minimium size is 1 byte (A command byte, which is always required, but with no parameters) and the maximium is 3 bytes. (A command byte with 2 parameters).

Commands and their parameters As far as I have experimented, the third databyte is always zero, so the message itself only consists of thre.e significant bytes (cmd, p1, p2).
enum MIDICommand : unsigned char
{
	MIDI_StartNote = 0x90,
	MIDI_StopNote = 0x80,
	MIDI_ChangePatch = 0xC0,
};

int MIDICommand(MIDICommand cmd, char p1 = 0, char p2 = 0, char p3 = 0)
{
    union
	{
		unsigned long word;
		unsigned char data[4];
	}
	message;

    message.data[0] = cmd;
    message.data[1] = p1;
    message.data[2] = p2;
    message.data[3] = p3;
    return midiOutShortMsg(MIDIdevice, message.word);
}
The command exists in the upper half of the byte range, so its type is unsigned char. The parameters only exist in the lower half of the byte range, so I've left them signed chars in the function prototype as MIDI devices will ignore any parameters over 0x7F (127). This is different in the case of pitch bend and other commands which use the HSB and LSB of the whole message.

For example, Middle C may be played by
SendMIDICommand(MIDI_StartNote, 60, 0x7F);
But if you do not send a MIDI stop note before the next note is played, the falloff from this note may last a while. To do that,
SendMIDICommand(MIDI_StopNote, 60, 0x7F);