MidiHID Configurations
What Are MidiHID Configurations?
MidiHID configurations describe how to translate the events sent by a given HID compatible USB device into MIDI messages.

The configuration files are located in "~/Library/Application Support/MidiHID Configurations", and contain the following information:

  • A unique identifier describing the target USB device
  • A few parameters on how the configuration should be used
  • A Lua script (more information below) that gets executed whenever an event is received from this USB device to convert it into a MIDI message
You should have no reason to manipulate or edit configuration files in this directory, as this can be done directly from the MidiHID user interface.
 
Finding and Installing New Configurations
To install new configurations, simply drop the corresponding files into the configuration list of the MidiHID window.

You can find and dowload new configurations for USB devices in the Community Forums.

You can also export existing configurations by selecting and dragging them from the configuration list to any location in the Finder (e.g. the Desktop).

 
Writing Your Own Configurations
Creating a new configuration for a USB device is fairly straightforward and involves these steps:
  1. Make sure the USB device is connected to your computer
  2. Click on the (+) button at the bottom-left of the MidiHID Window to create a new blank configuration
  3. Rename the configuration
  4. Select the USB device it applies to
  5. Edit the Lua script (make sure to click "Reload Script" anytime you want to test your changes)
  6. Click "Save"
 
Getting Started With Lua
Lua is a very lightweight but powerful scripting language that is quite popular in the video game world.

If you have basic knowledge of programming languages, you should be able to get started in no time. If you have no programming language knowledge however, it should still be reasonably easy for you to modify any properly documented configuration file.

MidiHID uses Lua 5.1.4 with the following core libraries available in the script environment: base, string, table and math. MidiHID provides an extra "midi" library (see below), that is used to send MIDI messages from the Lua script.

MidiHID also adds a log() function, similar to the Lua print() function, except it prints to the MidiHID log instead of the system log (i.e. the Console application). It's recommended you use this function instead of print() for debugging your scripts.

To get started with Lua, you can browse the nice tutorials available on lua-users.org. Once more familiar, you can head to the reference manual for Lua 5.1 which is available on lua.org.

 
MIDI Library
MidiHID adds a new MIDI library to the Lua environment consisting of the following functions:
midi.message(message, [data1, [data2]])
midi.noteon(key, [velocity])
midi.noteoff(key, [velocity])
midi.controlchange(control, value)
midi.pitchwheelchange(value)

Use the midi.message() function to send a raw MIDI message. The parameters are as follow:

  • "message" (REQUIRED): a numerical value between 0 and 15 corresponding to the MIDI message
  • "data1" (OPTIONAL): a numerical value between 0 and 127 representing the first data byte
  • "data2" (OPTIONAL): a numerical value between 0 and 127 representing the second data byte
-- Example usage to send a Note On for key #16 and velocity 100
midi.message(9, 16, 100)

The midi.noteon() function is a convenience function to send a Note On MIDI message. The parameters are as follow:

  • "key" (REQUIRED): a numerical value between 0 and 127 representing the note key
  • "velocity" (OPTIONAL): a numerical value between 0 and 127 representing the note velocity (if absent, 127 will be used)
-- Example usage to send a Note On for key #16 and velocity 100
midi.noteon(16, 100)
The midi.noteoff() function is a convenience function to send a Note Off MIDI message. The parameters are as follow:
  • "key" (REQUIRED): a numerical value between 0 and 127 representing the note key
  • "velocity" (OPTIONAL): a numerical value between 0 and 127 representing the note velocity (if absent, 127 will be used)
-- Example usage to send a Note Off for key #16 and velocity 127
midi.noteoff(16)
The midi.controlchange() function is a convenience function to send a Control Change MIDI message. The parameters are as follow:
  • "control" (REQUIRED): a numerical value between 0 and 127 representing the control number
  • "value" (REQUIRED): a numerical value between 0 and 127 representing the control value
-- Example usage to send a Control Change for controler #20 and value 50
midi.controlchange(20, 50)
The midi.pitchwheelchange() function is a convenience function to send a Pitch Wheel MIDI message. The parameters are as follow:
  • "value" (REQUIRED): a numerical value between 0 and 16383 representing the pitch
