InVeSTigations (part 2)
One quick way to start having fun with Max is to use the vst~ object to host audio plug-ins or VST instruments; you can load plug-ins you already have (or find some free plug-ins) and get a little experience with using Max to send messages to them while you gather the courage to write your own audio processing patches or virtual synths.
I’ve written the patch you see below to help you get started. It should let you explore working with audio plug-ins.
Last time, we looked at using the vst~ object to load VST audio plug-ins in Max, and also looked at how to use some Max messages to load a pop-up menu (the ubumenu object) with useful things like a listing of plug-in parameters or programs.
The vst~ object can also be used to load VST instruments. And, in the same way that we used Max messages to control the audio plug-ins, we can send messages to virtual instruments that will do useful things—like playing actual notes (in addition to the dial twisting, button punching, and fader yanking you already know how to do).
Let’s start with MIDI, for starters—it’s the easiest way to look at the kinds of messages we’ll be sending to the virtual instrument hosted by the vst~ object. And, since you already use MIDI in the non-virtual synth world, we can use any MIDI keyboard you’ve got to explore how MIDI messages are put together; in order to work with VST instruments, we only need to make a few little changes to have a lot of fun.
Note:MSP only lets you host VST instruments. There is currently not a way to host any other plug-in format (e.g., Audio Units, DirectX, etc.).
Watching MIDI Work
Here’s a little patch that shows the Max midiparse object. We can use it to take a look at the kinds of messages that MIDI uses and sends, and we can also use its output to feed messages to our VST instruments and make some noise later on:
This patch includes a midiin object that “listens” to any MIDI devices you’ve got currently plugged in to your computer and simply outputs a stream of numbers when you play the keyboard or push a button or turn a knob on your keyboard. When you start Max, it takes a look around to see what’s currently connected, and keeps a complete list. If you double-click on the midiin object, you’ll see a pop-up menu that lists all the currently available choices for MIDI input (for example, my Edirol lists things that look like “EDIROL PCR EDIROL PCR 1”). If you don’t know what the official name of your MIDI input device is, you can just make a choice and play some keys—if you’re connected, you’ll see the number box objects at the bottom of the patch change and the LEDs at the bottom will flash when you do something. You can also look in the Max window to see a long list of integers. That’s the raw input from your MIDI device, sent one number at a time. Since Max really does nothing but make music using numbers, we’re in good shape.
You’ll also see four Message box objects in the patch, each containing three numbers separated by commas. They’re examples of MIDI messages, and will have the same effect when sent to the midiparse object as if you’d played a key or turned a know on a connected MIDI keyboard.
Each of the four MIDI messages starts with a number that identifies what kind of MIDI message it is. There are different MIDI messages to turn notes on and off, messages for MIDI controllers (you may have knobs, dials, buttons or sliders on your MIDI keyboard), and special kinds of MIDI messages for things like pitch bend, aftertouch, polyphonic key pressure, and so on. The midiparse object helpfully takes raw MIDI input and parses the incoming messages according to what kind of MIDI message it is, and sends them out of separate outputs as either pairs of numbers (which we call that a list), or as single values.
Click on the Message box object that contains the message 144, 60, 70. You’ll see the number box objects labeled Note On/Off change and flash, and you’ll also see the MIDI Channel number box on the right change and flash. The message we send tells a MIDI instrument to play a note on channel 1 (144), tells it the MIDI note number to play (60), and the velocity—how “hard” to hit the key (70). If you’ve got a MIDI keyboard attached, you’ll notice that the final number in the MIDI message changes to 0 when you release the key—that’s because sending a velocity message of 0 means “note off.”
Try the modulation wheel or the pitch band on your keyboard and watch the display change.
Talking to a VST instrument
If you’ll recall, the vst~ object used messages to control parameters of an audio plug-in. In the last tutorial, we discovered that sending an integer followed by a floating point number in the range 0.-1.0 could be used to control the parameters of an audio plug-in—all we needed to know what what number corresponded to what parameter.
So, how to we send MIDI messages to a virtual instrument we’re hosting in the vst~ object? That’s right—by sending another kind of message. It’s almost exactly the same as a MIDI message, except that the list of numbers is preceded by the word midievent. So, if the MIDI message we send to a MIDI synth to play a note is composed of the numbers 144, 63, and 70, we’ll pack those three numbers into a list, add the word “midievent” to the beginning, and send it to a vst~ object that contains our virtual synth:
midievent 144 63 70
Note: We’re not converting any of the MIDI messages to the range 0.-1.0. We only do that when we’re sending parameter messages to a VST plug-in.
Since the midiparse object divides up incoming raw MIDI data so that all the different kinds of MIDI messages are grouped together according to their message type (note-on/off, pitch bend, etc.), then it’s perfect for feeding MIDI data directly to a vst~ object. There’s a nifty little patcher written by my pal Darwin Grosse called the “qs.vstizer” that does just that:
As you can see, the patch has an input that corresponds to each of the different MIDI message types that the midiparse object outputs. It takes that message, prepends the proper MIDI event number associated with the kind of event, and then prepends the word midievent to that. So what pops out the bottom of the subpatch is a perfectly formed message you can send straight to the vst~ object to make noise and have fun.
You may have noticed that the various MIDI event numbers (the first number in the list of three in any MIDI message) aren’t right next to each other in numerical order. In fact, they’re 16 numbers apart (144-160, 160-176, etc.). You might also have noticed in the previous patch example that sending the MIDI message “144, 60, 70” would play a note on MIDI channel 1, while “145, 60, 70” would play the same note on MIDI channel 2. The messages are 16 numbers apart because each different type of MIDI message can be sent on one of 16 channels. The use of the numbers 144, 160, 176, and so on this patch assume that you’re sending MIDI data on channel 1.
But what if you’re not using channel 1? No problem—the Max objects on the right keep track of the MIDI channel your keyboard or controller is sending MIDI messages on, and increments the MIDI message number so that it matches the right channel (a nice detail from Darwin, who is a very thoughtful man).
Note: This abstraction (which I’ve included in the tutorial files) is available, along with a number of other incredibly useful “Quick Start” Max/MSP patches, from the Cycling ’74 share website directory that holds Darwin’s patches and contributions.
Putting It All Together
Here’s a patch that combines the midiparse object with Darwin’s message handling patch (called qs.vstizer) in a way that will let us have some fun with a VST instrument plug-in, Max, and a MIDI keyboard:
You’ll recognize a lot of this patch from the previous column: there’s the trusty vst~ object that’ll host the VST instrument plug-in, a Message box object containing the message plug that will cause the vst~ object to load any VST instrument we have in our plug-ins folder, and the combination of the trigger and deferlow objects we used last time to make sure that the plug-in was successfully loaded before we used the params message to load a ubumenu object with the names of all the plug-in parameters (this time out, there are four of those ubumenu objects, though).
At the top of the patch, you’ll notice a midiin object connected to a combination of the midiparse and qs.vstizer objects/abstractions, which are, in turn, connected to the vst~ object. This is the part of the patch that connects our MIDI keyboard to the patch, decodes the incoming raw MIDI data, and then formats it to send to the VST instrument hosted by the vst~ object. It allows us to load a virtual instrument and play it from our MIDI keyboard. Here’s how you do it:
- click on the Message box containing the plug message and choose a virtual instrument to load.
- Double-click on the midiin object and choose your MIDI keyboard from the pop-up menu.
- Click on the ezdac~ object (the Speaker icon) and play. You can use the volume sliders to set the instrument’s output level.
Have fun for a while.
But you’ve probably noticed that there are a few other things in the patch. What are those ubumenu objects for? What does that abstraction named p dialhandler do? What are those little send and receive objects like s mydials and r vstdials for, anyway?
Adding Synth Controls
Being able to play notes and mess with the pitch wheel on a softsynth is certainly a lot of fun, but twiddling the synth knobs would be even better—especially if you could do both at the same time. Since we already know how to control the parameters of a plug-in hosted by the vst~ object (by sending messages that take the form [parameter number] [value (0.-1.0)], all we need to do is to figure out how to translate the MIDI messages that are sent out when we use a knob or fader into a form that the vst~ object understands. And it would be nice to do this for only the controllers we want without interrupting the flow of other controller messages.
Take a look at the midiparse object at the top of the patch. You’ll notice that while most of the outputs of the midiparse object are connected directly to the inputs of qs.vstizer, there is one set of outputs for the midiparse object that is connected to a send object (s mydials), and a receive object connected to the corresponding input of qs.vstizer. If you look for the corresponding receive and send objects that have the same names, you’ll find them at the bottom of the patch, attached to a subpatcher (p dialhandler). Looks like the subpatcher is also connected to each of the four ubumenu objects above them, using the same lefmost output we used in our last column when we wanted to create parameter messages to sent to the vst~ object. Want to guess what’s going on here?
That’s right—the p dialhandler subpatch lets us select some controller messages from a MIDI keyboard and create parameter messages using the contents of the four ubumenu objects right above the subpatcher, which we then send to the VST instrument. If you double-click on the p dialhandler subpateher, here’s what you’ll see:
The patch itself is pretty straightforward. The rightmost outlet takes the MIDI controller message output from the midiparse object and looks for any controller messages that begin with the numbers 74, 71, 76, or 77—any controller messages that don’t start with those numbers is simply passed through the object. What do those numbers represent?
The correspond to the MIDI controller numbers of four knobs on the front panel of my Edirol PCR-80. I found out what the controller numbers were by using the very first example patch in this article—I just hooked up the keyboard, turned the knobs, and noted the controller numbers that came out the bottom of the midiparse object. If you’d like to change this patch to match the equipment you’re using, just replace the arguments to the route objects so that the four numbers reflect four knobs or sliders on your equipment.
As you’ll recall from inVeSTigations (part 1), all VST audio or instrument plug-ins expect their parameters to be set using a floating point value in the range 0.-1.0. And you also noticed that the midiparse object outputs messages as integers in the range 0-127. This subpatch uses the zmap object to map one set of values to the other—as shown by the arguments to the object ([input range low] [input range high] [output range low] [output range high]). Notice, too that the 3rd and 4th arguments have periods to indicate that the values are floating point numbers; using 0 126 0 1 instead of 0 126 0. 1. as arguments will not produce the result you’re looking for). The four inputs on the top left of the subpatcher represent the output from the left outlet of each ubumenu object. You’ll recall that the left outlet sends a number when you select a parameter from the pop-up menu. Since the ubumenu counts from 0 rather than 1, we always need to add 1 to the number the ubumenu outputs to choose the proper parameter number. Any time we turn one of the four knobs on the front panel of my MIDI keyboard, the MIDI controller message is translated into a floating point number in the correct range for a VST parameter message, packed up with the number of the VST parameter that corresponds to the parameter name listed in the ubumenu, and sent to the vst~ object.
The end result? Why, it’s twisterrific!
You can find a Zip file containing the patches in this article here.
Next time, we’ll take another look at VST audio plug-ins, and look at an interesting way to combine multiple plug-ins in performance.