Multimedia Programming Using Max-MSP and TouchDesigner
上QQ阅读APP看书,第一时间看更新

Understanding the basic concepts of Max

Cycling'74, the company that produces the software, defines it as a toolkit for audiovisual/multimedia expressions that don't demand much knowledge about programming. In fact, Max is a graphical programming language that lets us avoid the traditionally steep learning curve of text-oriented programming languages to some extent. We simply put boxes into an empty canvas, called a patcher or a patch, and connect them, patching them together.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you. In case of Max examples, all examples (except for the first two chapters) are provided as so called Max projects. For each chapter, just open the corresponding *.maxproj file.

Let's compare graphical programming with other representations of code for a minute. Look at this patcher:

Don't bother about the vocabulary, that is the object names, too much. This is a special patcher. It is also called a gen~ patcher, and we use it here since it allows us to see the code generated under the hood. However, this gen~ patcher is using a somewhat different vocabulary (object names). So, don't try to implement this right away; we'll have a slightly theoretical start for now. Can you already see what's happening? Imagine a number, say 0, coming into our patcher at [in 1]. You can see that first, we add 1 to our incoming number, resulting in 1. Then, we multiply it with 0.5 (or divide it by 2), resulting in 0.5. Afterwards, we subtract 0.2 and get 0.3, which will be sent to the output of our little patcher. The program we see here doesn't do anything very useful, but it will hopefully illustrate differences in representing mathematical operations. By now, you have seen two representations of what's happening; the last few sentences describe what's happening in the patcher and the patcher itself. In essence, these sentences are like a recipe for cooking. Let's add another equation for reference:

Don't be afraid of the notation. For simplicity, you can simply ignore the n subscriptions, but this is a common notation that you will encounter very often. The x parameter usually denotes an incoming value, and it corresponds to our [in 1] in our patcher; y corresponds to the output, [out 1]. The n parameter stands for a running index. Since we are usually dealing with a sequence of incoming numbers, we have to be able to address this fact. In some cases, we would, for example, like to combine the input with the previous input in some way. To give an example for this case, let's think of an expression that outputs the input plus the previous number's input:

You don't have to understand what this is actually doing right now; this is just to make you familiar with another way of representing our code. We will later see how to create an n-1 term in max (a one-sample delay), but now, let's concentrate on another form of representing our first patcher:

add_1 = in1 + 1;
mul_2 = add_1 * 0.5;
sub_3 = mul_2 - 0.2;
out1 = sub_3;

This might look a bit overcomplicated for such a simple operation. It is the code that Max automatically generated for us when we created our patch. You can see that we are constantly assigning values to variables, for example the variable sub_3 is assigned the value mul_2 – 0.2, which is referring to the variable mul_2 and so on, until we reach in1. One can certainly write this program in a more elegant way, but let's stick to this version for now.

Think about the differences in these four representations of a system:

  • Mathematical (the previous equation)
  • Code (C++, as in the previous code)
  • Data flow (Max patch) / block diagram (as in our patcher depicted previously)
  • Text (a recipe that explains what to do in natural human language)

Each one of them has its strengths and weaknesses. A mathematical expression is concise and precise. On the other hand, mathematical expressions that describe a system can be declarative (meaning not giving us a recipe to get from the input to output but only describing a relation as it's the case for differential equations). Code, Max patches, and written recipes, on the other hand, are always imperative. They tell us what to do with the input so as to get the output. A Max patch has the advantage that the flow of data is always obvious. We always go from the outlets of an object to the input of another, typically using a line, going from top to bottom. A traditionally coded program doesn't need to be that way. This, for example, looks much like our mathematical representation and does not provide us with an impression of the order of operations as quickly as a Max patch does:

out1 = (in1+1)*0.5-0.2

It is yet another valid version of our code, a bit tidier than the automatically generated code of course.

So, we can see that one major advantage of Max patching is that we can quickly see the order of operations, just like when we connect the guitar stomp boxes' input to the output, as shown in the following figure:

I leave it to you to reflect on the differences of these representations in our text recipe.