MIDI Tutorial 3: MIDI Parsing
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, ctlin, pgmin and others), we can use a single midiparse object to decode 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.
To open the tutorial patch, click on the green Open Tutorial button in the upper right-hand corner of the documentation window.
Viewing midiparse in action
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.
The midiparse 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.
Viewing midiformat in action
A complementary object to midiparse is midiformat, 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 objects 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 a slider 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 rate of controller messages that are sent to any device, since too great a density of controller messages can potentially confound a MIDI synthesizer. Finally, you should make sure that the MIDI channel you are using is appropriate for the device that you are attempting to control.
Tracking extended MIDI controllers using xbendin
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 defines pitchbend to use 14 bits of data, providing values from (full bend down) to (full bend up - the no bend state is ). This allows much finer pitch control, and offers a better likelihood of achieving musical results. Few controllers provide all 14 bits of accuracy, but 8 to 10 bits are very common.
Midiparse only provides the most significant 7 bits of bend data, but we can track extended pitchbend information using the xbendin object. Xbendin 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 sluggishly, 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 and number 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 be 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 and midiformat messages to stream MIDI data from and to the devices while having access to all the message types. Using midiparse and midiformat 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. However, since some of this information might be received too quickly, using speedlim to slow down the receipt of these messages can help us keep our patches responsive.