MIDI Machine lets you easily build your own custom MIDI effects. It is turing complete with respect to the MIDI system, which means it can map *any* MIDI input sequence to *any* MIDI output sequence. Thus, MIDI Machine lets you make custom arpeggiators, harmonizers, chord filters, tuning-mappings or indeed any type of MIDI effect you can imagine. It was originally built for the MIDI Guitar software, but it works with with keyboards or any kind of MIDI controller as well.
The design objective of MIDI Machine is to make it as simple as possible to do anything within the MIDI domain. Of course, ultimate MIDI powers and versatility is only possible though some form of programming. MIDI Machine is based upon the Lua language and has its own development environment integrated to make it easy to get started.
From a user point of view, MIDI Machines are not very different from other types of MIDI effect plugins and should also look familiar with a series of knobs to control them. The big difference is that existing MIDI Machines effects are easy to modify to your needs, and that MIDI Machine makes it easy to create entierely new custom MIDI effects. MIDI Machine code is friendly and it should be easy to get started – you can create simple MIDI effects within minutes. As an example of the pursuit for simplicity MIDI Machines will automatically create their own graphical user interfaces.
This best way to learn about MIDI Machines is to run the application (ie. MIDI Guitar standalone) and look at the small built-in example Machines.
Currently MIDI Machine exist only as part of the MIDI Guitar application/plugin. That should not be a limitation since MIDI Guitar pass MIDI though from keyboards and -controllers.
You can download MIDI Machine as part of MIDI Guitar here.
MIDI Machine API, Overview
The easiest way to get started creating your own MIDI Machines is to download and run the application (inside MIDI Guitar) and play with the example MIDI Machines to understand how they work. This page provides the documentation of the API for reference.
A MIDI Machine is defined by up to 6 Lua functions. These function are handlers for different MIDI input events. The functions are:
- OnStart will be called when a MIDI Machine starts up.
- OnNote will be called whenever a note event occur.
- OnBend will be called whenever a pitch bend/wheel event occur.
- OnAftertouch will be called whenever an aftertouch event occur.
- OnControl will be called whenever a control change event occur.
- OnFrame will be called every few milliseconds, once every audio frame.
Inside these event handlers a MIDI Machine can do its work. In order to produce anything useful it must be able to send out MIDI messages in response to the input events. There are 4 functions to produce MIDI output, almost symmetrical to the above:
- Note will send out a note event.
- Bend will send out a pitch bend/wheel event.
- Control will send out a control change event.
- Aftertouch will send out an aftertouch event.
Thats it! Well, there is one more function used for debugging your machines:
- Print will print out a text string to the console, to be used for debugging.
Below the API is described in detail.
MIDI Machine API, Reference
function OnStart(description, link)
Print(“The MIDI Machine has started”)
The OnStart function is called upon start of your MIDI Machine.
You can assign a description and a link to your MIDI Machine or website which will be displayed in the interface of the MIDI MAchine.
function OnNote(channel, pitch, velocity)
if velocity > 0 then
Print(“A note with pitch “, pitch, ” was played”)
The OnNote function will intercept any MIDI note-on/off messages and give you its channel, midi pitch and velocity. The channel parameter is an integer in the range [1..16]. The pitch is the midi pitch in integer semitones. The velocity of a note is an integer in the range [0..127].
function OnBend(channel, bend)
Print(“Channel “, channel, ” was just bended “, bend, ” semitones”)
The OnBend function will intercept any pitch wheel MIDI messages and give you its channel and how many semitones were bended. The channel parameter is an integer in the range [1..16]. The bend parameter is a floating point number in the range [-12..12] representing a bend of up to 12 semitones (an octave) up- and downward.
Not implemented yet…
function OnControl(channel, cc, value)
Print(“Recieved a midi control change “, cc, ” with the value “, value)
The OnControl function will intercept any MIDI control change messages and give you its MIDI cc identifier and the value of the control change.The channel parameter is an integer in the range [1..16]. The cc parameter is an integer in the range [0..127]. The value paramter is an integer in the range [0..127].
Print(“Currently “, #notes, ” notes sounding”)
The OnFrame function will be called every few milliseconds, or more preciesly once pr audio buffer processed by the audio system. It delivers one parameter notes which is an array of all notes currently sounding. For each note n in the array the following data is avaialble. n.pitch is the midi pitch of the note. n.bend is a floating point value in the range [-12..12] giving the current bend value of the note. Thus at any time, n.pitch+n.bend is the actual pitch of a note. n.velocity is the velocity of the note. n.duration is the duration the note has been sounding in milliseconds. n.frames is the duration the note has been sounding in number of OnFrame events.
function Note(channel, pitch, velocity [, time])
The Note function will send out a note-on/-off message a given channel with a given pitch and velocity. Any note send with zero velocity will be interpreted as a note off. Optionally pass in a time offset to schedule future events.
function Bend(channel, bend [, time])
The Bend function will send out a pitch bend message on a given channel with a bend in the range [-12..12]. Optionally pass in a time offset to schedule future events.
Not implemented yet.
function Control(channel, cc, value [, time])
The Control function will send out a midi control change message a given channel with a given cc number and value. Optionally pass in a time offset to schedule future events.