(Moved from the relevant topic in Wishlist
http://www.autohotkey.com/forum/topic2831.html.. now in the correct sub forum)
I made a small library for integrating midi input to ahk scripts. It consists of a dll that uses a callback function to store the most recent value for each key velocity, cc, pitch wheel and channel aftertouch for every channel. To get midi input as windows messages you command the dll to send specific data only, and to specific message numbers. You can also directly ask any of the stored most recent values
I also wrote an ahk layer on top of the dll supposed to make it easier to use. It also creates a tray icon menu to select/change midi in device.
The dll file:
http://ihme.org/~orbik/midi4ahk/midi_in.dll
Dll source (as a vc++ project):
http://ihme.org/~orbik/midi4ahk/dll_source/
Dll function reference:
http://ihme.org/~orbik/midi4ahk/midi_in.readme.txt
midi_in_lib.ahk:
Code:
midi_in_Open(defaultDevID = -1)
{
global
if ((midi_in_hModule := DllCall("LoadLibrary", Str,A_ScriptDir . "\midi_in.dll")) == 0)
{
MsgBox Cannot load library midi_in.dll"
return 1
}
if (defaultDevID >= DllCall("midi_in.dll\getNumDevs"))
defaultDevID := -1
midi_in_MakeTrayMenu(defaultDevID)
if (defaultDevID >= 0)
midi_in_OpenDevice(defaultDevID)
return 0
}
midi_in_MakeTrayMenu(defaultDevID)
{
numDevs := DllCall("midi_in.dll\getNumDevs")
global midi_in_lastSelectedMenuItem
Menu devNameMenu, Add, No input, sub_menu_openinput
Menu devNameMenu, Add ; separator
if (defaultDevID < 0)
midi_in_lastSelectedMenuItem := "No Input"
loop %numDevs%
{
devID := A_Index-1
if ((devName := DllCall("midi_in.dll\getDevName", Int,devID, Str)) == 0)
{
MsgBox, Error in creating midi input device list
return 1
}
Menu devNameMenu, Add, %devName%, sub_menu_openinput
if (devID == defaultDevID)
{
Menu devNameMenu, Check, %devName%
midi_in_lastSelectedMenuItem := devName
}
}
Menu TRAY, Add, MIDI-in device, :devNameMenu
}
sub_menu_openinput:
midi_in_OpenDevice(A_ThisMenuItemPos-3)
; Move the check mark to new position
Menu %A_ThisMenu%, Check, %A_ThisMenuItem%
Menu %A_ThisMenu%, Uncheck, %midi_in_lastSelectedMenuItem%
midi_in_lastSelectedMenuItem := A_ThisMenuItem
return
midi_in_OpenDevice(deviceID) ;deviceID < 0 means no input
{
Critical
midi_in_Stop()
Gui +LastFound
hWnd := WinExist()
curDevID := DllCall("midi_in.dll\getCurDevID", Int)
if (deviceID == curDevID)
return 0
if (curDevID >= 0)
result := DllCall("midi_in.dll\close")
if (result)
{
MsgBox Error closing midi device`nmidi_in.dll\close returned %result%
return 1
}
if (deviceID < 0)
return 0
result := DllCall("midi_in.dll\open", UInt,hWnd, Int,deviceID, Int)
if (result)
{
MsgBox Error opening midi device`nmidi_in.dll\open(%hWnd%, %deviceID%) returned %result%
return 1
}
; MsgBox Press OK to start midi input
midi_in_Start()
return 0
}
midi_in_Close()
{
global
if (midi_in_hModule)
DllCall("FreeLibrary", UInt,midi_in_hModule), midi_in_hModule := ""
}
midi_in_Start()
{
DllCall("midi_in.dll\start")
}
midi_in_Stop()
{
DllCall("midi_in.dll\stop")
}
listenNote(noteNumber, funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenNote", Int,noteNumber, Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
listenNoteRange(rangeStart, rangeEnd, funcName, flags=0, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
msgCount := DllCall("midi_in.dll\listenNoteRange", int,rangeStart, int,rangeEnd, int,(flags & 0x07), int,channel, int,msgNum)
if (msgCount <= 0)
return
if (flags & 0x01)
loop %msgCount%
{
OnMessage(msgNum, funcName . A_Index)
GoSub, sub_increase_msgnum
}
else
OnMessage(msgNum, funcName)
}
listenCC(ccNumber, funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenCC", Int,ccNumber, Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
listenWheel(funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenWheel", Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
listenChanAT(funcName, channel=0)
{
global msgNum
GoSub, sub_increase_msgnum
DllCall("midi_in.dll\listenChanAT", Int,channel, Int,msgNum)
OnMessage(msgNum, funcName)
}
getNoteOn(noteNumber, channel)
{
return DllCall("midi_in.dll\getNoteOn", Int,noteNumber, Int,channel)
}
getCC(ccNumber, channel)
{
return DllCall("midi_in.dll\getCC", Int,ccNumber, Int,channel)
}
getWheel(channel)
{
return DllCall("midi_in.dll\getWheel", Int,channel)
}
getChanAT(channel)
{
return DllCall("midi_in.dll\getChanAT", Int,channel)
}
sub_increase_msgnum:
if msgNum
msgNum++
else
msgNum := 0x2000
return
And an example script to use the library:
Code:
SendMode Input
SetWorkingDir %A_ScriptDir%
OnExit, sub_exit
if (midi_in_Open(0))
ExitApp
;-------------------- Midi "hotkey" mappings -----------------------
listenNoteRange(48, 52, "playSomeSounds", 0x02)
return
;----------------------End of auto execute section--------------------
sub_exit:
midi_in_Close()
ExitApp
;-------------------------Miscellaneous hotkeys-----------------------
Esc::ExitApp
;-------------------------Midi "hotkey" functions---------------------
playSomeSounds(note, vel)
{
if (vel) ; vel == 0 means note off
{
SoundPlay drum%note%.wav
}
}
;------------------------- Midi input library ----------------------
#include midi_in_lib.ahk
All relevant files:
http://ihme.org/~orbik/midi4ahk/