So far in these tutorials, all messages between objects have been sent using patch cords. However, there is another way to transfer messages between objects – by using the
remote messaging mechanism built into Max. There are specific objects for this (called, not surprisingly,
send and
receive), as well as methods for sending a
message box's contents to an object. Finally, we use some objects that allow the storage of variable data, and can help use move values throughout complex patches.
As our patches get more complex, we need to take advantage of more techniques to modularize and compartmentalize our patches, making them easier to understand, maintain and extend. When our patches contain a lot of logic, maintaining patch cord connections can cause unnecessary visual complexity. Using tools that allow message passing without patch cords can clean up our patches without changing how they operate.
The most common way to send messages without patch cords is through the use of the
send and
receive objects. If we look at the tutorial patcher, the top left part of the patch shows a pairing of
send and
receive objects that pass an integer value. When we change the top
number box, the integer value is passed to the
send fred object. This value is “broadcast” throughout the Max environment, and can be “received” by any
receive object with the name
fred. In this case, the
receive fred object immediately below gets the message, and outputs it to be displayed in the attached
number box.
Since a message is broadcast by
name, any
receive object sharing the
send object's
name can receive the message. Hence, you can have more than one
receive object for a message, and more than one
send object sending messages using a single
name. In our test patch, the
slider system connected to the
send bob object does just that – it sends the value (set with either the
slider or the
number box) to all
receive objects of
bob messages. At the lower right of the patch are two different
receive bob objects: one connected to a
slider system, while another is connected directly to a
number box. Changing the top
slider value changes both of the receiving values simultaneously.
When working with pairs of
send and
receive objects, it’s important to realize that the message will be grabbed by any
receive object anywhere in the Max environment – even in another patcher. To test this, open a new patcher (selecting
New Patcher from the
File menu). Add a new object, and enter
receive bob. Connect the output of the
receive object to a
number box, then return to the tutorial patch. If you change our test
slider, you will see the output received in the new patch as well as all other
receive bob objects in the main patcher.
When working with other people’s patches, you may see objects named “s” or “r”. Since the
send and
receive objects are so popular, they have
alias (or shorthand) names of “s” and “r” respectively. In addition to being easier to type, these shortcut names also allow you to keep the object small in size!
Another common use of remote messaging is to send the contents of a
message box to one or more
receive objects. Rather than always having to connect
message boxes to
send objects, there is a special format of the
message box that can directly send messages to
receive objects. This involves placing a semicolon (
;) and the
name of a
receive object in front of the message. Thus,
; bob 155 is the equivalent of sending the value
155 to any
receive object named
bob.
The large
message box at the bottom-left of the patch is an example of direct message sending. Four messages are generated: two are sent to
lcd1 destinations, and two are sent to
lcd2 destinations. If you click on the
message box, you will see that the two
lcdobjects each receive the appropriate draw commands through their respective
receive objects - the top
lcd (
lcd1) draws a blue circle; the bottom
lcd (
lcd2) draws a green rectangle.
Another common need we might have is to send messages to one of several destinations based on some logical criteria. This can be done using switching logic (e.g. the
gate object connected to different
send objects). However, we can also use the
forward object to route messages to selected locations. Just above our
message box example is a
forward object with supporting logic.
You can select which named destination should receive the messages: the
send message, sent to the
forward object, will set the destination name for any incoming messages. Once a destination has been set, you can send in messages to be routed appropriately. If we click on the
send lcd1 message, changes to the
number box will cause a colored rectangle to be created in the first
lcd object. If we click on the
send lcd2 message, it changes the output destination of the
forward object to the
receive lcd2 object. Now, any changes to the
number box will cause the creation of a rectangle in the second
lcd object.
By a similar token, a
receive object with
no arguments can be used to receive messages from any named
send or appropriately configured
forward or
message box. The
set message to the
receive object allows it to "switch names", so to speak, so that it can listen to different parts of the patcher. Next to our
forward object is one such
receive object. By switching it between listening to
bob and
fred (using the
message boxes) and then manipulating the
number box and
slider object sending to those names, we can see how this works. Setting the
receive to a
name that doesn't exist (e.g.
none) will disconnect it from listening to anything in our patch. Note that in order for a
receive object to be "switchable", it needs to be created
without an argument (otherwise it has no inlet).
Sometimes, when working with patch programming, we need a place to “stash” a value until we need to use it. While we could use integer and floating-point
number boxes, those objects have the possibility of having the user change the value through their UI. In order to provide simple variable storage and recall, there are a set of objects specifically used for this purpose. The
int and
float objects can act as temporary storage of values; values coming in the
left inlet are stored and sent out the outlet immediately, while values coming in the
right inlet are stored without output. If you want to retrieve the value stored in an
int or
float object, you need to send a
bang message (such as from a
button object) into the left inlet.
One of the advantages of the
int and
float objects is that you can initialize the value without using any other message. The argument provided with the object gives it an initial value; there is no need to set these up with
loadbang messages or other functions. If we look at the
int and
float objects to the right of our patch, we can see how they work. Sending a
bang into them with the
button objects outputs their initialized value. Once we start entering numbers into them from the
number boxes, those new values are stored inside the objects until we
bang them again.
In our patch, just below the
int and
float object, we find a pair of objects called
value. The
value object is like a combination of an
int/
float object and a
send/
receive pair – each of the
value objects has a
name (in this case,
joe), and any values placed in one of the objects is shared with all of the other
value objects with that
name. One thing to notice is that sending a message into a
value object does not trigger output – you need to explicitly force output by sending a
bang message to the object. In our test patch, change the value of one object then
bang the other: you will see that the value is magically transferred from one to the other.
Unlike the
int and
float objects, the
value object can take messages of
any type; symbols, integers and floats can all be stored by the
value object, as can a list. While this is convenient, it also means that you need to be careful about the objects that you connect to a
value object to display the output. Our test patch has
number boxes connected to the value objects; however, it might be better to connect a
print object or other display object that can accept a diverse set of values.
Being able to send messages without having to connect patch cords can give us more flexibility in patch layout, and can also allow us to produce and route very complex messages throughout our patches. The
send and
receive objects are the most common way of passing messages around a patch, but the use of
; notation in
message boxes and the use of the
forward object for routing can help minimize the visual complexity of our work. Finally, we saw how values can be stored in the
int and
float objects, and how a
value object can be used to both store and forward data that is sent into it. All of these objects and techniques are important for working with complex patching systems.
See Also
Name |
Description |
send |
Send messages without patch cords
|
receive |
Receive messages without patch cords
|
forward |
Send remote messages to a variety of objects
|
int |
Store an integer value
|
float |
Store a decimal number
|
value |
Share a stored number with other objects
|