Tutorial 3: Numbers and Lists
Numeric Data in Max
A lot of programming in Max involves manipulation of different types of data. In this tutorial, we'll look at how Max deals with some new types of messages: numbers and lists. We will spend some time with user interface elements that allow us to manipulate numbers, and learn how to use arguments to insert list elements into a message.
While messages made of text are useful for communicating with humans (and sending commands to a lot of Max objects which we'll look at later on), much of the media world is dependent on numbers, whether they are MIDI note data, video pixel colors or robotic motion control. Having a command of numeric messages is critical to understanding how Max works.
Numeric messages in Max are not always singular entities; they are often combined with command text or other information to create a list of data that is useful to other objects, the user of your patch, or the outside world. Hence, there are several methods of combining messages into lists.
To open the tutorial patch, click on the Open Tutorial button in the upper right-hand corner of the documentation window.
Number boxes
Take a look at the tutorial patch. The patcher window contains several small patches that feature number and list manipulations. The upper left patch looks at a new object called the number box. It deals with integer numbers (often called whole numbers), and accepts many different messages. Click on some of the connected message boxes, and notice their effect on the number box as well as the messages that appear in the Max Console via the print object).
The most noticeable effect comes when numeric data is sent to the number box: it responds by displaying the data as well as sending the number from its outlet. When a floating-point number such as 3.5 is sent to the object, it takes the integer portion of the number and ignores the decimal portion. If a non-numeric message is sent such as "Hey!", the Max Console displays a complaint by the object, stating that it doesn’t understand that type of message.
The patch just to the right is similar, but uses a floating-point number box that allows decimal values to be displayed and output. Many of the messages produce results in the same way as the integer number box. However, when a floating point value is received, the decimal value is saved and displayed in this number box. If the box is not wide enough to display the entire number, only part of it may show, but it's all there (and passed on). You can adjust the number of decimal places shown in the inspector.
Two special messages are accepted by either the number or floating-point box. First, sending a number box a bang
forces the current value to be output without any change to the data. Secondly, including a number in a "set" message will change the data without any output – in essence, providing a way to silently change the contents of a number box. The set method is fairly common in Max objects as a way to manipulate the state of an object without triggering output messages.
The user interface of the number box
In addition to sending number or floating-point boxes messages, we can also directly enter and manipulate the values stored. With the patcher locked, select the box, type a value, and hit return or click elsewhere. In addition, we can click-drag within the box to manually change the contents. This is useful for performance situations where we may want to change a number in real-time while the patch is running. Rather than having to set up message boxes for every possible value we might need, we can manipulate the number box to change a setting. If we click-drag on the integer number box, we see that the Max Console displays a stream of data – the number box generates output for most of the values that we scroll through. It does skip some however, depending on how fast you drag. To include every value, select the box and hit the up or down arrow.
With integer data, it is easy to support a scrolling value area – moving up adds 1 to the value, while scrolling down subtracts 1. But what do we add/subtract when we have floating point values? In the case of the floating-point flonum box, the answer is based on where we place the mouse before we click-drag. If the mouse is on the integer portion of the data (to the left of the decimal point), click-dragging will produce changes identical to the integer number box. However, if we position the mouse over the fractional portion of the data, we can change any of the displayed digits. (All digits to the right of the mouse are set to 0.) This allows us to manipulate the data stored in the floating point number box at both a "coarse" and "fine" grain. The third patch has some number and floating-point boxes hooked up to each other. Here, you can see the visible difference between integer and floating-point number boxes – the floating-point versions have a displayed decimal point. If you change the top-most (floating-point) number box, you will see its data being used to update an integer number box, which subsequently updates the next (floating-point) number box. You can also directly manipulate the integer box to see how its messages affect the floating-point variant.
Enter a large number into the top-most number box – something like 60000. You will see that the integer number boxes can’t display this number, since it is too large for the provided display area. Unlock the patch and move your mouse to the right-hand side of the object. You will see a small "handle" appear, and the cursor will change to a left arrow; this is called a grow box, and can be used to re-size all objects in Max. Click-drag on the handle to change the width of the number box, then click on a blank area of the patch to deselect the object. You will see an immediate change in the integer display.
The size of integer that can be handled depends on whether Max is operating in 32 or 64 bit mode. To see the difference, enter a ridiculously high number, like 7245569558. The integer number box may have changed to -2147483648. How did that happen? Integers always have a limit – in 32 bit mode, the maximum value of an integer is 2147483520. In 64 bit mode, the top value is 9223372036854775807. Any numbers greater than that cause the integer value to "overflow", and become the greatest negative number. Other very high values might provide other values, depending on how far over this limit the number is. The range of floating point numbers is approximately 38 digits in 32 bit mode and 308 digits in 64 bit mode.
Looking at messages with replaceable arguments
The central patch is a little different – it is just a group of message boxes with contents that are groups of numbers and words (which are called symbols in Max). When we click on the message box with "60 30", we see the two numbers displayed together on the Max Console. A message with several numbers or symbols is called a list; the list is a mechanism for keeping data together into a single message that can be send via patchcords to other objects. The numbers can be either integer, floating-point, or a combination, as you can see in the second example "22 33.9 -5 -44.2". The next example message is a number box connected to a message box. Use the mouse to change the value of the number box; the result is that the Max Console displays the "fleas" message, but replaces the 1" text is called a replaceable argument or token, and allows you to substitute message content variably using a message box.
The last example in this patch accepts two values (as noted by the 2 tokens), and uses the incoming list values to create the "fleas and ticks" message. You can have up to 9 replaceable arguments, numbered 9, and the arguments can be in any order. Let’s try an experiment with the arguments:
Unlock the patch window, and select the text in that last message box. At the end of the existing text, add the following text after a space: "1 fleas". Lock the patch, and click on one of the two connected lists. You should see the new statement displayed in the Max Console, with the proper list content replacing the arguments in the message. This demonstrates that replaceable arguments can be re-used (i.e. you can have multiple 2 can precede $1 in a message).
Building lists with pack and pak
The patches in the lower section show an alternate method for building lists. The pack object will have an inlet for each item in its arguments (which can be symbols or numbers). The arguments make up the default message that will be sent if the object is banged. Data received in any inlet replaces the associated item in the output; however, the type of the incoming data is changed to match the original argument. In the "lists made with pack" patch, the third inlet is associated with an integer argument, but a float box is attached. Those numbers will be converted. (When symbol arguments and number inputs or vice versa are mixed up, the results are either 0s or blank spaces.) Data received in the left inlet replaces the first argument and sends the list. If a list of data is sent to any inlet in a pack object, the first item replaces the argument associated with the inlet and following items are applied to succeeding inlets.
The pak object (pronounced "pock") is exactly like pack with one difference. Output is sent when data is received at any inlet. Change some of the number boxes in the "Lists made with pak" patch with the mouse and watch how many messages appear in the max window. Pack is used when numbers need to be gathered into a list and sent when ready, pak is used when lists need to be updated as soon as any value is received.
Summary
Max can send numeric data as messages, just like text. There are a few user-interface objects that help us construct and process numeric data, such as the integer and floating-point number boxes. Max can also keep groups of numbers linked in a single message using lists; message boxes can be used to construct lists and other more complex messages with replaceable arguments. Lists can also be built with pack and pak.