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 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
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 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 messages from its outlets in right-to-left order. The number of outlets is determined by the argument to bangbang
(in this case, the 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 (for list), (for ), (for integer), (for symbol – a text message) and (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 . 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 , since our arguments for trigger were are of type (integer).
The next patch to the right also uses an incoming integer message (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 (integer), produces an unchanged output. The middle outlet, set to type (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 ( ), accepts the incoming message but turns it into a . So, in addition to making the message order explicit, the trigger
object can do type conversion of messages.
), and is connected to a
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 outlet – a is a , regardless of incoming message type.
Now would be a good time to build some more button
matrices, but combining them with trigger
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
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
to make the ordering explicit. In all cases, however, you need to watch out for structural loops – they are literal patch-killers!
Send a bang to many places, in order
Send input to many places, in order