In this tutorial we'll learn how to use the
name attribute of 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 .
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 and
traffic.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 and
receive objects to communicate with the rest of the patch. The
receive objects named
m1 and
m2 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
movie1 and
movie2 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.
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
bang 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
bang.
• Click the two
message boxes attached to the left inlet of the
gate (
1 and
2). 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
bang messages to the same three named receive objects (
m1,
m2, and
output). 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
bang to the
jit.qt.movie object (with the rain movie). Finally, the
jit.matrix object at the bottom of the patch receives a
bang, 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
bang messages driving our
jit.qt.movie objects (the left
jit.qt.movie outputs a matrix first, followed by the right
jit.qt.movie object).
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 object.
Once our
jit.qt.movie objects receive their
bang messages, they output a matrix to the
send objects below them, which in turn pass their matrices over to
receive objects named
movie1 and
movie2. 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
name. The
name attached to all three of these objects is
composite. 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
composite.
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
name) we can understand why the ordering of the
bang messages is important. If the left
jit.qt.movie sends out its matrix first, it writes data into the
composite 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
usedstdim attribute set to
1. 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
composite Jitter matrix.
• Play around with the
number boxes labelled
x origin,
y origin, and
scale connected to the two subpatchers labelled
p coords. Notice how you can move and resize the two images from the
jit.qt.movie objects in the
composite matrix.
The subpatches
p coords contain identical helper patches to format the
dstdimstart and
dstdimend attributes for the
jit.matrix objects. These attributes specify the upper left and lower right coordinates, respectively, to use when copying data into our
composite Jitter matrix. The
usedstdim attribute simply tells the
jit.matrix object to use those attributes when copying data. When
usedstdim is set to
0, the incoming matrix is scaled to fill the entire matrix referred to by the
jit.matrix object.
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
composite matrix is that a
bang is sent to the
receive object named
output:
The region at the bottom of the tutorial patch contains a third named
jit.matrix object. The
bang sent by the
metro goes through a
trigger object that sends a
bang to the
jit.matrix (causing it to output its matrix to the
jit.pwindow) followed immediately by a
clear message. The
clear message erases (zeroes) all the cells in the Jitter matrix named
composite. If we didn't clear the matrix, changing the
dstdimstart and
dstdimend attributes of any of the
jit.matrix objects could result in cells left over from a previous output location of our movies.
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
bang 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
composite 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
bang 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
bang. Similarly, if another
bang comes along before that first
bang has been sent (i.e. if it takes more than 50 milliseconds for the rest of the patch to do everything), the first
bang 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
jit.qball bypass switch 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
bang to a Jitter object will usurp an already pending event in that object (e.g. a
bang that has already arrived but hasn't been dealt with yet by the object). However, the
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.
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
dstdimstart and
dstdimend attributes and by setting the
usedstdim attribute to
1. 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.