Gen Tutorial 2a: The Joy of Swiz

Welcome to the second in a series of “drive-by” tutorials – quick introductions to the world of Max Gen objects. While the Gen world is deep and subtle and you may eventually find yourself thinking about things like polar coordinate conversion, dot products, and other bits of arcana, you can still do some rewarding things armed with a few basic concepts and the will to play.

Reading This Tutorial (And The Next One)

You’ll notice that this is Gen Tutorial 2a, and that it showed up alongside its fraternal twin Gen Tutorial 2b on the very same day. They’re closely related, but very different. In this first tutorial, we’re going to introduce some basic concepts about working in the Jitter Gen environment in ways that closely resemble your experience in the Max world.

Our suggestion is that you go through Tutorial 2a, learn about swizzling, play around with the patches and then dive right back into Tutorial 2b. The second part of the tutorial takes the concepts you learned and the patches we showed you and rewrites them with more efficiency by making use of the vector nature of the Jitter Gen environment.

The Lay of the Land

While the programming you do inside of any Gen object looks and feels like regular Max patching (connecting object boxes together with patch cords in ways that show you the flow of data), there are some important differences that are useful to know when you begin.

The Jitter Gen objects are no exception. They’re even a little different than the gen~ object you use for audio processing, in fact.

  1. The things that happen inside of a Gen object are synchronous – there are no triggers and there’s no notion about the order in which things happen. In the Jitter world, the basic unit of data is a vector, which we’ll describe in greater detail in a minute. For now, think of this vector as a way to collectively describe a group of single pixels rather than a frame of video. Actually, it’s more correct to think of it as though you’re performing the same operation on every single individual pixel (unit of data) in the entire matrix at once.
  2. To provide user input used for calculations and transformations inside a Jitter Gen object, we use the Gen param operator.
  3. Most of the Jitter family of Gen objects only allow you to have a single outlet for your objects – you can have as many single matrix inputs as you’d like (each of which represents a single matrix), but only one output. The jit.gen object is the only exception to this rule.
  4. There’s no way to retain the value of the pixel you’re working on from one operation to the next – if you’re familiar with the gen~ object, there’s no such thing as a history operator for Jitter Gen objects that you’d use for interpolation or filtering or delays (Don’t worry – there are ways to do what you’d use a history object for, which we’ll talk about in another tutorial).

Meet the family

The first thing you’ll notice about using Gen in the Jitter world is that there are three objects instead of one. Here’s how they differ:

The jit.pix and jit.gl.pix objects are made for standard Jitter 2d image processing. They work with input matrices with 1 to 4 planes, and treat incoming data like image data. The jit.gl.pix differs from the jit.pix object in that does all its work on the GPU (Graphics Processing Unit) instead of your CPU.

The jit.gen object is a general matrix processing object that works with any type of data that a matrix can contain (e.g. OpenGL).

In (both halves of) this tutorial, we’re going to be working with the jit.pix object.

Maps Make the Journey More Interesting

As we’ve said before, when you work with Jitter Gen objects, it’s easiest to think of it as performing the same operation on every single individual pixel (unit of data) in the entire matrix at once.

At a very low level, that’s how things like the jit.op or jit.expr objects work – a single operation is performed on each and every individual cell of the matrix or some part of the matrix, and the result of the calculations inside of your Jitter Gen object pops out the outlet of the object as a single matrix.

Let’s start with a really simple Jitter Gen patch. I’m a big fan of color mapping as a way to generate visual variety, so I’m going to start with a simple Gen patch that uses a cosine function to do some color remapping.

The inside of the jit.pix patch is much simpler than you might think from watching its output, but that’s because the relatively straightforward calculations on the inside of the patch are being applied to each and every pixel in the image (actually, the calculations are being performed on each and every pixel in the alpha, red, green, and blue planes).

Note: If you’re accustomed to only working with color in Jitter as char data in the range of 0 – 255, you might be wondering where the color processing is. Jitter actually has an additional way of specifying and working with color values – floating point values in the range of 0 – 1.0. In genland, colors are always specified using floating-point numbers.

Each input pixel is multiplied by an input value and then used as the input to a cosine function. Since we know that cosine functions output values in the range from -1.0 to 1.0, we’ll multiply the cosine function’s output by 0.5 and then add 0.5 to produce values in the 0. – 1.0 range that we expect for colors. The result is quick and easy color remapping – I particularly like the kind of results you get from using large values for the amp parameter.

Of course, we could replace the cos operator with any other kind of calculation we could think of (a sin operator would also work well, since its outputs fall into the same range as that of the cos operator), as long as we know in advance what the maximum and minimum values for the output range is so that we can coerce them into the 0. – 1.0 range.

In fact, the tutorial patch colormap_2a does precisely that. The patch not only adds the ability to pass the output unchanged, to select from either cosine or sine mappings, but also lets you choose to pass the data unchanged or invert its output for the passed or processed images. Here’s what the patch inside our jit.pix object looks like now:

Gen Tutorial 2a: The Joy of Swiz

Feb 7, 2012 at 3:31pm

A basic & global question would be:
why should we use jit gen instead of using classical objects ?

I guess answer woud be efficiency and a bit of low level easiness
right?

my video generator should probably go that way instead of “classical” patching

#260579
Mar 30, 2012 at 1:25pm

This is really great stuff, Thanks! I am excited that I might be able to avoid shaders now. I have similar questions to Julien though.

-How do I choose when to use a jitter object, a slab, or a gen object (which also have the choice of using an opengl version)? Should I think about it as a jit.expr or slab that has unified and more complex ways to process data as well as getting a performance boost from being compiled?
Also, does using a jit.gl.pix object have the same overhead as transferring ARGB data from a jitter matrix to a slab?
As I continue to learn about Gen, I will try to post anything interesting I learn. Thank you Gregory (and the rest of the team)! Its exciting to think about how gen could some day use the resources offered by technologies such as Nvidia Cuda, ATI Stream, or Intel Quicksync.

#260580
Jun 28, 2012 at 1:59pm

Very cool tutorial. Btw, the Ricahrd Avedon link seems not to be…

#260581

You must be logged in to reply to this topic.