-- Example usage to send a Pitch Wheel with value 5000
midi.pitchwheelchange(5000)
 
Defining Optional Functions
MidiHID supports 3 optional functions in the Lua script that get called at specific times:
_connect()
_disconnect()
_event(cookie, name, value, min, max)

The _connect() function is called whenever the USB device is connected to the computer: you can use it to send specific MIDI messages when this happens.

-- Example implementation that simply prints a message when the device is connected
function _connect()
    log("<CONNECT>")
end

The _disconnect() function is called whenever the USB device is disconnected from the computer: you can also use it to send specific MIDI messages when this happens.

-- Example implementation that simply prints a message when the device is disconnected
function _disconnect()
    log("<DISCONNECT>")
end

The _event() function gets called whenever an event is received from the USB device, assuming it is connected. The parameters are as follow:

  • "name": the name of the event (this will be unique per-device)
  • "value": the current numerical value for this event
  • "min": the minimum numerical value the device reports for this event
  • "max": the maximum numerical value the device reports for this event
Note that this function is not called if there's already an event handler defined for this specific event (see below).
-- Example implementation that simply prints a message whenever an event is received from the device
function _event(name, value, min, max)
    log("[" .. name .. "] = " .. value .. " (" .. min .. " | " .. max .. ")")
end
 
Defining Event Handlers
Having a single function _event() called for any event received from the USB device can be useful for debugging reasons, but it's neither practical nor elegant to have a single monolithic function handle the USB to MIDI conversion.

MidiHID conveniently lets you defined functions, called event handlers, that get called only for a specific device event. They must have the following prototype, where "EVENT_NAME" is the name of the event for which the function should be called:

EVENT_NAME(value, min, max)

The "value", "min" and "max" parameters have the same meaning as for the _event() function.

-- Example implementation of a function that gets called when the event "Button_1" happens
function Button_1(value, min, max)
    log("Button-1 = " .. value)
end
 
Example Event Handlers

Here are some example event handlers:

Sending a Control Change #3 MIDI message with control value 127 when the device button #1 (corresponding to event "Button_1") is pressed down (event value is zero) or control value 0 when it is released (event value is non-zero):

-- Regular version
function Button_1(value, min, max)
    if value ~= 0 then
        midi.controlchange(3, 127)
    else
        midi.controlchange(3, 0)
    end
end

-- Compact version
function Button_1(value, min, max)
    midi.controlchange(3, (value ~= 0) and 127 or 0)
end

Sending Control Change #20, #21, #22 and #23 MIDI messages with control value 0 or 127 depending on the current position of a 4 positions hatswitch button on the device:

function Hatswitch(value, min, max)
    if value == 8 then
        -- Hatswitch is neutral, reset MIDI controllers #20 and #21 and #22 and #23
        midi.controlchange(20, 0);
        midi.controlchange(21, 0);
        midi.controlchange(22, 0);
        midi.controlchange(23, 0);
    elseif value == 0 then
        -- Hatswitch is on position up, send MIDI controller #20
        midi.controlchange(20, 127);
    elseif value == 4 then
        -- Hatswitch is on position down, send MIDI controller #21
        midi.controlchange(21, 127);
    elseif value == 6 then
        --Hatswitch is on position down, send MIDI controller #22
        midi.controlchange(22, 127);
    elseif value == 2 then
        --Hatswitch is on position down, send MIDI controller #23
        midi.controlchange(23, 127);
    end
end

Sending Control Change #10 with alternating values of 0 and 127 whenever the "System_Menu" event is received:

-- We need to use a global variable "toggle" to hold remember the current state across function calls
toggle = 0;
function System_Menu(value, min, max)
    if value > 0 then
        toggle = (toggle == 0) and 127 or 0
        midi.controlchange(10, toggle)
    end
end

Remapping the value for the "Z" event from its original min & max to Control Change #1 between 0 and 127:

function Z(value, min, max)
    value = (value - min) * (max - min) * 127
    midi.controlchange(1, value)
end
 
© Pierre-Olivier Latour, 2008-2009 | info@midihid.com