Iterative processes in MaxMSP.
[This article is intended to introduce composers without a background in computer science to some of the ideas and techniques that might be useful to them in using computers as part of their compositional practice. It will probably not be useful for all users!]
Musical representation in computer music is usually in the form of lists of numbers, or lists of pitch names. Whatever format one's data will be in, it is usually essential to iterate through the data at one stage or another. I will illustrate below two basic approaches to the creation, storage, and utilization of lists, and how they can be iterated through. In order to iterate through material, one has to have a place where that data is held. The two easiest ways of doing this are using the coll object, and messages. For example:
Here, we use the uzi object to trigger the random and append process twelve times, giving us twelve discrete values. These values are one by one appended to a blank message, effectively storing our data. In order to actually iterate through this data we need to use a few more objects. Firstly, we need to count how much data we have. As we have set uzi to 12, and it triggered the generation of that many random numbers, we already know how much data we have here. But imagine we had generated a random amount of data, then we cannot use our knowledge for this task. Instead we can use a handly object, zl len. Now that we know how much data (or how many values) we have, we now need to be able to move through the data. For this purpose, we will use the counter object. The rightmost inlet will set the maximum count of the counter, which means when that value has been hit, it will begin counting at zero again. At this stage, we need to examine the technical aspects of iteration a little more closely. What we essentially have here is a list; each piece of data in the list has an index, which is essentially a reference to where in the list it can be found. In the above example, the third entry is 4934, but its index is 2, as we start counting from 0, and not from 1. With this in mind, we can now construct a simple linear iterator. The function of the counter object in this context is to be a basic iterator. Every time it receives a bang, the counter's value increments. We can use this value to lookup the message, and retrieve the value at that index. This is achieved using the zl mth object. In the left inlet goes to the data you want to lookup, and in the right goes the index you want to retrieve. It is useful to connect the bang that triggers the counter to both the zl mth object, and the list itself, so that the zl mth will always have the most current version of the list. From here you can enjoy easy iteration using messages.
The procedure for using coll is very similar to that of messages and zl len. The main advantage in coll is that is a more robust means of data storage and management, giving you the option to load/save data to the hard disk. In order to store data in coll, you must present it with a list. The easiest method to do this is to use the pack object (give it two 0s to represent integers) and then add data.
As you can see in the above example, we are sending two random integers, the left one being the index, and the right being the value. We can then iterate through this in a linear way, similarly to how we did previously, using the length message, sent to the coll, and a counter.
List – an ordered collection of values. For example:
[14 10 1066] is a list of three numbers, and
[Tom Dick Harry] is a list of three names.
Values are called by their 'index', beginning at ‘0'. Harry's index is 2.
Iterator – is a tool which allows for the movement through a type of data, by providing index values to reference data with.