This tutorial dives into a few MIDI-based objects that provide extended functionality for MIDI programming. The midiparse
object can be used to examine the components of a raw MIDI stream, while midiformat
is used as a one-stop shop for creation of most commonly supported MIDI messages. We also use the xbendin
object to see the extended values provided by many MIDI controllers for the pitch bend value.
Because of the nature of these objects, this will be a “show” tutorial rather than a “build” tutorial. However, please take the time to understand the data flow through these patches, since they are the basis for much of the handling of a complicated MIDI setup.
When creating any significant MIDI-controlled patch, we may need access to all of the notes, controller changes, and other messages generated by a MIDI device. Rather than using many individual objects (such as notein
and others), we can use the midiparse
object to parse the incoming MIDI stream. We can also use the midiformat
object to generate a MIDI stream that can contain a wide variety of MIDI messages. Both of these objects are very useful for complicated MIDI control patching.
We also take a look at the extended values provided for certain message types – specifically, the extended (14-bit) values provided by most MIDI keyboards for the pitchbend wheel. Since these messages can be produced very rapidly, we will also use the speedlim
object to slow down the display of the values, preventing overload of our patch during high-speed message generation.
In the patcher for this tutorial, we are using a midiin
object to grab the raw MIDI input stream from a MIDI input device, and using midiparse
to split the data into the various supported message types. The outlets of midiparse
issue different types of messages depending on the type of MIDI input: notes, poly key pressure and control changes are lists, while the program change, aftertouch and pitch bend outlets put out single integers. We’ve routed these outputs to slider
objects in order to display the various messages as they are received. If you have a MIDI controller that can generate these messages, select its MIDI port (by double-clicking on the midiin
object) and play it – you should see the slider
objects respond to incoming messages. Note that the MIDI is not attached to the individual messages; the MIDI channel is sent from a shared outlet that will always display the channel of the most currently received message.
object is used whenever you are creating a MIDI-driven patch that has to respond to a large number of message types. Rather than using all of the different message-specific objects (notein
etc.), you can use this single object to track the various messages. MIDI sequences being played into Max from an external hardware or software sequencer, for example, will contain much more than just notes; the midiparse
object lets you see the full range of information present in the sequence.
A complementary object to midiparse
, which allows us to create many different message types and turn them into a MIDI stream that is acceptable to the midiout
object. The lower half of our test patch shows all of the messages that can be created, and provides slider
s that can be used to generate these messages. To test the result, double-click on the midiout
object, and select an appropriate MIDI output device. Then move the slider
s connected to the midiformat
object – you should hear the results (when they are audible) from your MIDI device.
Some care needs to be taken when creating messages for midiformat
. As with any other note-based device, you should pair MIDI note-on messages with MIDI note-off messages. You should also limit the number of controller messages that are sent to any device, since too great a density of controller messages can potentially confound a MIDI synthesizer, depending on its capabilities. Finally, you should make sure that the MIDI channel you are using is appropriate (and, in the case of multitimbral synthesizers, the active channel) for the device that you are attempting to control.
In most cases, the 7-bit values (
- ) sent and received from MIDI controllers are sufficient for dealing with synthesizer and sampler control. However, in a few cases, 7-bit values are insufficient for nuanced information. The most common example of this is the pitchbend control. When a synthesizer is set to bend +/- one octave, the individual steps of the pitchbend control might correspond to coarse and unmusical pitch steps. The MIDI specification allows for pitchbend to occupy 14-bit values, providing values from to . This allows use to have much finer pitch control, and offers a better likelihood of achieving musical results.
We can track extended pitchbend information using the xbendin
object, which takes raw MIDI input and outputs pitchbend messages that include this extended range. Even if your MIDI controller does not send true 14-bit messages, they will be parsed as if the full 14-bits were available. Unfortunately, even the most stable MIDI controller can produce an excessive number of MIDI pitchbend messages when tracking the extended value – the hardware is unable to stabilize on a single value, and may produce a greater-than-acceptable number of very small changes. While this may not affect any connected hardware, it can cause a Max patch to behave erratically, or at least make it difficult to properly debug a complex patch.
The solution for this is the speedlim
object, which will take the output of any object (in this case, xbendin
), and will limit the output to only one message in any given timeframe. In the example patch, the argument tells speedlim
to output a message at most
every milliseconds (one-quarter second). The object will discard all but the last message in that timeframe, giving us a less dense set of messages to manage in our patch. When you send pitchbend information to the example patch, you will see that the button
box connected to xbendin
update much more often than those out of the speedlim
; the number
box connected to the output of speedlim
will always updated within a quarter-second to show the most recently passed value.
When creating a complicated MIDI-controlled patch, we will often want to use all of the available MIDI messages. Rather than have a large number of message-specific objects, we can use the midiparse
messages to stream MIDI data from and to the devices while having access to all the message types. Using midiparse
is at the heart of any large and complex MIDI-based patching system.
Having access to extended control information can allow us to make more musically sensitive patches. Using xbendin
to receive the extended pitch bend information can help us create more stable-sounding synthesizers within Max/MSP. However, since some of this information might be received too quickly, using speedlim
to slow down the receipt of these messages can help us control the amount of overhead built into our patches.
Interpret raw MIDI data
Prepare data in the form of a MIDI message
Interpret extra precision MIDI pitch bend values
Limit the speed at which messages can pass through.