Tutorial 22: Designing Equations
Introduction
This tutorial covers the creation of equations: mathematical statements that evaluate an expression based on input values. The key to equations in Max is the expr object, which provides a wealth of mathematical functions and a “write your own” mechanism for developing complex statements.
To this point, we have created somewhat complex mathematical processes using individual math objects (+, *, etc.). However, in many cases, we can collapse a number of objects into a single mathematical equation, eliminating a lot of unnecessary complexity in our patches. The tool used for this simplification is the expr object, which uses a specific syntax for creating an equation that accepts multiple inputs and can produce very complex results.
Overview of the drawing patch
Take a look at the tutorial patch to see the work we have ahead of us. This patch is broken into four portions of patcher logic and an lcd object; communication between the parts is accomplished using value objects and pairs of send and receive objects. To see the patch in action, turn on the metro at the lower left of the patcher using the toggle box, then hit the space bar to trigger the events at the top of the patch. The result will vary from small scribbles to large-format abstract line-and-circle drawings. Each time you hit the space bar, the lcd will clear and a new, related drawing will begin to appear.
The comment box at the top of the patch shows three lines of mathematical equations:
x = sin(A*y)-z*cos(B*x);
y = z*sin(C*x)-cos(D*y);
z = E*sin(x);
These expressions compute three values (x, y, and z) based on applying some simple trigonometric functions to their previous states as well as five fixed values (A, B, C, D, and E). When plotted onto the lcd object (with z visualized as a circle of variable size), we can see that a wide variety of patterns can be created. This equation generates something called a strange attractor - in essence an iterated function where the previous outputs of the equation combine with five variables (called coefficients) to generate a variety of shapes that exhibit chaotic behavior.
Let’s examine each section of this patch. The lower-left is obviously the key to making things draw – it generates bang messages from a metro that are sent to the compute and draw receive objects, as well as into a subpatch that slowly varies the color of the drawing (more on this later). After the subpatch is evaluated, the compute section of the patch (in the middle) receives a bang. This section updates the equation for the next round of drawing by triggering a number value objects, sending their output through equations encoded in the expr objects. These then update the x, y, and z values for drawing. We'll examine how these expr objects work in a moment.
The send object named draw sends bang messages to the drawing routine at the top-right of the patch. This triggers the newly calculated x, y and z values which are scaled, packed into command messages, and then put through a send object to the receive object attached to the lcd. This is just a shortcut to the input of the lcd, which performs the drawing commands that were generated above it.
Finally, the top-left section of the patch controls the action when the space bar is pressed. It is a good example of the right-to-left execution of events in Max; when the key object outputs a 32 (meaning that the space bar has been depressed), a button is used to generate a bang message. This, in turn, performs seven actions in order from right to left: the generation of 5 random values (E to A) that are scaled from -4.0 to 4.0, the transmission of a clear message to the lcd object, and a reset of the value contained in the x, y and z value objects. In essence, the space bar is the overall “reset” key for this patch, in that virtually every segment of the patch is affected when that key is hit.
Using expr for equation creation
Now let’s look into the expr objects themselves. While they look complicated, the argument for each of the expr objects is a relatively simple equation. The important thing to realize is that the \$ references simply refer to an incoming message, along with its message type and inlet number. So, for instance, using a reference named \$f1 means that the equation should use an incoming message (\$) that is a floating-point number (f) retrieved from inlet number 1 (1). Once you realize that the “complexity” of the equation is simply its reference to incoming messages, the format of the expr statement is a little more comprehensible.
The operations used in our expr statements are limited to the sin (sine function), cos (cosine) and * (multiply) functions; however, there are dozens of operations available. You can use the common math operators (+, -, * and /), logic (&&, ||), bitwise comparison (&, |) and other C language math functions such as abs, sin, cos, and pow. The documentation provides a complete list of the available functions.
In the case of our tutorial patch, the three expr objects use eight different variables (x, y, z, A, B, C, D, E) to create the three target values (x, y, z). There is an interesting bit of feedback here: the target variables are not only used for the drawing routine, but are also used for the next “round” of computation. The five variables A through E only change when the space bar is hit, so they provide an “anchor” to the drawing routine while the ever-changing x, y and z variables determine the individual line and circle drawings for each round of computation.
In order to make the drawing a little more interesting, let’s do some creative equation-making and use it to generate a constantly shifting foreground color. We are going to “tap into” the x, y and z value objects that are updated each bang of the metro.
Double-click the patcher object labeled changecolor at the bottom of the patch. We can see that the foreground color of the lcd is being altered by a trio of drunk objects that are packed into an frgb message sent to the lcd. In here, we are going to use an expr object compute the exp (E to the power of x) mathematical function. If you aren’t familiar with the properties of E, that’s OK – it’s sufficient to know that it is exponential in nature, and that the value will rapidly increase as the input value increases.
Delete the drunk objects, or disconnect them from the inlet and pack objects and move them out of the way. Create three new value objects with x, y, and z as their respective arguments and connect the inlet object to their inlets.
Now create a new object and type in the following:
expr int(exp(\$f1)*5.)
Examining the argument/equation from the inside-out, we see that we are taking an incoming floating-point value (\$f1), using the exp function to create a new value (exp(\$f1)), multiplying it by 5.0 (*5.) then turning it into an integer (int). The result will be a number that is approximately in the range of color values (0-255), but is predominantly low in that number range. Copy this expr object two more times, then connect the output of the three value objects (x, y and z) to each of the expr objects. Connect the outlets of the expr objects into the pack, and see what happens.
When we start the metro and clear the lcd, we will see that the drawing is colored, but tends toward the darker colors. Since the coloring is influenced by the calculated x, y and z coordinates, the colors will tend to be brighter toward the extreme edges of the drawing window. This is an example of calculating drawing commands that might be difficult using traditional object-based programming, but is made quite easy using expr.
Conclusion
Using the expr object gives us the opportunity to create complex mathematical and logical equations without having to resort to large object programming segments. The huge number of operations that can be performed, in combination with the ability to define and use multiple inputs, allows for interesting results that might otherwise be cumbersome to create.