In this tutorial we'll learn how to use the jit.matrix
object to write matrix data from multiple sources into the same matrix. We'll also look at how to scale the size of matrices when they are copied into a new matrix, and how to use the Max low-priority queue to de-prioritize Max events in favor of more time-consuming tasks .
attribute of the
The tutorial patch is divided into five colored regions. The middle (light blue) region contains two jit.qt.movie
objects. A loadbang
object reads two movies (rain.mov
) into the jit.qt.movie
objects when the patch is opened:
Unlike the tutorial patches we've looked at before, the jit.qt.movie
objects in this patch use send
objects to communicate with the rest of the patch. The receive
objects named and forward messages to the two jit.qt.movie
objects. The output matrices of the two objects are then sent (using send
objects) to receive
objects named and elsewhere in the patch.
The yellow region at the top of the patch contains the metro
object that drives the Jitter processes in the patch:
• Click the toggle box to start the metro
. The three jit.pwindow
objects in the patch will start to display an image.
object goes through a Ggate
object and an object called jit.qball
(about which we will have something to say later) into a gate
object. The messages sent by the metro
are routed by the gate
to one of two message
boxes. Our final output matrix (in the jit.pwindow
at the bottom of the patch) will change depending on which message
box gets a .
• Click the two message
boxes attached to the left inlet of the gate
( and ). Notice how the jit.pwindow
at the bottom changes:
The final output matrix changes depending on the message ordering of the patch.
The two message
boxes both send messages to the same three named receive objects ( , , and ). The difference between the two is the order in which they send the messages. The lefthand message
box (driven by the metro
when the gate
is set to 1) sends the first to the jit.qt.movie
object (with the rain movie). Finally, the jit.matrix
object at the bottom of the patch receives a , causing our final matrix to be sent out. The righthand message
box (driven by the metro
when the gate
is set to 2) reverses the order of the two messages driving our jit.qt.movie
objects (the left jit.qt.movie
outputs a matrix first, followed by the right jit.qt.movie
The order in which these messages occur only becomes relevant when we look into what happens between the two jit.qt.movie
objects and the final jit.pwindow
Once our jit.qt.movie
objects receive their messages, they output a matrix to the send
objects below them, which in turn pass their matrices over to receive
objects named and . The receive
objects (in two identical regions at the right of the patch) are connected to jit.pwindow
objects as well as two named jit.matrix
Both of the jit.matrix
objects at the right of the patch (as well as the jit.matrix
object at the bottom of the patch above our final jit.pwindow
) have a . The attached to all three of these objects is . The result of this is that all three of these jit.matrix
objects share the same
matrix data, which is contained in a Jitter matrix called .
Once we know that our two jit.qt.movie
objects write data into the same Jitter matrix (via two separate jit.matrix
objects sharing the same ) we can understand why the ordering of the messages is important. If the left jit.qt.movie
sends out its matrix first, it writes data into the matrix, followed by the right jit.qt.movie
, which writes data into the same matrix. If the two matrices write to any cells in common (see below), the matrix that gets there last will overwrite
any data that was in those cells before.
Important Note: If you are ever unsure about the order in which things are happening in your Max patch, you can do a Trace of the patch to see the way in which your patch executes. If you choose the Enable
command from the Trace menu, and then turn on the metro
object, you can step through the patch with the Step
command (�-T), to see how it executes. (See the "Debugging" chapter of the Max Tutorials and Topics
manual for details about how to trace Max messages with the Trace feature.)
The two jit.matrix
objects on the right of the tutorial patch have their attribute set to . This allows us to scale the matrices sent by our jit.qt.movie
objects so that they only write to a certain region of the Jitter matrix.
• Play around with the number
boxes labelled , , and connected to the two subpatchers labelled p
. Notice how you can move and resize the two images from the jit.qt.movie
objects in the matrix.
The subpatches p
contain identical helper patches to format the and attributes for the jit.matrix
objects. These attributes specify the upper left and lower right coordinates, respectively, to use when copying data into our Jitter matrix. The attribute simply tells the jit.matrix
object to use those attributes when copying data. When is set to , the incoming matrix is scaled to fill the entire matrix referred to by the jit.matrix
Scaling the input matrices before the are written into our shared matrix
The three numbers that we send into the subpatches get formatted by the Max objects inside to generate a list that describes the upper left and lower right areas of the output matrix which we want to fill with our input matrix. The message
box before the outlet uses substitution to replace the relevant arguments for the attributes with numbers from the list.
The last thing that happens after our two matrices have been written into the receive
object named :
matrix is that a is sent to the
The region at the bottom of the tutorial patch contains a third named jit.matrix
object. The sent by the metro
goes through a trigger
object that sends a to the jit.matrix
(causing it to output its matrix to the jit.pwindow
) followed immediately by a message. The message erases (zeroes) all the cells in the Jitter matrix named . If we didn't clear the matrix, changing the and attributes of any of the jit.matrix
objects could result in cells left over from a previous output location of our movies.
object at the top of the patch provides an invaluable service in the event that Max can't keep up with our demands. The metro
object (which is sending out messages every 50 milliseconds) is driving three separate operations (writing the two matrices from the jit.qt.movie
objects into our named Jitter matrix, as well as displaying the data and clearing the matrix so we can start over). The jit.matrix
object writes data into its internal Jitter matrix (in this case our named matrix) in a way that allows it to be usurped
by a subsequent message. It also allows other Max events that are scheduled at a higher priority to happen while it works on a task. This makes it possible to display the matrix (or write more data into it) before the previous operation has finished, causing flicker and other unexpected results. The jit.qball
object places messages input into the object at the back of Max's low priority queue where they too can be usurped
by another message. This way, if jit.qball
gets a from the metro
object before all the current Jitter tasks are complete, it will wait until everything else in the low priority queue is finished before sending out the . Similarly, if another comes along before that first has been sent (i.e. if it takes more than 50 milliseconds for the rest of the patch to do everything), the first will be usurped (jettisoned) in favor of the second. This allows you to set a maximum hypothetical rate of events in a Max patch without having to worry about events accumulating too rapidly for the objects in the patch to keep up.
• Click on the Ggate
object labeled so that the output of the metro
object bypasses the jit.qball
object. The composite image in the jit.pwindow
at the bottom will start to flicker, indicating that messages are arriving out of order.
Normally, sending a jit.qball
object gives us this kind of control over multiple chains of Jitter objects, automatically usurping events ("dropframing") to guarantee that messages arrive in the right order.
to a Jitter object will usurp an already pending event in that object (e.g. a that has already arrived but hasn't been dealt with yet by the object). However, the
By giving a single name to multiple jit.matrix
objects, you can write into and read from a common Jitter matrix in different parts of your patch. You can scale a Jitter matrix while copying it into the internal matrix of a jit.matrix
object by using the and attributes and by setting the attribute to . The jit.qball
object allows you to de-prioritize Max events by placing them in the low-priority queue where they can be usurped by subsequent events if there isn't enough time for them to execute.