MIDI Programming in .NET

Here’s the code I use in the Sends on Fader Application to Read and Write MIDI From/To the Yamaha consoles. Should work for any MIDI messages.

Module MidiFunctions
	' MIDI input device capabilities structure
	<StructLayout(LayoutKind.Sequential)> _
	Public Structure MIDIINCAPS
 		Dim wMid As Short 					' Manufacturer ID
 		Dim wPid As Short 					' Product ID
 		Dim vDriverVersion As Integer 				' Driver version
 		<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
		Dim szPname As String 					' Product Name
 		Dim dwSupport As Integer 				' Supported extras
	End Structure
	 
	' MIDI output device capabilities structure
	<StructLayout(LayoutKind.Sequential)> _
	Public Structure MIDIOUTCAPS
 		Dim wMid As Short					' Manufacturer ID
 		Dim wPid As Short      					' Product ID
 		Dim vDriverVersion As Integer      			' Driver version
 		<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> _
		Dim szPname As String					' Product Name
 		Dim wTechnology As Short      				' Device type
 		Dim wVoices As Short      				' n. of voices (internal synth only)
 		Dim wNotes As Short     				' max n. of notes (internal synth only)
 		Dim wChannelMask As Short     				' n. of Midi channels (internal synth only)
		Dim dwSupport As Integer     				' Supported extra controllers (volume, etc)
	End Structure
 
	' MIDI data block header
	<StructLayout(LayoutKind.Sequential)> _
	Public Structure MIDIHDR
 		Dim lpData As IntPtr      	' pointer to locked data block
 		Dim dwBufferLength As Integer	' length of data in data block
 		Dim dwBytesRecorded As Integer	' used for input only
 		Dim dwUser As Integer      	' for client's use
 		Dim dwFlags As Integer      	' assorted flags (see defines)
 		Dim lpNext As Integer      	' reserved for driver
 		Dim reserved As Integer      	' reserved for driver
 		Dim dwOffset As Integer
 		Dim reserved1 As Integer
 		Dim reserved2 As Integer
 		Dim reserved3 As Integer
 		Dim reserved4 As Integer
	End Structure
 
	'Input functions
	Declare Function midiInGetNumDevs Lib "winmm.dll" () As Short
	Declare Function midiInGetDevCaps Lib "winmm.dll" Alias "midiInGetDevCapsA" (ByVal uDeviceID As Integer, ByRef lpCaps As MIDIINCAPS, ByVal uSize As Integer) As Integer
	Declare Function midiInGetErrorText Lib "winmm.dll" Alias "midiInGetErrorTextA" (ByVal err_Renamed As Integer, ByVal lpText As String, ByVal uSize As Integer) As Integer
	Declare Function midiInOpen Lib "winmm.dll" (ByRef lphMidiIn As Integer, ByVal uDeviceID As Integer, ByVal dwCallback As MidiDelegate, _
		ByVal dwInstance As Integer, ByVal dwFlags As Integer) As Integer
	Declare Function midiInClose Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
	Declare Function midiInPrepareHeader Lib "winmm.dll" (ByVal hMidiIN As Integer, ByRef lpMidiInHdr As MIDIHDR, ByVal uSize As Integer) As Integer
	Declare Function midiInUnprepareHeader Lib "winmm.dll" (ByVal hMidiIN As Integer, ByRef lpMidiInHdr As MIDIHDR, ByVal uSize As Integer) As Integer
	Declare Function midiInAddBuffer Lib "winmm.dll" (ByVal hMidiIN As Integer, ByRef lpMidiInHdr As MIDIHDR, ByVal uSize As Integer) As Integer
	Declare Function midiInReset Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
	Declare Function midiInStart Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
	Declare Function midiInStop Lib "winmm.dll" (ByVal hMidiIN As Integer) As Integer
 
	'Output functions
	Declare Function midiOutGetNumDevs Lib "winmm.dll" () As Short
	Declare Function midiOutGetDevCaps Lib "winmm.dll" Alias "midiOutGetDevCapsA" (ByVal uDeviceID As Integer, ByRef lpCaps As MIDIOUTCAPS, ByVal uSize As Integer) As Integer
	Declare Function midiOutGetErrorText Lib "winmm.dll" Alias "midiOutGetErrorTextA" (ByVal errcode As Integer, ByVal lpText As String, ByVal uSize As Integer) As Integer
	Declare Function midiOutOpen Lib "winmm.dll" (ByRef lphMidiOut As Integer, ByVal uDeviceID As Integer, ByVal dwCallback As Integer, _
		ByVal dwInstance As Integer, ByVal dwFlags As Integer) As Integer
	Declare Function midiOutClose Lib "winmm.dll" (ByVal hMidiOut As Integer) As Integer
	Declare Function midiOutPrepareHeader Lib "winmm.dll" (ByVal hMidiOut As Integer, ByRef lpMidiOutHdr As MIDIHDR, ByVal uSize As Integer) As Integer
	Declare Function midiOutUnprepareHeader Lib "winmm.dll" (ByVal hMidiOut As Integer, ByRef lpMidiOutHdr As MIDIHDR, ByVal uSize As Integer) As Integer
	Declare Function midiOutShortMsg Lib "winmm.dll" (ByVal hMidiOut As Integer, ByVal dwMsg As Integer) As Integer
	Declare Function midiOutLongMsg Lib "winmm.dll" (ByVal hMidiOut As Integer, ByRef lpMidiOutHdr As MIDIHDR, ByVal uSize As Integer) As Integer
	Public Delegate Sub MidiDelegate(ByVal MidiHandle As Int32, ByVal wMsg As Int32, ByVal Instance As Int32, ByVal wParam As Int32, ByVal lParam As Int32)
 
	' Callback Function constants
	Public Const CALLBACK_FUNCTION As Integer = &H30000	' dwCallback is a FARPROC
	Public Const MIM_OPEN As Short = &H3C1S      		' MIDI In Port Opened
	Public Const MIM_CLOSE As Short = &H3C2S      		' MIDI In Port Closed
	Public Const MIM_DATA As Short = &H3C3S      		' MIDI In Short Data (e.g. Notes & CC)
	Public Const MIM_LONGDATA As Short = &H3C4S      	' MIDI In Long Data (i.e. SYSEX)
	Public Const MIM_ERROR As Short = &H3C5S      		' MIDI In Error
	Public Const MIM_LONGERROR As Short = &H3C6S      	' MIDI In Long Error
	Public Const MIM_MOREDATA As Short = &H3CCS      	' MIDI Header Buffer is Full
	Public Const MOM_OPEN As Short = &H3C7S      		' MIDI Out Port Opened
	Public Const MOM_CLOSE As Short = &H3C8S      		' MIDI Out Port Closed
	Public Const MOM_DONE As Short = &H3C9S      		' MIDI Out Data sending completed
	Public Const MOM_POSITIONCB As Short = &HCAS      	' MIDI Out Position requested
 
	' Midi Error Constants
	Public Const MMSYSERR_NOERROR As Short = 0
	Public Const MMSYSERR_ERROR As Short = 1
	Public Const MMSYSERR_BADDEVICEID As Short = 2
	Public Const MMSYSERR_NOTENABLED As Short = 3
	Public Const MMSYSERR_ALLOCATED As Short = 4
	Public Const MMSYSERR_INVALHANDLE As Short = 5
	Public Const MMSYSERR_NODRIVER As Short = 6
	Public Const MMSYSERR_NOMEM As Short = 7
	Public Const MMSYSERR_NOTSUPPORTED As Short = 8
	Public Const MMSYSERR_BADERRNUM As Short = 9
	Public Const MMSYSERR_INVALFLAG As Short = 10
	Public Const MMSYSERR_INVALPARAM As Short = 11
	Public Const MMSYSERR_HANDLEBUSY As Short = 12
	Public Const MMSYSERR_INVALIDALIAS As Short = 13
	Public Const MMSYSERR_BADDB As Short = 14
	Public Const MMSYSERR_KEYNOTFOUND As Short = 15
	Public Const MMSYSERR_READERROR As Short = 16
	Public Const MMSYSERR_WRITEERROR As Short = 17
	Public Const MMSYSERR_DELETEERROR As Short = 18
	Public Const MMSYSERR_VALNOTFOUND As Short = 19
	Public Const MMSYSERR_NODRIVERCB As Short = 20
	Public Const MMSYSERR_LASTERROR As Short = 20
	Public Const MIDIERR_UNPREPARED As Short = 64 	' header not prepared
	Public Const MIDIERR_STILLPLAYING As Short = 65 ' still something playing
	Public Const MIDIERR_NOMAP As Short = 66 	' no current map
	Public Const MIDIERR_NOTREADY As Short = 67 	' hardware is still busy
	Public Const MIDIERR_NODEVICE As Short = 68 	' port no longer connected
	Public Const MIDIERR_INVALIDSETUP As Short = 69 ' invalid setup
	Public Const MIDIERR_LASTERROR As Short = 69 	' last error in range

	' Midi Header flags
	Public Const MHDR_DONE As Short = 1 	' Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.
	Public Const MHDR_PREPARED As Short = 2 ' Set by Windows to indicate that the buffer has been prepared
	Public Const MHDR_INQUEUE As Short = 4 	' Set by Windows to indicate that the buffer is queued for playback
	Public Const MHDR_ISSTRM As Short = 8 	' Set to indicate that the buffer is a stream buffer
EndModule