Attributes are a new way to specify the behavior of Max objects. Most Jitter objects use attributes for the different variables that make up their current internal state.
Many Max objects, such as the counter object shown above, take a number of arguments to determine how they behave. The order of these arguments after the object's name determines how the object interprets them. In the example above, the first argument to counter sets the direction in which the object counts; the second and third arguments determine the minimum and maximum values that the object counts between. Since these values are simply given to the object as numbers, their ordering is important. With some Max objects (counter is one of them) the number of arguments you give has some effect on the way in which they are interpreted. If you supply counter with only two arguments, they will be understood by the object as the minimum and maximum count, not the direction and minimum count. Because the position and number of arguments are crucial, there is no way, for example, to create a counter object with a predefined direction and maximum count using only two arguments.
The arguments to an object are often seen as initial values, and Max objects typically have ways to modify those values through additional inlets to the object or special messages you send the object. You can change the direction and maximum count of a counter object by sending integers into its second and fifth inlets, respectively. These will override the default values supplied by the arguments. Similarly, you can change the minimum count of the object by sending the message min followed by an integer into the left inlet.
While this system works well when a Max object only has two or three variables that define its behavior, Jitter objects often have many, many more variables (sometimes dozens). If all of these variables depended on the order of inlets and object arguments, you would spend all day searching the reference manual and never have time to do any work with Jitter!
Jitter objects, unlike Max objects, can be told how to behave by using attributes. You can type attributes into an object box along with the Jitter object's name, or you can set (and retrieve) attributes through Max messages after the object is created.
The Jitter object shown above, called jit.brcosa, has three typed-in attributes. Typed-in attributes are set in object boxes by using the symbol followed by the name of the attribute and one or more arguments (which could be any kind of Max data: ints, floats, symbols, or lists). You can enter as many attributes as the object recognizes, in any order, after the object's name. While you may not know what the jit.brcosa object does yet, you can infer a little bit about the object based on the names of the attributes and what type of data they have assigned to them.
As with Max objects, the information you give a Jitter object to set its initial behavior is generally something you can change after the object is created. Attributes can be changed at any time by sending messages to the object as shown below.
This jit.brcosa object has its attribute set to . initially (typed into the object box as '@brightness 0.5'), but we can change it to something else by sending the message into the object's left inlet. You can change virtually any attribute by sending a message with the attribute's name, followed by the relevant arguments, into a Jitter object's left inlet.
As with Max objects, Jitter objects have default values for their parameters. The jit.brcosa object above only has typed-in attributes initializing its value, but other attributes are set to their default values. We’ll show you how to find out what attributes an object uses below. In the example above, we can change the values of the object's and attributes using messages, overriding whatever default values the object has supplied.
Jitter Object Arguments
There are four pieces of information that most Jitter objects use that can be entered either as typed-in attributes or typed-in arguments. In fact, they are always attributes, but Jitter objects automatically handle them correctly when they are used as arguments.
The jit.rota object, shown above, clearly has two attribute initialized: and . But what does the other stuff mean?
If you supply arguments for a Jitter object that processes Jitter matrix data (and most Jitter objects do), the arguments are interpreted as:
- The of the output matrix.
- The of the output matrix.
- The size, or 'dimension list' ( ), of the output matrix.
Now that we know this, we can determine that the jit.rota object above will output a matrix that is made up of planes of (8-bit integer) data with two dimensions of by cells.
These arguments can also be set by attributes that are consistent for all Jitter objects that output matrix data:, , and . They can be set as unordered typed-in attributes or changed with messages. The three objects below, for example, are identical.
The first object has its output matrix attributes set using typed-in arguments. The second object has theand set using typed-in arguments, but uses a typed-in attribute for the dimension list. The third object uses a typed-in attributes to set everything.
If you prefer, you can initialize an object-s attributes using messages triggered from a loadbang object as shown below.
Querying Attributes and Object State
The quickest way to find out an object's attribute settings is by consulting the inspector window. This is available by selecting the object and keying command/alt i or by clicking the i icon on the right toolbar. You will find current attribute settings near the bottom of the window.
An additional (and very useful) feature of attributes is that you can ask a Jitter object to tell you what value it currently has stored for any given attribute. You do this by querying the attribute with the Max messagefollowed (with no space) by the name of the attribute you want to know about. The resulting value is output by the Jitter object as a message (beginning with the attribute's name), sent out the object's right outlet.
Using jit.plur object. The Max route object lets you easily separate the values for each of the attributes.to find the values of attributes lets you discover the current value of an attribute, even if you never set the attribute in the first place. For example, the patch below discovers some of the default values of the
Two messages you can send to any Jitter object,and , output all the attributes used by the object.
The jit.brass object) will have special meaning for the object that uses them.message causes the Jitter object to output the message followed by a list of all the attribute symbols that Jitter object understands. Experimenting with a few Jitter objects will quickly show you that many of these, such as , and , are fairly standard. Others (such as mask in the
Themessage dumps out all the attributes for the Jitter object as if every conceivable attribute query had been performed all at once.
You can then use route, unpack, and other Max objects to extract the attributes as you need them. Later in the tutorials, you will encounter several Jitter objects where the attributes change based on calculations performed on the input matrix (or a file that has just been opened by the object). Querying the relevant attributes is how you can find out the result of the object's calculation.
You can also read attribute values with the attrui object. This is a user Interface widget that seems to be connected to the inlet of an object but actually has two-way communication. The attrui object has two sections—the left section is a pull-down menu with all of the connected object's attributes available. Once an attribute has been chosen, the right hand side shows the current value of the attribute and allows you to edit it.
Jitter attributes are a powerful tool for managing the parameters of complex objects. You can use attributes to initialize, change, and find out the current values stored in Jitter objects, and the attachment of each value to a fixed attribute name eliminates the need to remember typed-in argument ordering or the role of each inlet in a complex object.