InVeSTigations (part 1)


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.

You’ll find the patch at the bottom of this article, saved as a text file. Here’s a good chance to practice the technique for converting text filces into Max patches, as I described here.

Here is the patch:

Some of the patch is very simple: you’ll find an sfplay~ object (the 2 argument specifies we’re playing a stereo file), the vst~ object we’ll load a plug-in into, a pair of linked gain~ sliders to control the output volume, and a dac~ object to turn the audio on and off.

All the other stuff in this patch is used to load plug-ins, create lists of parameters and programs after we’ve loaded the plug-in, and to control the plug-in using Max messages. We’ll look at these messages as we go (I’ll presume that you’ve got a plug-in you’d like to load and investigate).

The vst~ object takes a variety of messages that let you do things like loading plug-ins, querying a plug-in to discover the parameters you can change, querying a plug-in to determine whether it has any preset programs, as well as messages that let you set and change any parameter the VST plug-in uses.

You’ll see several trigger objects located in the upper right-hand corner of the patch. For example, there’s one right underneath each of the Message box objects for plug, params, and pgmnames (Note: you can type “t” instead of “trigger” for the name of the object, if you want. Many people do). This object is used to make sure that messages are sent in a specified order. In the case of the trigger objects below the params and pgmnames Message box objects, the trigger object will always send out a clear message to clear out the ubumenu before sending the message that repopulates the menu. The trigger object below the plug Message box object deserves a little closer attention, since it uses a neat little trick. The trigger object sends out two messages in order—the list message it receives from the Message box (plug), and a bang message that goes to a Max object named deferlow.

The deferlow object is used to de-prioritize any Max message it receives—it puts all incoming messages at the tail of the low priority queue. We’re using it here as a kind of “smart delay” to make sure that the vst~ object is finished loading whatever plug-in we tell it to load (using the plug message) before we send a bang message to the Message box objects containing the params and pgmnames messages.

The plug, params, and pgmnames messages are used to load a VST plug-in, and to query the loaded plug-in about any preset programs it may have, and to query the loaded plug-in about the parameters it uses.

According to the VST plug-in specification every parameter associated with a VST plug-in uses floating point values in the range 0. to 1.0 and each plug-in parameter is identified by a unique number. You can control VST plug-in parameters in Max by sending a message to the vst object that takes the form [parameter number] [value (0.-1.0)].

But how do you know which parameter corresponds to which dial or switch or slider on your plug-in’s front panel? The vst~ object lets you generate a list of every single VST parameter for your plug-in in numerical order by sending the message params message to the object. The list of all the plug-ins is sent out the Nth outlet of the vst~ object as a list.

At this point, we can use the ubumenu object to collect that list and save it in a form that we can use later. If you send the ubumenu a list preceded by the symbol “append”, the menu will be populated with the list you send. It’s a useful feature——so useful that we’ll use it to create a pull-down menu full of plug-in parameter names, and to create another menu full of program names.

Once we’ve populated the menu, we can select any plug-in parameter and send a value to that parameter. In the patch, when you choose a parameter from the ubumenu, the object sends the number that corresponds to it out the Nth outlet of the ubumenu object (remember—since menus begin numbering at 0 instead of 1, we’ll need to add 1 to the number output of the ubumenu). The pak object packs up the parameter number and the floating point parameter value whenever we change the value and send it to the VST plug-in.

Of course the actual number of parameters for a plug-in will vary widely—some plug-ins only have a few, and some plug-ins have a squillion of ‘em. What’s more, not everyone names their parameters very clearly, or names them at all. Suppose you’ve got a plug-in with 300 parameters, and all you need to do is find out about only one parameter. Luckily, the vst~ plug-in reports information about any parameters you’re using. When you move a slider or a dial, a message consisting of the parameter number and the current value are sent out the Nth outlet of the vst~ object. So the quickest way to check on a single plug-in parameter is to twiddle the knob and watch the outputs.

VST plug-ins may also have “programs”—collections of parameter settings that are save together so that you can bring ‘em all up by choosing the “parking garage” program instead of setting each value every time. If your plug-in has programs, you can also list them and load them using messages to the vst~ object.

The method for working with programs is almost exactly the same one as we used for plug-in parameters; the example patch sends a message to the vst~ object (the pgmnames message), which causes a list of all the programs for the plug-in to be sent out the Nth outlet of the vst~ object. We add the message append to the list output from the vst~ object using the prepend object, and the ubumenu object fills up with a list of all the programs associated with the plug-in.

As you’re playing around with loading patches, you might start to wonder about a few things:

  • If I’m playing an audio file when I load a new plug-in, the audio cuts out. How come this happens?
  • Can I load VST instruments into a vst~ object? If I do that, how to I play notes?

We’ll be looking at this stuff next time. In the meanwhile, here’s the Max patch used for this Beginner’s corner:

