This tutorial will cover some of the basics of using the MIDI (Musical Instrument Digital Interface) communications protocol. We will see how to receive MIDI information from input devices, send it to other hardware or software and select the device that will get the sent information.
While the prevalence of software-only music systems have reduced the need for MIDI devices, the MIDI protocol is still necessary for working with both hardware and software synthesizers and samplers. MIDI is also becoming more widely used by artists working with physical interfaces, since it provides a compact and easy-to-use communications protocol for receiving sensor information and producing control messages for motors and other controllable devices.
The tutorial patcher contains a number of small MIDI-specific patches. The left-most patch changes a number
box anytime information is received from a MIDI input device (via the midiin
object), then sends that information out to another MIDI device (through the midiout
object). However, you need to select which device will be used for MIDI input and output. A simple way select a MIDI device is to double-click on the MIDI object you want to assign. Double-clicking on the midiin
object produces a menu of available MIDI inputs
, while double-clicking on the midiout
object will display a menu of MIDI outputs
In addition to the physical MIDI devices that are connected to your computer, you will also see some virtual MIDI ports, depending on your operating system and how it's configured. One of the most useful virtual ports is the built-in synthesizer output – it allows you to generate sounds from MIDI messages without having to connect a physical synthesizer or sampler.
If you select a MIDI input keyboard for the midiin
object, and the built-in synthesizer for output, you have a simple MIDI thru
application with very little patching. The midiin
objects pass out and expect unformatted raw
MIDI messages – if you route the output of the midiin
object to a print object, you will see that you have a serial stream of numbers that can be difficult to interpret. Max contains a number of objects that give us a little more control how we use MIDI data inside out program by selecting which types
of MIDI events (notes, continuous controllers, etc.) we want to work with.
objects are an example of message-specific
MIDI objects. They accept the input of a MIDI stream, and ignore all message types other than note
messages - those traditionally caused by playing keys on a MIDI keyboard or pads on a drum trigger. As with the midiin
objects, we can select the MIDI port by double-clicking on the object.
The second patch shows a basic note display; we can select a MIDI port, then view the notes that are received on that port. The notein
object displays three pieces of information for each incoming note message: the note number
), the note velocity
and the MIDI channel it was transmitted on. Play a MIDI keyboard or other controller that creates MIDI note messages, and see how the note information is displayed by the number
You will notice that there is no “on or off” display to differentiate keys being played (a "note-on") and keys being released (a "note-off") – rather, a note-off message is displayed as a note with a velocity of zero (0
). This is a common MIDI convention, and it is used by many Max objects as the preferred way of displaying a note-off message. We have also used a number
box with the Display Format
attribute set to MIDI
. This provides us with an easily-read cue as to the pitch of the note that is being played.
The next patch is a simple example of the reverse process: generating
note messages to be played by a MIDI device. The noteout
object expects pitch
, and channel
numbers to be received in its left, center, and right inlets, respectively. The left inlet (pitch
) is hot
, while the others are cold. In this case, we use Max’s ability to decode a list
of messages as the input to all of the inlets of an object. Thus, the message
box labeled 64 100 0
is treated like three separate messages to each inlet: they are “channel 0”, “velocity 100” and “note 64”. This will send a note-on message for pitch 64
) at a velocity of 100
to channel 0
. The second message
box is almost the same, but uses a velocity of 0
– which is the equivalent of a note-off message. Double-click on the noteout
object, and select a valid MIDI output device. Then click on the first message
box. You should hear the device sound the note. It should sustain until you hit the second message
box, which will turn it off. This is a basic MIDI note event structure, and can be used as the basis for generating MIDI messages that play music.
The right-most patch is a simple version of an application that remaps
MIDI controller data: it changes any modulation wheel control value (by convention, MIDI controller 1
) into a pan control value (controller 10
). In this case, the ctlin
objects are used for receiving and sending MIDI continuous controller messages. These objects are message-specific MIDI object dedicated to MIDI controller values which are often sent by MIDI fader boxes and knob/rotary controllers, as well as more music-centric interfaces such as keyboard sustain pedals. As with the other objects, you can double-click them to set a MIDI port for use.
The incoming values are used to set up the control system. The patch uses the incoming controller number (the middle outlet of ctlin
) to determine the routing of a graphical gate (gswitch2
) object. When controller 1
is seen, the ==
object outputs a 1
, which sets the the switch to allow the controller value (the left
outlet) to go into the subsequent message
box. This value is then assembled into a valid message for ctlout
, which will send the value (assigned to MIDI controller 10
on channel 0
) to the selected MIDI output.
There is a little extra programming attached to the ctlout
object: a button
is connected to a midiinfo
object, which loads a umenu
object with some data when it receives a bang
message. This data is fed into the ctlout
object. What is this about?
Sometimes, you don’t want the end user of your patch to have to double-click the MIDI objects to set a port, or you may want to set the port on many objects simultaneously. The midiinfo
object provides a lot of information on your current MIDI setup, which you can use to set the port information on your MIDI objects. In this case, when the midiinfo
object receives a bang
message in its left
inlet, it produces the names of the available MIDI output
ports currently defined on your system. This is used to load the umenu
object with your current MIDI setup. When you select an item from the menu, it is sent to the ctlout
object as an identifier of the port you want to use.
This is just one of the uses of the midiinfo
object; we will see other uses in upcoming tutorials. If you want to query your computer for information about available MIDI ports and available controllers, review the midiinfo
help files and reference pages.
In order to exercise the MIDI message tools, let’s create a basic MIDI monitoring application. We can start by creating a version of the midiinfo
combination that will show available MIDI inputs
. In order to see the inputs, we need to send a bang
message into the right
inlet of the midiinfo
object. You can do this with a button
object, or use a loadbang
object so the menu will be loaded each time the patch is loaded.
In order to track both note and controller information, we can send the output of the umenu
to both a notein
object. This sets up the two objects to receive MIDI information from the same MIDI port. Now, connect number
boxes to each of the outlets of the notein
objects. We can probably have a single number
box share the “channel” messages, since we won’t have notes and controllers being generated at the same time. Finally, changing the note number
box to use a Display Format
of MIDI will allow us to easily see the key of the depressed note.
While this is a fairly simple MIDI monitor application, it is the sort of application that can help you debug a complex MIDI setup. You can expand this patch by using other MIDI message-specific objects, such as pgmin
(MIDI program changes) and bendin
(MIDI pitch bend messages), to see even more of the received MIDI data stream.
The basic contents of an incoming MIDI stream can be retrieved using the midiin
object, and a MIDI stream can be sent using the midiout
object. However, in most cases, it is easier to deal with individual message types using their message-specific objects. The notein
objects provide an easy way to deal with messages without having to decode the raw MIDI input or create raw MIDI output.
object, is a powerful tool for examining the current state of your MIDI setup. Using it to load a menu of available MIDI ports can help make your patch easier to use and is also the best way to set a number of objects simultaneously.
Output received raw MIDI data
Transmit raw MIDI data
Output received MIDI note messages
Transmit MIDI note messages
Output received MIDI control values
Transmit MIDI control messages
Set a pop-up menu with names of MIDI devices
Pass the input out one of two outlets