Tutorial 14: Encapsulation
Introduction
This tutorial will cover the concept of encapsulation within Max. Encapsulation allows us to place sections of our patcher within their own subpatch using the patcher object. This lets us hide parts of patcher logic that we no longer need to see, in order to make our projects easier to read and more concise. We will examine the creation of a patcher that contains objects, as well as using some editing tools to encapsulate parts of a patcher that no longer need to be seen.
Properly encapsulating your Max logic is important for keeping your patch files clean, easy to read and maintainable. Encapsulated logic can be easily edited, and can also be saved as separate files that can be reused in other patches.
To open the tutorial patch please open 14mEncapsulation.maxpat
from the the zip archive, which is available for download at the top of this page.
Basic encapsulation
At the top-left of the tutorial, there are two small patches that do the same thing – they both add 5
to the incoming number
. The patch on the left does it with a + object, while the patch on the right uses a patcher object. The patcher object (which can be abbreviated "p", much as trigger can be abbreviated "t") is literally another patch embedded in the current patch. To see the contents of a patcher object, you can double-click on it (when the patch is locked) to open the encapsulated patcher object's window.
If we double-click on the patcheradd5
object, a small patcher window shows the contents (in a window labeled add5
- the name of the subpatch). It is a simple subpatch, with only three objects. The object in the middle is obvious – it is the + object that performs the addition. The objects above and below the + object are inlet and outlet objects, respectively. An inlet object causes the enclosing patcher object to have an inlet, while an outlet object causes the enclosing patcher to have an outlet. In this way, we can make patcher objects that act very much like built-in Max objects. Multiple inlet and outlet objects will create corresponding inlets and outlets on the enclosing patcher object, arrayed spatially in relation to how they are in the subpatch (e.g. the leftmost inlet object in the subpatch will correspond to the leftmost inlet on the patcher).
When working with inlet and outlet objects, it is useful to add assistance to them; in this way, the enclosing patcher can display helpful information about the type of message that is expected by the inlet, or produced by the outlet. If you select an inlet or outlet and then open the object’s Inspector, you will see that there is a comment
field available. Any text that you enter in this field will show up as assistance in the patcher object during patch editing.
Performing encapsulation
Creating sub-patchers sometimes needs to happen after the logic is in place; perhaps your patcher has expanded beyond where you originally thought it would go, or you’ve added logic that wasn’t planned, and things are starting to get messy. In these cases, it would be useful to be able to select a group of objects and quickly turn them into a single encapsulated patcher. This can be done using the Encapsulate menu item.
Our example patch has an interesting drawing algorithm, where you move a puck around a rectangular area (using an object called the pictslider), and small circles are drawn in the area randomly near the equivalent position in the lcd at the bottom of the patch. If you need to clear the lcd, you can hit the space bar (ASCII character 32
, captured by the key object and triggered by the select object). The logic is rather messy, and it doesn’t really help us to see it spread around the screen. We are going to select a majority of the logic and encapsulate it into a subpatch.
There are two comment boxes (“encapsulate from here” and “to here”) that we will use to select our encapsulated logic. Unlock the patcher, then select (using click-and-drag) all of the objects between and to the right of the comment boxes. 15 objects will be selected. Select Encapsulate from the Edit menu, and you will see that all of this logic is folded into a single unnamed patcher patcher. If you lock the patch and double-click the patcher object (or command-double-click in an unlocked patcher), it will open the subpatch and show all of the objects again, tied to the outside world using four inlet objects and one outlet object. If, for some reason, we needed to reverse this process later, the De-encapsulate command under the Edit menu will unravel the subpatch back into our main patcher, re-connecting everything correctly as it was originally.
It is often useful to name our patcher objects; while this adds no particular value to the patcher, it will help you (and others) understand the logic that is encapsulated into the object. To name it, just click inside the object, and add a first argument that is the name you’d like to use. Something like draw_logic
would be perfectly useful for this example.
Creating our own subpatcher
When you know ahead of time that you want to work within a subpatch, it is easy to create a patcher object and work within its editing window. At the lower-left is a pair of number boxes connected by – nothing. We will make a subpatch here and use it to convert one value into another.
Create a new, blank object in between the number boxes by parking the mouse there and typing "n". In the new object box, type p mycalc
- this will create a new patcher named mycalc
. A new window will appear for editing our new subpatch. Start with an inlet and outlet (both available under the Add Object
icon in the top toolbar). Note that adding these to the patcher added and inlet and an outlet to the patcher object in our main window. Next, connect the inlet directly to the outlet – thereby making a “thru” object that does nothing except pass incoming message to the outlet. Let’s test this encapsulation in the main patcher window.
Now that our mycalc
patcher object has an inlet and outlet, we can connect it to the number boxes. Connect the top number box to the patcher inlet; connect the patcher outlet to the bottom number box. Lock the patch, and change the top number box: we should see the bottom number box change to match. This shouldn’t be a surprise, since our patcher object encapsulates a straight line between the two boxes!
Let’s go back to the patcher editing window and add some logic - if the window has closed, double-click the patcher object to open it up again and unlock it. Start by selecting and deleting the patch cord connecting the inlet and outlet. Now, let’s add some math: create two new objects, a +50
object and a /7
object. Now, connect the inlet to the + object, the + to the / object, and the output of the / object to the outlet. We’ve changed our mycalc
encapsulation from meaningless subpatch into an “(input + 50) / 7” patcher. The nice thing about doing this within an encapsulation is that we don’t have to change anything in the top-level patcher – all of the connections remain as-is. Now, at our main patch, changing the top number box will produce the new result without any further changes.
Summary
Encapsulation of patching logic accomplishes two things:
- it allows us to work at higher levels without having to interact with (or even see) all of our objects; and,
- it allows us to change our lower-level logic without having to change anything at the higher-level programming.
In working with patcher objects, you can either manually create and populate them, or you can select existing patcher logic and use the Encapsulate menu option to automatically create a subpatch. In either case, you can further explore and change the patcher code without any further changes to the higher level patch.