max v2;
#N vpatcher 30 56 931 750;
#P origin 0 -47;
#P window setfont "Sans Serif" 9.;
#P comment 251 125 220 196617 mute effect processing and echo input to output;
#P toggle 171 125 15 0;
#P message 194 125 54 196617 bypass $1;
#B color 6;
#P window setfont "Sans Serif" 10.;
#P comment 150 29 231 196618 Here's the usual stuff to load an audio file to listen to. The loop 1
message makes it loop.;
#P newex 255 322 33 196618 + 1;
#P comment 353 530 231 196618 Choose a plug-in parameter from the ubumenu and then click and drag
this number box to play with a parameter Note that the values are between 0. and 1.;
#P comment 310 360 231 196618 If you want to know the parameter number of a knob , just wiggle it
on the plug-in's edit window and watch these outputs!;
#P comment 598 53 277 196618 The trigger and deferlow objects are used to delay loading the ubumenu
with a list of plug-in parameters until the VST plug-in finishes loading.;
#P comment 598 29 277 196618 The plug message is used to load a VST plug-in.;
#B color 12;
#P message 508 172 59 196618 pgmnames;
#B color 14;
#P newex 508 196 79 196618 trigger l clear;
#P comment 598 172 277 196618 The pgmnames message will cause a list of the current program names
associated with a VST plug-in to be sent out the rightmost outlet of the vst~ object;
#B color 14;
#P message 508 110 56 196618 params;
#B color 13;
#P newex 508 134 79 196618 trigger l clear;
#P message 114 29 29 196618 open;
#P toggle 55 29 15 0;
#P message 75 29 35 196618 loop 1;
#N sfplay~  2 120960 0 ;
#P newobj 55 73 61 196618 sfplay~ 2;
#P user ezdac~ 55 406 99 439 0;
#P user gain~ 77 271 22 100 158 0 1.071519 7.94321 60.;
#P user gain~ 55 271 22 100 158 0 1.071519 7.94321 10.;
#P newex 508 79 67 196618 deferlow;
#P newex 508 53 75 196618 trigger b l;
#P message 508 29 44 196618 plug;
#B color 12;
#P newex 255 263 208 196618 prepend append;
#P user ubumenu 255 297 233 196618 0 0 1 0;
#X setrgb 31 31 31 255 92 187 234 234 234 4 4 4 141 141 141 112 112 112;
#X add "Program 1";
#X add "Program 2";
#X add "Program 3";
#X add "Program 4";
#X add "Program 5";
#X add "Program 6";
#X add "Program 7";
#X add "Program 8";
#X prefix_set 0 0 <none> 0;
#P comment 173 411 81 196618 parameter;
#P comment 255 411 50 196618 value;
#P number 175 386 47 10 0 0 160 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 255 386 44 10 0. 1. 163 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 175 360 90 196618 unpack 0 0.;
#P comment 180 166 233 196618 You can see the plug-in's edit window by using the open message or
double-clicking on the vst~ object;
#P comment 598 110 277 196618 The params message will cause a list of all the parameter names
associated with a VST plug-in to be sent out the third outlet of the vst~ object;
#B color 13;
#P message 144 165 31 196618 open;
#P newex 135 530 33 196618 + 1;
#P flonum 303 530 44 10 0. 1. 35 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 135 556 178 196618 pak 0 0.;
#P newex 135 456 208 196618 prepend append;
#P user ubumenu 135 490 233 196618 0 0 1 0;
#X setrgb 255 255 255 153 102 187 153 102 187 4 4 4 141 141 141 112 112 112;
#X add Gain;
#X prefix_set 0 0 <none> 0;
#N vst~ loaduniqueid 0;
#P newobj 55 235 212 196618 vst~;
#P fasten 25 0 22 0 119 63 60 63;
#P fasten 23 0 22 0 80 63 60 63;
#P connect 24 0 22 0;
#P fasten 37 0 0 0 199 148 60 148;
#P fasten 3 0 0 0 140 598 35 598 35 195 60 195;
#P connect 22 0 0 0;
#P fasten 35 0 0 0 260 347 116 347 116 598 35 598 35 195 60 195;
#P fasten 6 0 0 0 149 208 60 208;
#P fasten 17 1 0 0 578 102 60 102;
#P fasten 26 0 0 0 513 158 60 158;
#P fasten 29 0 0 0 512 211 512 219 60 219;
#P connect 0 0 19 0;
#P connect 19 0 21 0;
#P fasten 0 1 20 0 100 262 82 262;
#P hidden connect 19 1 20 0;
#P fasten 20 0 21 1 82 400 94 400;
#P connect 0 2 2 0;
#P connect 2 0 1 0;
#P fasten 26 1 1 0 582 482 140 482;
#P connect 1 0 5 0;
#P connect 5 0 3 0;
#P connect 0 3 9 0;
#P connect 9 0 11 0;
#P fasten 38 0 37 0 176 143 190 143 190 121 199 121;
#P connect 0 5 15 0;
#P connect 15 0 14 0;
#P fasten 29 1 14 0 582 288 260 288;
#P connect 14 0 35 0;
#P connect 9 1 10 0;
#P fasten 22 1 0 1 85 226 262 226;
#P connect 4 0 3 1;
#P connect 16 0 17 0;
#P connect 17 0 18 0;
#P connect 18 0 27 0;
#P connect 27 0 26 0;
#P fasten 18 0 30 0 513 102 485 102 485 165 513 165;
#P connect 30 0 29 0;
#P pop;