Max Tutorial #11: Modular Synthesis

This tutorial builds on Tutorial #8, in which we first used the keyboard as a synthesizer interface. (If you haven’t watched it yet, I encourage you to check it out first.) We’ll continue to improve our synthesizer by dividing it up into its component parts, or modules. This is the first step towards what is more commonly known as “modular” synthesis, where, instead of thinking of a synthesizer as a single, one-way chain of audio from source to output, we think of the different parts of the synthesizer as building blocks that be arranged and connected in many different ways. We’ll also start to use MIDI velocity values to control the volume of our synth.

We’ll start off by using the [notein] and [kslider] objects as before. Plug in your MIDI controller if desired. This time, instead of only using the pitch output of [notein], we’ll also use the velocity output (middle outlet). As you’ll recall, MIDI velocity is often used to control volume. So we’ll have a modular system that is also velocity-sensitive: depending on how hard you press the keys, the volume will be louder or softer. (As before, if you do not have a MIDI keyboard, you can click directly on the [kslider] object. Clicking towards the top of each key results in a higher velocity value, and towards the bottom gives a lower velocity value.)

If you’re clicking on [kslider] with the cursor, you’ll notice that each click activates that key, but we don’t have a way of explicitly turning off notes (i.e. sending a note off message). We can enable this functionality by changing the [kslider] object’s display mode. In the past, we have changed attributes like this by using the Inspector. However, we can also use an object called [attrui] to change an object’s attributes. Simply connect [attrui] to [kslider], and the [attrui] menu will populate with the same attributes that appear in the Inspector. Lock the patch to browse the menu. We’ll switch the Display mode from “monophonic” to “touchscreen,” so that now when we unclick a key it send out a note off message (velocity = 0), which will stop the note.

Now we can proceed with our synthesizer, using the same objects we’ve used before. However, this time we’ll multiply the output of our oscillator [saw~] by the velocity value so as to control its volume. Just as pitch is assigned to a range of 0-127 in the world of MIDI, velocity also ranges from 0-127 (where note off = 0). Next, just as we have to convert MIDI pitch into frequency recognizable by digital audio objects (such as [saw~]), we have to convert MIDI velocity into an amplitude value in the range from 0 to 1. Therefore, we divide by 127: a value of 0/127 gives us 0 (no sound), and a value of 127/127 gives us 1 (maximum volume). We’ll use the [/] (division) object with an argument of “127.” (we need the “.” to ensure that the output is a decimal, since all values will be between 0 and 1).

Now that we have velocity integrated into our synthesizer, we can start to modularize it. One important set of tools for working in modular fashion in Max is the [send~] and [receive~] pair of objects. These allow you to take any audio signal (output of any object ending in “~”) and wirelessly route it to any other with the same argument. In this case, we create objects with the matching argument “synth_sound” and split our audio signal between the output of the synthesizer and the [gain~] object. Now we can move different parts of our synth around in the patch, but they remain connected. (It also helps us keep our patch tidy!)

We can also send control data around the patch wirelessly using the control-rate equivalents [send] and [receive]. We can use it to send our pitch values (we’ll use the argument “pitch”) as well as our velocity values (“velocity”). The argument names I’ve chosen are rather generic—you can name your [send] and [receive] pairs (almost) anything you like, as long as it does not contain spaces or any restricted characters. We can also use the shortcuts [s] and [r] instead of typing out the whole words “send” and “receive” (just like using [t] for the [trigger] object).

At this point, you’ll probably notice that we have three completely separate elements in our patch: the keyboard, the synthesizer, and the output. They are connected wirelessly, which makes our patch look cleaner, and also allows us to rearrange things as we choose. Now that we’ve divided our patch by function, we can start to think about it from a modular perspective, and encapsulate specific parts of the patch into subpatches. Usually this is useful for groups of objects that aren’t part of the user-facing interface.

Since we need to keyboard to enter notes, and we need the output module to control the volume, let’s encapsulate the internal synthesizer bits ([saw~], [*~], etc.). Simply select the objects you’d like to encapsulate and then click Edit -> Encapsulate (or command+shift+E). You’ll see a new object simply called [p]. It is customary to name subpatches to describe their contents. We’ll call ours [p synth_voice]. Make sure to follow the same naming conventions as for the [send]/[receive] objects (no spaces), and be sure not to get rid of the “p”! The [saw~], [*~], and [receive] objects are no longer visible, but if we test our synth, it still works! Lock the patch and double-click on [p synth_voice] to view its contents. In the next tutorial, we’ll use these techniques to build a polyphonic synth!