This tutorial is focused on message ordering – the sequence in which messages are passed from object-to-object and how objects generate them. We will also use some of the debugging tools in Max to determine how a patch is running.
Max patches often seem to have everything happening at once; in reality, messages are produced and acted upon in a specific order. In order to make patches that operate correctly, we need to understand the order that things are occur, and how to control complex matrices of actions.
Take a look at the tutorial patcher. This file has a number of small patches that we will use to learn about the rules that messages follow. Click on top-most
button in the top-left patch; it seems that all three of the connected
button objects fire simultaneously. This is an illusion – messages are sent down the patch cables in a sequential order.
The easiest way to see this in action is to use some of the debugging tools in Max. You'll notice that the top row of patches in the tutorial have small red circles with numbers in them covering the patchcords. These are called watchpoints (specifically - breakpoint watchpoints). When we debug our patcher, we can use these watchpoints to stop the execution of the patch at a specific point. This is done by enabling the Max Debugger. Select Enable Debugging from the Debug menu. Once debugging is enabled, these watchpoints will help us see the way messages are passed in our patcher.
Click on the topmost
button in the left-hand patch. Instead of the immediate "flash" of all the
button objects lighting up, the
rightmost patchcord begins blinking red. In addition, a window opens called the
Debug Window. Looking at the window, you can see what kind of information it gives us. The window tells us that a
bang message has been intercepted by a watchpoint; moreover it tells us which watchpoint was tripped (in this case, watchpoint #1), the name of the patcher and what class of object the sending and receiving object was (in this case, both are
button objects). Select
Step from the
Debug menu (or press Shift-Command-T). You will see that the middle cord flashes; select Step again and you will see that the left-most cord flashes. Select Step once more to finish our patch trace. When the outlet of an object is connected to more than one inlet, the messages are sent in
right-to-left order.
But what happens when the receiving objects are stacked vertically (and therefore at the same horizontal position)? With debugging still enabled, click on the topmost
button in the middle patch on the top row. As the watchpoints fire, select Step from the Debug menu. When we Step through the patch, we see that the bottom-most
button receives its message first, follow by the middle, then the top. So, we can see that Max has two levels of ordering: right-to-left, then bottom-to-top.
There is one more twist to message ordering, and that is the effect of messages that cause more messages to be generated. The third patch illustrates the issue. Click on the top-most
button and Step through the order of the messages. By tracing through this matrix of
button objects we see that messages travel through the entire
depth of one message chain before sending a message to the next "branch" of objects. Notice that the Debug Window shows you the length of each message chain in a branch; it only clears when a branch has been completed.
Therefore, the message-ordering rules in Max are:
1. Right-to-left, then bottom-to-top.
2. Depth-first traversal of connected objects.
Note that, for determining the right-to-left or bottom-to-top ordering, it is the location of the connected object, not the location of the patch cords, that determines the message route.
As an exercise, create a new matrix of
button objects, with both vertical and horizontal arrays of
button objects (perhaps using the
Align option from the
Arrange menu), and multiple depths of objects. Use
comment boxes to number the boxes in the order you think they will fire then trace the patch. Do this until the message ordering becomes second nature!
Select Disable Debugging from the Debug menu, and let's look at the other patches in the tutorial patcher.
Sometimes it is inconvenient to match the spatial order of the patch with our desired result. In the bottom row of patches, the left-most patch is well structured: it is cleanly laid out, and has the
number boxes in ascending numerical order from left to right. If we wanted the messages to go from low to high, it is also wrong; when we click the top
button, we see the numbers come out in reverse order in the Max window. This is because the
message boxes are receiving
bang messages in right-to-left order.
The next patch shows a corrected version of this patch, using a new object:
bangbang. This object takes an incoming message and produces
bang messages from its outlets in right-to-left order. The number of outlets is determined by the argument to
bangbang (in this case, the
3 argument produces three outlets). The outlets are connected to the
message boxes in the appropriate order; when we click on the top
button, the Max window displays the messages in the preferred order.
Notice that the outlets of
bangbang fire in right-to-left order, mimicking the message ordering of the patch itself. Most objects with multiple outlets will follow this rule: output is from the right-most outlet to the left-most outlet.
Use the
bangbang object makes the message order explicit; that is, it forces the messages to follow a specific path regardless of spatial orientation, and lets us place objects anywhere we want in the patch, knowing that they will be triggered in deterministic order based on which outlets we trigger them from. Another message that provides explicit ordering is the
trigger object. The
trigger object accepts input, and outputs messages based on its arguments. The arguments determine the
type of output, with options of
l (for list),
b (for
bang),
i (for integer),
s (for symbol – a text message) and
f (for floating-point number). You can also use specific integers, floating point numbers or symbols as constant outputs.
The next patch contains two
message boxes with the integer
90. If we click on the one connected directly to the
print objects, the Max window displays the typical right-to-left ordering of messages. However, if we click on the
message box connected to the
trigger object, we see that we can control the output to
print in left-to-right (reversed) order. The sent messages are all printed as the integer
90, since our arguments for trigger were are of type
i (integer).
The next patch to the right also uses an incoming integer message (
90), and is connected to a
trigger object (using the object abbreviation: “t”). However, in this case, three different arguments are used. When we click on the
message box, we see that the output of the three outlets are all different, matching the difference in arguments. The right-most outlet, with argument of type
i (integer), produces an unchanged
90 output. The middle outlet, set to type
f (for floating-point),
casts the incoming message to its floating-point equivalent (90.000000) and sends it to the
print object. Finally, the left-most outlet, of type
b (
bang), accepts the incoming message but turns it into a
bang. So, in addition to making the message order explicit, the
trigger object can do type conversion of messages.
The right-most patch shows the use of constant values within the
trigger object. When we change the floating-point
number box to any number, the trigger object again converts the incoming number, but also includes a number of symbols (text messages) that are used as constant values. We also see that the incoming message did not change the output of the
bang outlet – a
bang is a
bang, regardless of incoming message type.
Now would be a good time to build some more
button matrices, but combining them with
trigger and
bangbang objects, and labeling them with their expected message order.
The final patch in our tutorial file is a set of four
button objects all interconnected in a loop. When we click on any of the
button objects, the system comes to a halt with a
stack overflow error. Why did this happen? Remember that Max does a depth-first prioritization of messages. However, a looped patch construction has an infinite depth, and therefore cannot be properly parsed. One
button sends to the next, which sends to the next, which sends to the next, which sends to the first, triggering the cycle all over again. Click
OK to get rid of the error dialog. When a stack overflow occurs, Max shuts off its scheduler to prevent anything else from happening; once we've found the problem and corrected it in our patch (e.g. by disconnecting one of the
button objects in the loop), we can turn the patch "on" again by clicking
Resume under the
Edit menu.
A deep understanding of message ordering rules is necessary to create properly functioning patches. The right-to-left, bottom-to-top, depth-first order is the implicit rule for message passing, but you can use objects like
bangbang and
trigger to make the ordering explicit. In all cases, however, you need to watch out for structural loops – they are literal patch-killers!
See Also
Name |
Description |
bangbang |
Send a bang to many places, in order
|
trigger |
Send input to many places, in order
|