20Concepts Lesson 10 - Presets and The Pattr Object
(Needed: Example Video)
One of the things that everyone wants to do is to store the "state" of their patch so it can be restored when a patch is opened. If there is the chance of having more than one useful state, having multiple presets is even more valuable. Max provides a simple means of storing states - using the preset object - it has some limitations for external storage and content management. Therefore, it is important to consider a Max subsystem that offers significantly more flexibility: the pattr object.
(Needed: Fixture Patches with download)
The Pattr Object
Working with preset content in Max is all about learning to work with the pattr object. This object manages connections to your on-screen UI objects, maintains a set of preset "slots" to select, and interacts with other objects for the storage and communication of the preset data. Perhaps the best way to learn about the pattr object is to review a set of videos created by Gregory Taylor that maps it all out:
- A pattr Quick Start: [Tutorial #1]
- Sharing and storing: [Tutorial #2]
- Pattr preset morphing: [Tutorial #3]
Once you've reviewed these tutorials, we can start building toward our example patch.
More about autopattr
Now that we've learned about the overall use of pattr, let's look into some details. First, the important autopattr object. One important part of the autopattr autonaming function is that it just uses the object's default name, and adds an array index (such as ) after similar objects after the first. If you want to manage the names better, you need to name the object before you instantiate (create) the autopattr object.
Secondly, if you want to exclude a control from the autopattr default management, you need to connect this object to the second outlet of the autopattr (as with the above patch). This is useful for controls that select a preset from a pattrstorage object, or when you have controls (like a master volume control) that shouldn't change from preset to preset.
Finally, if you add an object to the patch after you've created the autopattr object, you will need to either reload the patcher (by saving, closing and reopening the patch) or reinstantiate the autopattr object (normally by editing the content of the object box). This will cause autopattr to rerun its collection of objects, do any necessary naming (if @autoname is set to 1) and add new objects to the internal pattr system.
More about pattrstorage
You'll notice that even in the simplest pattr example (above), I'm using the pattrstorage object. That's because pattrstorage maintains the majority of preset-like functions as well as providing us with ways to interact with the stored information. In the patch above, we are using it to give us a display window for the results of the autopattr object - we get the display window by double-clicking on the pattrstorage object box. In this window, we can see all of the attached objects, the order of preset loading, the way that interpolation will be performed and the current value of the object. This information is critical for proper use of the pattr system, and it is only through the pattrstorage object that we get easy access to it.
Another area we should discuss is the use of the @greedy attribute for a pattrstorage object. In the second of the pattr videos, Gregory describes the use of the @greedy attribute to pull information from subpatchers that have a pattrstorage object within the subpatch. This is important: the @greedy attribute is only necessary when subpatchers already have pattrstorage objects gathering the contents within that subpatcher (and therefore doesn't not have to pass the data to any parent patcher).
When would we see something like this in use? A good example is when a bpatcher (like the filtering bpatcher in Gregory's video) has a number of presets that help us have fun whenever we reuse the filtering bpatcher. However, when we use this bpatcher in one of our master patches, we will certainly want to save the current filter settings at the parent patcher level (as part of an overall instrument preset, for example). By using the @greedy attribute in this case, we are able to gather all of the filter settings into a preset at the parent patcher level, but we don't have to further edit the bpatcher in order to grab all of the data. This is a powerful feature that can allow you to create complex-but-reusable elements in your patching environment.
Note: A good example of this is the way a preset can work within the various bpatchers in the Vizzie abstraction collection.
This is a work in progress...
Rerouting Data using pattr
One side-benefit of using the pattr/pattrstorage system is that we can use it to reroute data to different destinations. Here is an example patch:
In this case, I've provided scripting names for the three number boxes: numbox_left, numbox_middle and numbex_right. Now, using the umenu, I can select a destination and let the pattrstorage object perform the data routing for me. This is very useful when you want to simplify the use of a single controller to manipulate several different values - but only one at a time.
Creating Complex Controls using Preset Morphing
One of the interesting side benefits of of preset morphing is the ability to create modulation activities that are more complex than would be possible unassisted. A good example is to use a single slider (in this case, the horizontal one) to move eight sliders simultaneously. This transforms a single control movement into a complex multi-faceted 'gesture' that can manage many other objects in a coordinated fashion.
You can download the patch, along with its preset file (called gesture.json) from this link:
- Create a music player that uses pattr presets to select DLS patch numbers, appropriate octaves and appropriate volume levels.
- Create a morphing patch that mixes several music players (using the MIDI CC 7 Volume Control) with a single slider. Animate that slider.
- Create a routing patch that uses message rerouting to shoot random numbers between 5 different number boxes.