MIDI Tutorial 1: Basic MIDI
Introduction
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.
To open the tutorial patch, click on the Open Tutorial button in the upper right-hand corner of the documentation window.
The midiin and midiout objects
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 and midiout objects 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 more control over how we use MIDI data inside our program by selecting the types of MIDI events (notes, continuous controllers, etc.) we want to work with.
All about notes: the notein and noteout objects
The notein and noteout 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 and midiout 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 (or pitch), 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 boxes.
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
, velocity
, 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
(E3
) at a velocity of 100
to channel 0
. The second message box is almost the same, but uses a velocity of 0
– which will generate 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.
Controllers and port selection: ctlin and ctlout, and midiinfo
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 and ctlout objects are used for receiving and sending MIDI continuous controller messages. These are message-specific MIDI objects 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.
Creating a basic MIDI monitor
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 / umenu 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 and ctlin 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 and ctlin 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.
Summary
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 / noteout and ctlin / ctlout objects provide an easy way to deal with messages without having to decode the raw MIDI input or create raw MIDI output.
The midiinfo 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.