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

Initializing a patcher

Initializing means to set up parameters of our patch at startup. There are a couple of ways to initialize values. Look at the following screenshot that depicts the initialization.maxpat patcher:

In the patch, you can see 5 differently initialized versions of the same. The [noise] patch is a white noise generator, and [onepole] is another lowpass filter (from left to right) and can be explained as follows:

  • No or rather default initialization (not recommended)
  • Initialization using initial attributes (through the inspector)
  • The [loadmess] object that fires out its argument when the patch is opened
  • The [loadbang] object that fires a bang when the patch's open end is connected to a messagebox object, which in turn contains our initial value
  • Initialization of the processing part using an argument but no/default initialization of the GUI object

The last one is particularly interesting; it can actually be considered as a bug (a bug we built, not Cycling'74). It has been taken up in this list to re-emphasize the idea of initializing objects via arguments. In this case, we produced a conflict between the GUI and the processing; the GUI shows us that the filter has a cutoff of 0 Hz, but it actually has a cutoff of 1,000 Hz. As soon as we move the corresponding [live.dial] object once, everything is synced again. So if it has this disadvantage, why do we do something like this? We will revisit this idea in the Structuring our patches section. Essentially, it's about bidirectional communication. For now, stick to one of the other three methods, which only have minor differences from each other. Think about what's missing from the previous method and what the advantages might be.

Note

Exercise

With the new initialization techniques at hand, try to fix our synth! To turn on audio at startup, look up the [adstatus] object or you can just send the integer 1 into [dac~]. The target is to open our patch, hit a key, and want reasonable sound right away.

Here is another neat little trick about initialization; sometimes, we need some object (especially interface objects) to be set but don't want it to output its value. For this purpose, we have the set message. Many objects behave similarly in reception of this message, as follows:

A word of caution about initialization; it can often be a source of errors. Wrong or a missing initialization can cause our patches to malfunction or even to crash on startup. To suppress the firing of all our [loadbang] and [loadmess] patchers, press and hold command/Ctrl + shift while opening it. Try this with the debugging_initialization.maxpat patcher. After that, press the button in the upper-left hand corner to fire all of them with just one click. This little trick allows us to test our startup easily. You can see the patcher in the following screenshot, and at its bottom, a more sophisticated initialization technique. If we need to order lots of processes in time on a macro level, we should consider implementing something like the startup sequence with the addition of an abstraction.

Take the bottom part of this patcher with a grain of salt. Mostly, if things have to be ordered in time, such as loading a sample and then querying its length, they shouldn't be done this way. The [buffer~] object in which we can load samples, for example, sends out a bang on its right outlet if it has finished with reading the file. So, even processes that take an indefinite amount of time should be ordered by logic and not by time. Doing things such as this startup sequence seems professional and can help if you take care of what you are doing. It's great if we load a lot of things dynamically, but we should try to stay away from these things, especially for smaller patchers. The [trigger] object is our best friend when we have to put things in order. If we want something to happen after something else in terms of initialization, simply putting in a delay is unreliable and a bad idea. In seldom cases, we are forced to make use of [defer]/[deferlow] to move things to the low priority queue if we want a process to wait for things. Refer to the Event priority section for more information on the event queue and the scheduler.