Tutorial 16: Using Named Jitter Matrices
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.movie objects. A loadbang object reads two movies (rain.mov and traffic.mov) into the jit.movie objects when the patch is opened:
Unlike the tutorial patches we've looked at before, the jit.movie objects in this patch use send and receive objects to communicate with the rest of the patch. The receive objects named and forward messages to the two jit.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:
Order of Importance
The metro 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 .
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.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.movie objects (the left jit.movie outputs a matrix first, followed by the right jit.movie object).
What's in a Name?
Once our jit.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 objects:
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.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.movie sends out its matrix first, it writes data into the matrix, followed by the right jit.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.
The Destination Dimension
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.movie objects so that they only write to a certain region of the Jitter 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 object.
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.
Jumping the Queue
The jit.qball 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.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.
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.
|jit.matrix||The Jitter Matrix!|
|jit.pwindow||Display Jitter data and images|
|jit.qball||Convert messages at scheduler time to low priority|
|jit.movie||Play a QuickTime movie|