Ich habe heute mal eben ein kleines Interface gebastelt, mit dem man
ganz einfach die MIDI-Funktionen aus der API benutzen kann.
Ein kleines Tastatur-Keyboard ist dabei. Halbtonleiter ist A, W, S, E, D, F,
T, G, Z, H, U, J, K. Bild hoch und runter für Lautstärke. ESC zum
Beenden. Cursor links und rechts zur Instrumentenauswahl. Cursor hoch
und runter zur Auswahl der Note auf Taste A. Leertaste zum Wechseln
zwischen Kanal 1 und 10 (Schlagzeug).
///Edit:
Hier noch als EXE-Datei für Nicht-PB-ler: Interface-Test.exe
Beim nächsten Update wird auch noch ein Callback für den MIDI-Input
dabei sein. Freut euch!

Code: Alles auswählen
Interface PB_MIDI
GetLastErrorText.s()
GetLastErrorNr.l()
Kill.l()
OpenOutputDevice.l(DeviceID.l)
CloseOutputDevice.l()
OpenInputDevice.l(DeviceID.l)
CloseInputDevice.l()
StartInput.l()
StopInput.l()
ResetInput.l()
ProgramChange.l(Channel.b, Voice.b)
NoteOn.l(Channel.b, Note.b, Velocity.b)
NoteOff.l(Channel.b, Note.b, Velocity.b)
NoteOffAlternate.l(Channel.b, Note.b)
AllNotesOff.l(Channel.b)
ChangeController.l(Channel.b, Controller.b, Value.b)
ChannelPressure.l(Channel.b, Value.b)
KeyAftertouch.l(Channe.b, Note.b, Value.b)
PitchWheel.l(Channel.b, Value.w)
EndInterface
Structure PB_MIDI_Struc
VTable.l
;Functions
fGetLastErrorText.l
fGetLastErrorNr.l
fKill.l
fOpenOutputDevice.l
fCloseOutputDevice.l
fOpenInputDevice.l
fCloseInputDevice.l
fStartInput.l
fStopInput.l
fResetInput.l
fProgramChange.l
fNoteOn.l
fNoteOff.l
fNoteOffAlternate.l
fAllNotesOff.l
fChangeController.l
fChannelPressure.l
fKeyAftertouch.l
fPitchWheel.l
;Data
OutDevice.l
InDevice.l
InCallback.l
hOutDevice.l
hInDevice.l
LastError.l
LastErrorFunc.l
EndStructure
Structure PB_MIDI_Msg
Channel.b
Note.b
Velocity.b
Null.b
EndStructure
#MIDIERR_BADOPENMODE = #MIDIERR_BASE + 6
Procedure.s PB_MIDI_GetLastErrorText(*PM.PB_MIDI_Struc)
Protected ErrorText.s
ErrorText = "Error: "
Select *PM\LastError
Case #MMSYSERR_NOERROR : ErrorText + "No Error"
Case #MIDIERR_NODEVICE : ErrorText + "No MIDI port was found. This error occurs only when the mapper is opened."
Case #MMSYSERR_ALLOCATED : ErrorText + "The specified resource is already allocated."
Case #MMSYSERR_BADDEVICEID : ErrorText + "The specified device identifier is out of range."
Case #MMSYSERR_INVALPARAM : ErrorText + "The specified pointer or structure is invalid."
Case #MMSYSERR_NOMEM : ErrorText + "The system is unable to allocate or lock memory."
Case #MMSYSERR_INVALHANDLE : ErrorText + "The specified device handle is invalid."
Case #MIDIERR_BADOPENMODE : ErrorText + "The application sent a message without a status byte to a stream handle."
Case #MIDIERR_NOTREADY : ErrorText + "The hardware is busy with other data."
Case #MIDIERR_STILLPLAYING : ErrorText + "Buffers are still in the queue."
Default : ErrorText + "Code " + Str(*PM\LastError)
EndSelect
ErrorText + #CRLF$ + "Function: "
Select *PM\LastErrorFunc
Case 0 : ErrorText + "No Function"
Case 1 : ErrorText + "OpenOutptDevice"
Case 2 : ErrorText + "OpenInputDevice"
Case 3 : ErrorText + "StartInput"
Case 4 : ErrorText + "StopInput"
Case 5 : ErrorText + "ResetInput"
Case 6 : ErrorText + "ProgramChange"
Case 7 : ErrorText + "NoteOn"
Case 8 : ErrorText + "NoteOff"
Case 9 : ErrorText + "NoteOffAlternate"
Case 10 : ErrorText + "AllNotesOff"
Case 11 : ErrorText + "ChangeController"
Case 12 : ErrorText + "ChannelPressure"
Case 13 : ErrorText + "KeyAftertouch"
Case 14 : ErrorText + "PitchWheel"
Case 15 : ErrorText + "CloseOutputDevice"
Case 16 : ErrorText + "CloseInputDevice"
Default : ErrorText + "Unknown"
EndSelect
*PM\LastError = #MMSYSERR_NOERROR
*PM\LastErrorFunc = 0
ProcedureReturn ErrorText
EndProcedure
Procedure PB_MIDI_GetLastErrorNr(*PM.PB_MIDI_Struc)
Protected Error.l
Error = *PM\LastError
*PM\LastError = 0
ProcedureReturn Error
EndProcedure
Procedure PB_MIDI_OpenOutputDevice(*PM.PB_MIDI_Struc, DeviceID.l)
Protected Error.l
Error = midiOutOpen_(@*PM\hOutDevice, DeviceID, 0, 0, 0)
If Error = #MMSYSERR_NOERROR
*PM\OutDevice = DeviceID
ProcedureReturn #True
Else
*PM\LastErrorFunc = 1
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_CloseOutputDevice(*PM.PB_MIDI_Struc)
Protected Error.l
Error = midiOutClose_(*PM\hOutDevice)
If Error = #MMSYSERR_NOERROR
*PM\OutDevice = 0
*PM\hOutDevice = 0
ProcedureReturn #True
Else
*PM\LastErrorFunc = 15
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_InCallback(hMidiIn.l, wMsg.l, *PM.PB_MIDI_Struc, dwMideMessage.l, dwTimeStamp.l)
EndProcedure
Procedure PB_MIDI_OpenInputDevice(*PM.PB_MIDI_Struc, DeviceID.l, Callback.l)
Protected Error.l
Error = midiInOpen_(@*PM\hInDevice, DeviceID, @PB_MIDI_InCallback(), *PM, #CALLBACK_FUNCTION)
If Error = #MMSYSERR_NOERROR
*PM\InDevice = DeviceID
*PM\InCallback = Callback
ProcedureReturn #True
Else
*PM\LastErrorFunc = 2
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_CloseInputDevice(*PM.PB_MIDI_Struc)
Protected Error.l
Error = midiInClose_(*PM\hInDevice)
If Error = #MMSYSERR_NOERROR
*PM\InDevice = 0
*PM\hInDevice = 0
*PM\InCallback = 0
ProcedureReturn #True
Else
*PM\LastErrorFunc = 16
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_StartInput(*PM.PB_MIDI_Struc)
Protected Error.l
Error = midiInStart_(*PM\hInDevice)
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastErrorFunc = 3
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_StopInput(*PM.PB_MIDI_Struc)
Protected Error.l
Error = midiInStop_(*PM\hInDevice)
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastErrorFunc = 4
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_ResetInput(*PM.PB_MIDI_Struc)
Protected Error.l
Error = midiInReset_(*PM\hInDevice)
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastErrorFunc = 5
*PM\LastError = Error
ProcedureReturn #False
EndIf
EndProcedure
;Channel: 0-15
;Voice: 0-127
;Note: 0-127
;Controller: 0-127
;Value: 0-127
;Value von PitchWheel: 0-32768 (?)
Procedure PB_MIDI_ProgramChange(*PM.PB_MIDI_Struc, Channel.b, Voice.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $C0 + Channel
Msg\Note = Voice
Error = midiOutShortMsg_(*PM\hOutDevice, PeekW(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 6
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_NoteOn(*PM.PB_MIDI_Struc, Channel.b, Note.b, Velocity.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $90 + Channel
Msg\Note = Note
Msg\Velocity = Velocity
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 7
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_NoteOff(*PM.PB_MIDI_Struc, Channel.b, Note.b, Velocity.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $80 + Channel
Msg\Note = Note
Msg\Velocity = Velocity
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 8
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_NoteOffAlternate(*PM.PB_MIDI_Struc, Channel.b, Note.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $90 + Channel
Msg\Note = Note
Msg\Velocity = 0
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 9
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_AllNotesOff(*PM.PB_MIDI_Struc, Channel.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $B0 + Channel
Msg\Note = $7B
Msg\Velocity = 0
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 10
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_ChangeController(*PM.PB_MIDI_Struc, Channel.b, Controller.b, Value.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $B0 + Channel
Msg\Note = Controller
Msg\Velocity = Value
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 11
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_ChannelPressure(*PM.PB_MIDI_Struc, Channel.b, Value.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $D0 + Channel
Msg\Note = Value
Msg\Velocity = 0
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 12
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_KeyAftertouch(*PM.PB_MIDI_Struc, Channel.b, Note.b, Value.b)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $A0 + Channel
Msg\Note = Note
Msg\Velocity = Value
Msg\Null = 0
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 12
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_PitchWheel(*PM.PB_MIDI_Struc, Channel.b, Value.w)
Protected Msg.PB_MIDI_Msg, Error.l
Msg\Channel = $E0 + Channel
Msg\Null = 0
PokeW(@Msg, Value)
Error = midiOutShortMsg_(*PM\hOutDevice, PeekL(@Msg))
If Error = #MMSYSERR_NOERROR
ProcedureReturn #True
Else
*PM\LastError = Error
*PM\LastErrorFunc = 12
ProcedureReturn #False
EndIf
EndProcedure
Procedure PB_MIDI_Kill(*PM.PB_MIDI_Struc)
While midiInClose_(*PM\hInDevice) = #MIDIERR_STILLPLAYING : Wend
While midiOutClose_(*PM\hOutDevice) = #MIDIERR_STILLPLAYING : Wend
FreeMemory(*PM)
ProcedureReturn #True
EndProcedure
Procedure PB_MIDI_Create()
Protected *PM.PB_MIDI_Struc
*PM = AllocateMemory(SizeOf(PB_MIDI_Struc))
If *PM = 0 : ProcedureReturn #False : EndIf
*PM\VTable = *PM + 4
*PM\fGetLastErrorText = @PB_MIDI_GetLastErrorText()
*PM\fGetLastErrorNr = @PB_MIDI_GetLastErrorNr()
*PM\fKill = @PB_MIDI_Kill()
*PM\fOpenOutputDevice = @PB_MIDI_OpenOutputDevice()
*PM\fOpenInputDevice = @PB_MIDI_OpenInputDevice()
*PM\fStartInput = @PB_MIDI_StartInput()
*PM\fStopInput = @PB_MIDI_StopInput()
*PM\fResetInput = @PB_MIDI_ResetInput()
*PM\fProgramChange = @PB_MIDI_ProgramChange()
*PM\fNoteOn = @PB_MIDI_NoteOn()
*PM\fNoteOff = @PB_MIDI_NoteOff()
*PM\fNoteOffAlternate = @PB_MIDI_NoteOffAlternate()
*PM\fAllNotesOff = @PB_MIDI_AllNotesOff()
*PM\fChangeController = @PB_MIDI_ChangeController()
*PM\fChannelPressure = @PB_MIDI_ChannelPressure()
*PM\fKeyAftertouch = @PB_MIDI_KeyAftertouch()
*PM\fPitchWheel = @PB_MIDI_PitchWheel()
ProcedureReturn *PM
EndProcedure
Procedure MIDIRequester(*OutDevice.l, *InDevice.l)
Protected WinID.l
Protected List1.l, List2.l, But1.l, But2.l, Txt1.l, Txt2.l, Txt3.l, Txt4.l
Protected MaxOutDev.l, InfoOut.MIDIOUTCAPS, InDev.l, OutDev.l, Quit.l, Ok.l, EventID.l, a.l
Protected Width.l, Column.l, Offset.l
#MOD_WAVETABLE = 6
#MOD_SWSYNTH = 7
#MIDIRequ_InSet = 2
#MIDIRequ_OutSet = 1
Width = 400
WinID = OpenWindow(#PB_Any, 0, 0, Width, 270, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "MIDI-Requester")
If WinID
If CreateGadgetList(WindowID(WinID))
Column = (Width - 20) / 2
Offset = (Width / 2) + 5
TextGadget(#PB_Any, 5, 5, Column, 18, "Output-Device:", #PB_Text_Center | #PB_Text_Border)
List1 = ListViewGadget(#PB_Any, 5, 23, Column, 100)
MaxOutDev = midiOutGetNumDevs_()
If MaxOutDev
For a = -1 To MaxOutDev - 1
midiOutGetDevCaps_(a, InfoOut, SizeOf(MIDIOUTCAPS))
AddGadgetItem(List1, -1, PeekS(@InfoOut\szPname[0], 32))
Next
Else
AddGadgetItem(List1, -1, "(no output device)")
DisableGadget(List1, 1)
EndIf
If *OutDevice = 0 : DisableGadget(List1, 1) : EndIf
TextGadget(#PB_Any, Offset, 5, Column, 18, "Input-Device:", #PB_Text_Center | #PB_Text_Border)
List2 = ListViewGadget(#PB_Any, Offset, 23, Column, 100)
MaxInDev.l = midiInGetNumDevs_()
InfoIn.MIDIINCAPS
If MaxInDev
For a = 0 To MaxInDev - 1
midiInGetDevCaps_(a, InfoIn, SizeOf(MIDIINCAPS))
AddGadgetItem(List2, -1, PeekS(@InfoIn\szPname[0], 32))
Next
Else
AddGadgetItem(List2, -1, "(no input device)")
DisableGadget(List2, 1)
EndIf
If *InDevice = 0 : DisableGadget(List2, 1) : EndIf
But1 = ButtonGadget(#PB_Any, 5, 240, Column, 24, "&OK")
But2 = ButtonGadget(#PB_Any, Offset, 240, Column, 24, "&Cancel")
Frame3DGadget(#PB_Any, 5, 130, Width - 10, 100, "Info of Output-Device", 0)
Txt1 = TextGadget(#PB_Any, 10, 145, Width - 20, 18, "Version:")
Txt2 = TextGadget(#PB_Any, 10, 165, Width - 20, 18, "Technology:")
Txt3 = TextGadget(#PB_Any, 10, 185, Width - 20, 18, "Max. Voices:")
Txt4 = TextGadget(#PB_Any, 10, 205, Width - 20, 18, "Polyphonie:")
OutDev = 0
InDev = 0
Quit = #False
Ok = #False
Repeat
If GetGadgetState(List1) > -1 Or GetGadgetState(List2) > -1
DisableGadget(But1, 0)
Else
DisableGadget(But1, 1)
EndIf
If InDev <> GetGadgetState(List2)
InDev = GetGadgetState(List2)
EndIf
If GetGadgetState(List1) <> OutDev
OutDev = GetGadgetState(List1)
midiOutGetDevCaps_(OutDev - 1, InfoOut, SizeOf(MIDIOUTCAPS))
SetGadgetText(Txt1, "Version: " + Str(InfoOut\vDriverVersion >> 8) + "." + Str(InfoOut\vDriverVersion & FF))
Select InfoOut\wTechnology
Case #MOD_MIDIPORT : TmpS.s = "Hardware Port"
Case #MOD_SYNTH : TmpS.s = "Synthesizer"
Case #MOD_SQSYNTH : TmpS.s = "Square Wave Synthesizer"
Case #MOD_FMSYNTH : TmpS.s = "FM Synthesizer"
Case #MOD_MAPPER : TmpS.s = "Microsoft MIDI Mapper"
Case #MOD_WAVETABLE : TmpS.s = "Hardware Wavetable Synthesizer"
Case #MOD_SWSYNTH : TmpS.s = "Software Synthesizer"
Default: TmpS.s = "(Error Code " + Str(InfoOut\wTechnology) + ")"
EndSelect
SetGadgetText(Txt2, "Technology: " + TmpS)
If InfoOut\wVoices = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wVoices) : EndIf
SetGadgetText(Txt3, "Max. Voices: " + TmpS)
If InfoOut\wNotes = 0 : TmpS.s = "inf" : Else : TmpS.s = Str(InfoOut\wNotes) : EndIf
SetGadgetText(Txt4, "Polyphonie: " + TmpS)
EndIf
EventID = WaitWindowEvent()
Select EventID
Case #PB_EventCloseWindow
Quit = #True
Ok = #False
Case #PB_EventGadget
Select EventGadgetID()
Case But1
If *OutDevice : PokeL(*OutDevice, OutDev - 1) : EndIf
If *InDevice : PokeL(*InDevice, InDev) : EndIf
Quit = #True
Ok = 3
If (OutDev = -1 Or CountGadgetItems(List1) = 0) And Ok & #MIDIRequ_OutSet : Ok ! #MIDIRequ_OutSet : EndIf
If (InDev = -1 Or CountGadgetItems(List2) = 0) And Ok & #MIDIRequ_InSet : Ok ! #MIDIRequ_InSet : EndIf
Case But2
Quit = #True
Ok = #False
EndSelect
EndSelect
Until Quit
CloseWindow(WinID)
ProcedureReturn Ok
EndIf
EndIf
ProcedureReturn #False
EndProcedure
OutDevice.l
MIDIResult.l = MIDIRequester(@OutDevice, 0)
If MIDIResult & #MIDIRequ_OutSet = 0 : End : EndIf
*midi.PB_MIDI = PB_MIDI_Create()
*midi\OpenOutputDevice(OutDevice)
Voice.l = 0
Channel.l = 0
Vol.l = 127
NoteOffset.l = 36
Dim Note.l(127)
Win_Key.l = OpenWindow(#PB_Any, 0, 0, 100, 90, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "Keyboard")
If Win_Key
If CreateGadgetList(WindowID(Win_Key))
Txt1.l = TextGadget(#PB_Any, 0, 0, 100, 18, "Beenden mit ESC", #PB_Text_Center)
Txt2.l = TextGadget(#PB_Any, 0, 18, 100, 18, "Instrument: " + Str(Voice + 1), #PB_Text_Center)
Txt3.l = TextGadget(#PB_Any, 0, 36, 100, 18, "Ton: " + Str(NoteOffset), #PB_Text_Center)
Txt4.l = TextGadget(#PB_Any, 0, 54, 100, 18, "Kanal: " + Str(Channel + 1), #PB_Text_Center)
Txt5.l = TextGadget(#PB_Any, 0, 72, 100, 18, "Lautstärke: " + Str(Vol), #PB_Text_Center)
EndIf
Repeat
Select WaitWindowEvent()
Case #WM_KEYDOWN
Select EventwParam()
Case #VK_ESCAPE : Break
Case #VK_SPACE
If Channel = 0 : Channel = 9 : Else : Channel = 0 : EndIf
SetGadgetText(Txt4, "Kanal: " + Str(Channel + 1))
Case #VK_PRIOR
If Vol < 127 : Vol + 1 : EndIf
SetGadgetText(Txt5, "Lautstärke: " + Str(Vol))
Case #VK_NEXT
If Vol > 0 : Vol - 1 : EndIf
SetGadgetText(Txt5, "Lautstärke: " + Str(Vol))
Case #VK_RIGHT
If Voice < 127 : Voice + 1 : EndIf
*midi\ProgramChange(0, Voice)
SetGadgetText(Txt2, "Instrument: " + Str(Voice + 1))
Case #VK_LEFT
If Voice > 0 : Voice - 1 : EndIf
*midi\ProgramChange(0, Voice)
SetGadgetText(Txt2, "Instrument: " + Str(Voice + 1))
Case #VK_UP
If NoteOffset < 115 : NoteOffset + 1 : EndIf
SetGadgetText(Txt3, "Ton: " + Str(NoteOffset))
Case #VK_DOWN
If NoteOffset > 0 : NoteOffset - 1 : EndIf
SetGadgetText(Txt3, "Ton: " + Str(NoteOffset))
Case #VK_A : If Note(NoteOffset + 0) = 0 : *midi\NoteOn(Channel, NoteOffset + 0, Vol) : Note(NoteOffset + 0) = 1 : EndIf
Case #VK_W : If Note(NoteOffset + 1) = 0 : *midi\NoteOn(Channel, NoteOffset + 1, Vol) : Note(NoteOffset + 1) = 1 : EndIf
Case #VK_S : If Note(NoteOffset + 2) = 0 : *midi\NoteOn(Channel, NoteOffset + 2, Vol) : Note(NoteOffset + 2) = 1 : EndIf
Case #VK_E : If Note(NoteOffset + 3) = 0 : *midi\NoteOn(Channel, NoteOffset + 3, Vol) : Note(NoteOffset + 3) = 1 : EndIf
Case #VK_D : If Note(NoteOffset + 4) = 0 : *midi\NoteOn(Channel, NoteOffset + 4, Vol) : Note(NoteOffset + 4) = 1 : EndIf
Case #VK_F : If Note(NoteOffset + 5) = 0 : *midi\NoteOn(Channel, NoteOffset + 5, Vol) : Note(NoteOffset + 5) = 1 : EndIf
Case #VK_T : If Note(NoteOffset + 6) = 0 : *midi\NoteOn(Channel, NoteOffset + 6, Vol) : Note(NoteOffset + 6) = 1 : EndIf
Case #VK_G : If Note(NoteOffset + 7) = 0 : *midi\NoteOn(Channel, NoteOffset + 7, Vol) : Note(NoteOffset + 7) = 1 : EndIf
Case #VK_Z : If Note(NoteOffset + 8) = 0 : *midi\NoteOn(Channel, NoteOffset + 8, Vol) : Note(NoteOffset + 8) = 1 : EndIf
Case #VK_H : If Note(NoteOffset + 9) = 0 : *midi\NoteOn(Channel, NoteOffset + 9, Vol) : Note(NoteOffset + 9) = 1 : EndIf
Case #VK_U : If Note(NoteOffset + 10) = 0 : *midi\NoteOn(Channel, NoteOffset + 10, Vol) : Note(NoteOffset + 10) = 1 : EndIf
Case #VK_J : If Note(NoteOffset + 11) = 0 : *midi\NoteOn(Channel, NoteOffset + 11, Vol) : Note(NoteOffset + 11) = 1 : EndIf
Case #VK_K : If Note(NoteOffset + 12) = 0 : *midi\NoteOn(Channel, NoteOffset + 12, Vol) : Note(NoteOffset + 12) = 1 : EndIf
EndSelect
Case #WM_KEYUP
Select EventwParam()
Case #VK_A : If Note(NoteOffset + 0) : *midi\NoteOff(Channel, NoteOffset + 0, 0) : Note(NoteOffset + 0) = 0 : EndIf
Case #VK_W : If Note(NoteOffset + 1) : *midi\NoteOff(Channel, NoteOffset + 1, 0) : Note(NoteOffset + 1) = 0 : EndIf
Case #VK_S : If Note(NoteOffset + 2) : *midi\NoteOff(Channel, NoteOffset + 2, 0) : Note(NoteOffset + 2) = 0 : EndIf
Case #VK_E : If Note(NoteOffset + 3) : *midi\NoteOff(Channel, NoteOffset + 3, 0) : Note(NoteOffset + 3) = 0 : EndIf
Case #VK_D : If Note(NoteOffset + 4) : *midi\NoteOff(Channel, NoteOffset + 4, 0) : Note(NoteOffset + 4) = 0 : EndIf
Case #VK_F : If Note(NoteOffset + 5) : *midi\NoteOff(Channel, NoteOffset + 5, 0) : Note(NoteOffset + 5) = 0 : EndIf
Case #VK_T : If Note(NoteOffset + 6) : *midi\NoteOff(Channel, NoteOffset + 6, 0) : Note(NoteOffset + 6) = 0 : EndIf
Case #VK_G : If Note(NoteOffset + 7) : *midi\NoteOff(Channel, NoteOffset + 7, 0) : Note(NoteOffset + 7) = 0 : EndIf
Case #VK_Z : If Note(NoteOffset + 8) : *midi\NoteOff(Channel, NoteOffset + 8, 0) : Note(NoteOffset + 8) = 0 : EndIf
Case #VK_H : If Note(NoteOffset + 9) : *midi\NoteOff(Channel, NoteOffset + 9, 0) : Note(NoteOffset + 9) = 0 : EndIf
Case #VK_U : If Note(NoteOffset + 10) : *midi\NoteOff(Channel, NoteOffset + 10, 0) : Note(NoteOffset + 10) = 0 : EndIf
Case #VK_J : If Note(NoteOffset + 11) : *midi\NoteOff(Channel, NoteOffset + 11, 0) : Note(NoteOffset + 11) = 0 : EndIf
Case #VK_K : If Note(NoteOffset + 12) : *midi\NoteOff(Channel, NoteOffset + 12, 0) : Note(NoteOffset + 12) = 0 : EndIf
EndSelect
EndSelect
ForEver
EndIf
*midi\Kill()