Simple MIDI Router is a Max-based utility that routes MIDI. I originally built this so I could use a USB MIDI controller to control an external USB device. It can route internally as well, the Max patch is setup with four internal Max sends and returns. I figured I’d share it in case it’s useful to anyone else.
When I was first learning Cycling '74 Jitter’s OpenGL objects, I started working on a project that required a lot of geometric shapes which needed to be controlled easily and consistently. It seemed like jit.gl.multiple would be perfect, but I had a hard time figuring out how to use it. Even with the documentation, it took me a while to pare down to the basics and really figure out how the object works. Hopefully this tutorial can help anyone in the same situation.
Click to download the tutorial patch.
This tutorial assumes understanding of Jitter, including OpenGL rendering. If you're not yet familiar with that aspect of Jitter, there’s an overview online and the general GL tutorials starts at Jitter Tutorial 30. A tutorial patch is provided, please download it to follow along.
The basic premise of jit.gl.multiple is that it creates multiples of another GL object. jit.gl.multiple uses matrices to set parameters, allowing for easy control over individual shape parameters or global control of all the shapes. This tutorial will cover the basic required parameters and show some simple extended functionality.
Note: In an attempt to make clear what each description refers to, in this tutorial "object" refers to actual Jitter objects such as jit.gl.multiple and "shape" refers to the rendered shapes that the Jitter objects are creating.
The Rendering Context
This section of the patch sets up the rendering context, named “glmult”. This also has some basic view and camera positions preset to make it simpler to see what’s happening. (If you’re using Max 7, it may be simpler to use jit.world.)
The Shape to Multiply
In this patch, jit.gl.plato serves as our origin object, it has the required rendering context name (“glmult” in this patch). jit.gl.multiple works with any object that creates a geometric shape. The @name attribute identifies the object, so that the jit.gl.multiple object can bind to it. The @automatic attribute set to 0 means this object won’t render unless it receives a bang. In this situation, it won’t receive any bangs, the jit.gl.multiple object will. This means the original jit.gl.plato-generated shape will not be rendered, only the shapes generated by jit.gl.multiple will be rendered. Although this is not required, this setup allows for easier control all shapes directly via the jit.gl.multiple object. The remaining attributes are not required and simply setup the polygon rendering mode and color. Use the menu to change the shape.
The jit.gl.multiple Object
This is the jit.gl.multiple object, which is also set to render to the “glmult” context. The @targetname attribute matches the origin jit.gl.plato object to bind to and create multiples of the shape created by jit.gl.plato. jit.gl.multiple expects a matrix at each of its inlets. These specify data for various jit.gl.multiple parameters (color, position, rotate, rotatexyz, scale, and various texture parameters). By default, jit.gl.multiple has two inlets. The left inlet is for position and the right inlet is for scale. More can be added using the @glparams attribute. The @dimparam attribute sets the dimension that all parameter matrices will wrap to. While this is not a necessary attribute, this aspect is discussed later in the tutorial.
The Position Data Matrix
This section of the patch sets up the position data matrix (the specific name doesn't matter). This matrix must be a 3-plane float32 matrix. The matrix dimension sets the number of shapes that will be generated, with each cell representing one shape. It doesn't matter how this is set, in this example "3 9" or "27 1" would work equally well.
The 3 planes hold the position data for each shape:
Plane 0 = X position
Plane 1 = Y position
Plane 2 = Z position
This matrix can be set or filled in any manner supported by Jitter. This patch uses various jit.expr and other objects to generate position data. (There's an excellent online article on jit.expr.)
The jit.cellblock object shows the actual data that the matrix is sending to jit.gl.multiple. Set the number box to see each plane (X, Y, and Z positions).
The Scale Data Matrix
This section sets up the scale data matrix. Scale is also a 3-plane float32 matrix. This matrix is set to a dimension of “1 1”. In this example, all shapes are at the same scale, so it's not necessary to specify the scale for every individual shape. This is where the @dimparam of the jit.gl.multiple comes in, it sets the point at which matrix data will wrap when parameter matrices don't have matching dimensions. In this case it wouldn’t really matter as the default wrapping would yield the same results, but it’s good to understand how this works.
The three planes hold the scale data for each shape:
Plane 0 = X scale
Plane 1 = Y scale
Plane 2 = Z scale
This example uses an empty matrix with an applied a jit.expr expression to set all values to a specific number for all axes.
Changing the Position Data for One Object
This section shows a method for changing the position of one shape. Three different sine waves are converted to a number, and are used to change the x, y, and z position of the shape at cell position “4 1”. This example addresses only the center shape. Click the toggle to see the shape move. The changing data can be seen in the jit.cellblock grid attached to the position matrix.
Changing the Scale Data for All Objects
This section shows a method for changing the scale parameter for all shapes. A scaled random signal is used to alter the size of all the shapes. Click the toggle to see this changing.
This tutorial provided an overview of the basic setup and parameters of jit.gl.multiple, as well as how to generate and alter the shape parameters. This hopefully provided a general starting point in understanding how jit.gl.multiple works and why it's so useful. There are many ways that this data generation and processing can be done within Jitter. Various examples are shown in the jit.gl.multiple help patch and all attributes and parameter matrix requirements are noted in the jit.gl.multiple reference.