A clientside binary LUA module for Garry's Mod that allows you to read events from a MIDI device.
This is a modified version based on original gmcl_midi module.
Rename the module binary according to the Garry's Mod binary LUA module naming convention (see Garry's Mod Wiki).
When building for Windows, module should be named gmcl_midi_win32.dll
for 32-bit versions or gmcl_midi_win64.dll
for 64-bit ones.
When building for Linux or Mac OS X, the name would be either one of gmcl_midi_linux.dll
, gmcl_midi_linux64.dll
or gmcl_midi_osx.dll
.
Place the renamed file in the following folder:
steamapps/common/GarrysMod/garrysmod/lua/bin
NOTE: It's possible that there's no bin
folder in garrysmod/lua
. In that case you can just create it.
If you're using this for an existing addon, feel free to stop reading here since this only applies to developers.
- Require the module with
require "midi"
. - Figure out which devices you can connect to with
midi.GetPorts()
. - Open a connection to your midi device using
midi.Open(portNumber)
. By default it will try to open port 0. An error is thrown if there are no devices. - Add a listener to the
GM:MIDI
hook. This is where all the events come in. - In the listener, filter the events you want to listen to and perform actions based on these events.
Taking a quick glance at the MIDI protocol will make understanding this API a lot easier.
Called when a MIDI event occurs (when a key is pressed, released, when the pitch bend changes, etc). This hook will start working immediately after a port has been opened (see midi.Open(port)
)
time
: The exact SysTime at which the MIDI event occurred. This is useful when you want to know exactly when a note was played. Note: this is independent of FPScommand
: The command code of the event. This number contains BOTH the command code (first four bits of the number) AND the channel to which the command applies (last four bits of the number). These two can be separated with themidi.GetCommandCode(command)
(returns just the command code) andmidi.GetCommandChannel(command)
. To get a human readable name of the command code, you can runmidi.GetCommandName(command)
.par1
: Many commands have one or more parameters. The command code144
(named"NOTE_ON"
) has two parameters: the number of the key pressed and the velocity (how hard it was pressed)....
: other parameters
The average computer has more than one USB port. This makes it possible to connect multiple MIDI devices. Only one of these devices can be listened to at once. This function returns a table with a device's port
as index and the device's name as value.
lua_run_cl show(midi.GetPorts())
>{[0]: "USB MIDI 0"}
Open a connection with a MIDI device. Possible values for port
are the keys of the table returned by midi.GetPorts()
. By default port 0 is tried.
The
"MIDI"
hook will not be called until a port has been opened!
An error will be thrown if there are no MIDI devices available.
Only one port can be opened at once. The first port will be closed when connecting to a second port.
Returns whether the module is connected to a device.
Close the connection if it exists. No MIDI events will be received after this function has been called until of course midi.Open(port)
is called.
Note: Connections don't have to be closed. Changing level without closing a connection is fine. Only close the connection when you're the only user of the MIDI hook. Otherwise you'll mess up other scripts.
Helper function for the command (second) parameter of the function called by the "MIDI"
hook. As explained in the the MIDI protocol, the command code exists of 4 bits indicating the command code and 4 bits indicating the channel to which the command applies. The midi.GetCommandCode(command)
extracts the command code. (Basically it returns command & 0xF0
).
Whereas the midi.GetCommandCode(command)
returns the command code, the midi.GetCommandChannel(command)
function returns the channel to which the command applies. Possible channels are 0 <= channel < 16
.
This function takes a command (as given in the second parameter of a function attached to the "MIDI"
hook) and returns a human readable name.
] print(midi.GetCommandName(0x80))
NOTE_OFF
0x80 - "NOTE_OFF"
0x90 - "NOTE_ON"
0xA0 - "AFTERTOUCH"
0xB0 - "CONTINUOUS_CONTROLLER"
0xC0 - "PATCH_CHANGE"
0xD0 - "CHANNEL_PRESSURE"
0xE0 - "PITCH_BEND"
0xF0 - "SYSEX"
See the examples folder.