AutoHotkey and MIDI

I’ve been toying with AutoHotkey and MIDI a bit lately and thought I would share my findings in case anyone else finds it interesting.
I’ve cobbled together a very simple “library” file that can be used to:

  • Return all available MIDI input as well as output ports
  • Open and Close MIDI input and output ports
  • Send Note On and Note Off messages
  • Send Continuous Controller messages (MIDI CC)
  • Receive the following MIDI messages:
    • Note On
    • Note Off
    • Aftertouch
    • CC
    • Program change
    • Channel pressure
    • Pitchbend
    • SysEx (!)

Below is an example of how to use it.

#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
setbatchlines -1	; Never sleep
#SingleInstance force
#Persistent
#include %A_ScriptDir%\MIDI.ahk	;Path to the library

;SET UP ---------------------------------------
MIDI_IN_CHANNEL_FILTER := 0	; MIDI channel 1
MIDI_OUT_CH := 1	; MIDI channel 2

; Get all MIDI ports
midiInDevices := getMidiInDevices()
midiOutDevices := getMidiOutDevices()

; Display all MIDI ports
for index, device in midiInDevices
{
	portName := index-1 . ": " . device
	strInPorts .= portName . "`n"
}
for index, device in midiOutDevices
{
	strOutPorts .= index-1 . ": " . device . "`n"
}
MsgBox, % "MIDI In`n" strInPorts "`nMIDI Out`n" strOutPorts

; Open MIDI In
midiInDeviceId := 4
openMidiIn(midiInDeviceId)

; Open MIDI Out
midiOutDeviceId := 5
openMidiOut(midiOutDeviceId)
return


; MIDI OUT ------------------------------------
F10::
MIDI_NoteOn(1, 100)
KeyWait, F10	;Prevents key repeat
return

F10 Up::
MIDI_NoteOff(1)
return

F11::
MIDI_CC(21, 55)
return

F12::
MIDI_CC(50, 64)
return

; MIDI IN -------------------------------------
MidiControlChange:
MsgBox, % "CC#" midiEvent.controller ", value=" midiEvent.value
return

MidiControlChange62:
MsgBox, % "I received MIDI CC 62`nwith a value of " midiEvent.value
return

MidiNoteOn:
MsgBox, % "Note#" midiEvent.noteNumber ", velocity=" midiEvent.velocity
return

MidiNoteOff60:
MsgBox, % "Note Off. Note #60`nNote Off velocity=" midiEvent.velocity
return

MidiSysEx:
Msg :=
raw :=
loopMax := SysexMessage.MaxIndex() - 2
raw := SysexMessage[1] . " "
Loop, %loopMax%
{
	raw .= SysexMessage[A_Index+1] . " "
	dec := Format("{:i}", "0x" SysexMessage[A_Index+1])
	ansi := Chr(dec)
	Msg .= ansi
	OutputDebug, % "A_Index=" . A_Index . ", element=" . SysexMessage[A_Index+1]
}
raw .= SysexMessage[SysexMessage.MaxIndex()]
MsgBox, % "SysEx`n`nRaw hex:`n" . raw . "`n`nASCII:`n" . Msg
return

What can you use this for?

Easily convert keyboard and mouse actions into MIDI.
Turn a joystick or game controller into a MIDI controller. (Not tested, but shouldn’t be hard to accomplish.)
Interface with MIDI Remote in new interesting ways, such as building on-screen soft keys for Cubase functions with feedback.
Display parameter values from your MIDI controller that lacks a value read-out, or a VST parameter your screenless MIDI Controller is controlling via MIDI Remote.
Probably more fun things that I can’t think of right now.

Caveats

This has been tested with AutoHotkey v1 only.

I have been using this with a virtual MIDI port (loopMIDI) and noticed that MIDI data sent would echo back to the input port. My simple solution to this is to use different MIDI Channels for input and output and neglect data that are not received on the specified channel. MIDI_IN_CHANNEL_FILTER is used for this as shown in the example above. I did not observe this behavior when using physical MIDI ports.

I have put together this for my own personal use and the code is presented “as is”. I do not guarantee that it will work for you.
I am unlikely to provide extensive support.
I am unlikely to implement additional features. AutoHotkey has a large user base and is very well documented. Any additional functions or features you might be able to dream up is probably better implemented by someone else anyway.

AHK MIDI.zip (2.9 KB)

4 Likes

Hi there, I have some knobs on my mechanical keyboard. How can I use this script to use those knobs as MIDI controllers so that I can assign these knobs to control the gain of my tracks in Cubase (for example)? I tried running the script but kept getting different error messages (I don’t have any knowledge of scripting). Any help would be appreciated!

Hey thanks for this! I have been needing to bind some keys to midi in order to control some plugins for a while, and your example probably saved me a few hours of messing around with a different AHK midi class library. Yours worked like a charm. Cheers!

1 Like

I’m glad you found it useful.
Out of curiosity and perhaps as inspiration to others, would you mind sharing your use case?

I use the ADPTR Metric A/B Plugin, which has a switch for a/bing your mix against reference mixes. I wanted to be able to trigger the A/B switch using my keyboard, and not have to reach for an external midi device. So the autohotkey script allows me to send midi to cubase from a key binding (using loopMIDI) which then is translated by a generic remote to map to the plugin.
Honestly it’s kind of silly that all of these hacky steps are required to do something very simple, but that said, in other DAWS this sort of setup may not even be possible.

1 Like

I have made some tweaks to the library that improves handling incoming SysEx messages as well as a more reliable way of closing MIDI In ports.

Updated version:
AHK MIDI.zip (3.0 KB)