How to construct large programs using MaxMSP and still keep the control…
MaxMSP is a really great programming environment. It makes things even for quite unexperienced users possible, things which they cannot do in other systems without a long time of learning. The advantage of Max is that it hides a lot of the complicated stuff from the user who simply wants a task to be done. But there lays also a danger – Max patches have the tendency of growing exponential and getting more and more confusing and hard to debug. So it makes sense to use proven and documented strategies if you plan to do more than just simple things (and you don't bought Max for simple things?).
The following pages contain a brief introduction on how to use design patterns in Max, the guidelines how to program using the tlb framework, a demo plugin, and the documentation of tLb.
Things to consider
Many Max-patches start their existence from quick ideas on how to solve an (artistic) problem, without much planning or designing beforehand. Max makes it easy to work in this way and this is completely ok as long as the patchers remain small in size. But a patch is never really finished, and from hacking session to hacking session the patch will grow, will do more things, one has to consider special cases, it will be divided into sub-patchers, and so on. So you can save yourself a lot of work later on the debugging if you follow some rules even at the beginning of the work (play?). These rules stems from other programming languages and from professional software engineering, namely from the field of object-oriented programming and are not very complicated to follow.
Max itself is not an object-oriented programming language, even if you push "objects" around on the screen. But you can try to apply object oriented principles, which are not connected to a specific programming language – it is more a way of thinking and solving problems.
Here are the three
Do not repeat yourselfConsider you worked on the part of the patch and you discover that its functionality is useful in other parts of it, too. Resist the impulse to simply copy and paste it to the other location – if you discover later that there are bugs or other sub optimal things in it, you have to do the corrections on two or even more places. This boosts the probability of making more mistakes.
Instead, save the parts of the patch to a new patcher which can be simply re-used and has to be edited only in one place if things are wrong.
This leads to the second rule:
Separate constant things from things that varyAn example from LVD: each effect maintains its own texture, and its name is being used as the input to the following stage. Or there is no connection, in this case the input texture name is "gl_TexBlack". If you write this down in "pseudo code", you get something like:
"send source matrix to receiver"
"send black matrix to receiver"
In both cases "send xxx to receiver" remains constant, "xxx" is the varying part. Therefore make just one sub-patch and isolate "xxx" into an argument which can vary.
Use "speaking" names for patchers, send-receive pairs, variablesIn the old days memory in computers was precious and real programmers were always lazy and tried to avoid unnecessary keystrokes. This leads to rather cryptic short variable names, and even now it is not simple to fight this long used behavior. Here is an example from another Max framework:
s #0_xxx_rstctbf. Its up to you, if you see this in a patch, to guess what the meaning could be.
Better use intention revealing names, like
r bSavePresets. This name is composed of two parts:
bmeans that a bang is received.
SavePresetsis the action which shall be triggered.
It is a good idea to use a proven naming convention, e.g. like it is found in the Cocoa framework. In tLb you find abstractions like
tLb.FillUmenuFromCollWithIndex. The name reveals for what the patcher is made.