In this tutorial, we look at using the itable
object for data storage, data transformation and histogram tracking. The itable
object can be drawn into, or can be set using various formulae. We will also look at using the uzi
object to quickly generate many messages or streams of ascending numbers, both of which can be used to quickly create lots of algorithmically generated data.
Using a two-dimensional data structure (like itable
) gives us the opportunity to create data transformations that are easy to set up. These transfer functions
allow you to create irregular curves, probability tables that weigh the output based on the input, and random patterns that are easy to visualize. Additionally, the introduction of the uzi
object for the quick generation of procedural messages helps us find a way to create the functions necessary to load these itable
objects in interesting ways.
object used in this tutorial is virtually equivalent to the table
object, which has its own window and can be typed into a regular object box. The itable
is used here simply because it appears embedded visually in a patcher, rather than in a separate editor window.
In this tutorial's patcher, you will see a few display/drawing patches (labeled with numbers) and several small calculations (labeled with letters). We will start working with the patch area labeled 1
. This patch features an itable
object; an object that provides a visual interface to a two-dimensional data structure called a table
. The table
structure gives us an X/Y combination and a simple interface to this data: send in an number that represents an index on the X axis, and you will receive the corresponding Y axis value.
When you first open the patch, the itable
contains a random distribution of values. If we move the slider
at the top of the patch, it scans the itable
values, and outputs the Y value from its left outlet for the X position represented by the slider
. We have this connected to a number
box and slider
, so we can see the results of the transfer function described by the itable
. Next to the input slider
are a pair of message
boxes with two-integer lists; these will set the location of the first integer (X) to the value of the second integer (Y). Thus, with the first message
box, the value at location will be set to . If we click on this message
box, then move the slider
box) to , we can see that the output of the itable
is . Likewise, if we click on the second message
box ( ), we can see that an input value of outputs a value of .
view, but values are still intrinsic to the itable
; when cleared, the itable
simply assigns a value to every possible data point. Another way to change the values of the itable
is to draw within the itable
itself. If you place the mouse inside the itable
and click-drag the mouse, you can draw in the function contents you desire. If you need to make straight lines, you can hold down the shift key while you move the mouse, and click the mouse to commit the new line. Using these drawing commands gives you an easy way to manually create interesting transfer functions.
message “erases” the
Below the patch are three small patches that utilize uzi
objects to generate all of the points in the itable
. If you click on the A button
, a function is created where the input value is the same as the output value. Clicking on B
produces the opposite: input values ranging from are converted into a range. The C button
produces a random
distribution similar to the starting contents of the itable
Let’s look more closely at these function-generating routines, and particularly at the uzi
object. The uzi
object, as its name implies, is made to rapidly fire off messages. A single to an uzi
object’s input will generate as many messages as are specified in the object's argument; therefore, uzi
will send out messages from the left outlet. In order to keep track of the current number, the rightmost
outlet produces a count (starting with ) – this output is what we are using for the index to the itable
object. In patch segment A
, this count is decremented by (so that it begins with , the start of the itable
range), and used for both the X and Y values, giving us the straight line output for a function.
segment is similar, except that the Y value uses the !-
object to subtract the incoming value from . This results in a similar ramp, but heading in the opposite direction – the lowest X values have the highest Y values. The C
segment uses a random number generator to create random values as part of the output list. It has to use the swap
object (which simply "swaps" the left and right values it receives) to reverse the order of the list contents so that the random
object's output is used for the Y value instead of the X value.
Let’s alter the B
segment a little to see how different functions could be created. If we change the !-
object to be a division (/
) object with an argument of , we will reduce the range of the Y values to only 1/4th of the vertical range. Likewise, if we multiply (*
) the value by , we will hit the Y range maximum halfway through the X values. Obviously, with a little manipulation, you can use uzi
and a little math to create many complex functions.
The right-hand patch area (labeled 2
) provides an interesting use of the itable
system, as well as several formula patches and a new object called histo
. The histo
object performs a histogram function: it keeps a count of how many times a number has come into its input. Whenever a value comes into the input, the object produces the number of times it has been received out its right
outlet followed immediately by the value itself out its left
outlet - it can then be fed directly into the itable
object, where the left inlet becomes the X and the right inlet becomes the Y. If you use the slider
at the top of the patch to “scratch” in a lot of numbers, you will see the itable
object show the relative distribution of the values you have sent. If you want to clear the itable
and the histo
objects, you can hit the return key on your keyboard (ASCII ).
Turn on the metro
object with the toggle
at the top of the patch; this will cause messages to be sent to the itable
object. This produces a random “quantile” output to be generated – a random but weighted output value from the itable
object. The result is that the lcd
area below the itable
will begin drawing small circles where the density is roughly equivalent to the distribution curve shown in the itable
routine. If you want to clear the lcd
, you can hit the space bar (ASCII ) to restart drawing.
As with our first drawing patch, we have a number of smaller patch areas that can be used to generate functions into the itable
object. However, instead of drawing discrete functions, these generate “fuzzy” distributions by sending random and semi-random values into the histo
object; this histogram is then fed to the itable
to generate a probability map. Segments D
, respectively, to generate the values. Clicking on the attached button
objects repeatedly will show how each affects the distribution curve – random
hits all of the values fairly evenly, but drunk
is much more “lumpy” in its distribution. Again, we can clear the histogram at any time with the return key.
Patch segments F
take a somewhat different approach. Segment F
generates two random
numbers, then uses the minimum
object to choose the lower
of the two numbers. This will tend to emphasize the lower numbers in the range; repeatedly clicking on the connected button
will show the lower numbers being used more often than the higher values. Segment G
does the opposite: it uses the higher of two random
numbers by putting them into the maximum
object. Thus, repeatedly clicking on the connected button
will tend to generate more high numbers.
Finally, segment H
creates an average of 3 random
numbers by generating the numbers, adding them together, then dividing the sum by . If you clear the itable
and repeatedly hit the H button
, you will see a “bell-shaped” curve being generated, since the average of three random numbers will tend to be in the middle of the range. This is a simple type of Gaussian
(or normal) distribution, and is commonly found in statistical research when most subjects fall within the middle of a range of possible values.
In each of these cases, having the metro
running during our function generation should cause the drawing to simulate the distribution curve in the itable
object. To test more radical curves, you can draw sharp lines within the itable
object to force certain output curves; you can also use the slider
to “shade” in parts of the equation, causing the drawing output to shade in segments in response to the new distribution curve.
Many different processes depend on the ability to create functions that transform an input range into an output range. In previous tutorials, we saw how the scale
object could do this for us. However, if we want to manually change the distribution of values, or if we want to use a formula for data transformation, we need to use a more complex system. As we’ve seen in this tutorial, the table
objects serve this purpose perfectly, giving us the ability to either manufacture or manually draw a transfer function.
Using the histo
object, we also saw how we can generate the sort of distribution curves that serve as common random techniques in generative art and stochastic music. Whether the fuzziness of true random generation, or the tendencies found with more discrete math, these curves can be used to both generate and guide results to a desired outcome.
Store and graphically edit an array of numbers
A table in a patcher window
Send a specific number of bang messages
Reverse the sequential order of two integers
Make a histogram of the numbers received
Output the smallest in a list of numbers
Output the greatest in a list of numbers