Abstraction for mixing or crossfading two audio signals

Image

This patch is functionally identical to the mix~ abstraction in Example 1; you can read its explanation there. It’s repeated here in order to begin a series of examples regarding “initialization”: setting up the initial state of your program the way you want it. This patch demonstrates the use of a # argument in an object box to designate a value that can be specified in the parent patch when this patch is used as an abstraction (an object in some other patch). When this patch is used as an object in another patch by typing its filename into an object box, whatever is typed in as the first argument in that object box will be used in place of the #1, wherever it appears in this patch. (Subsequent arguments in the parent patch could be accessed with #2, #3, etc.) If nothing is typed in as an argument in the parent patch, the # arguments will be replaced by the integer value 0.

In this example, the #1 argument means that the initial crossfade value (to specify the balance between the audio signals coming in the first two inlets) can be typed into the object box in the parent patch. Notice that if the user does not type in any argument, the default behavior of this patch will be to send out only the audio signal of the left inlet, because the crossfade value will be 0 by default, resulting in a multiplier of 1 for audio signal 1 and a multiplier of 0 for audio signal 2.

[You can read a thorough explanation of the # argument in an excerpt from the Max 4 manual regarding the changeable arguments $ and #.]

An important thing to notice in this abstraction is that it has been constructed in such a way that the crossfade value coming in the rightmost inlet can be provided either as a float or as a control signal. If a person just wants to set a static crossfade value, a float is sufficient. It can be typed in as an argument and/or provided in the right inlet. For a dynamically changing value, though, a control signal is better. If, in the parent patch, a MSP signal is connected to the rightmost inlet of this patch, then any typed-in argument (and any float in the right inlet) will be ignored by the right inlets of the -~ and *~ objects in this patch.

Rhythmic automated panning

Image

This example allows a choice of four different modes of intensity panning, and two ways to specify the rate of panning change. The choice of four possible pannings is: static centered, left-to-right sudden switching, left-to-right gradual gliding, and random gliding. The rate of change can be controlled by sliders, either in Hertz (changes per second) or note values (based on the current transport tempo).

A few objects and techniques here bear some explanation. The bit-shift operator >> shifts the binary form of an integer some number of bits to the right, which is equivalent to dividing by a power of 2. So shifting an integer 3 bits to the right is equivalent to an integer division by 8 (with the remainder being discarded). Why not just use a / 8 object? No reason (although it’s perhaps a little more computationally efficient). It’s just a nerdy way to scale down a range of numbers, by focusing only on the most significant bits of its binary form. The radiogroup object allows you to create a related set of mutually exclusive buttons, providing the user a choice of one (and only one) of several options. It sends out the index number of the selected button (counting up from 0).

The pcontrol object allows certain types of automated control of a subpatch or abstraction. One thing you can do is totally disable the MIDI and audio functions of a subpatch or abstraction, with the message enable 0 (and enable 1 to re-enable it). Inside those patcher objects that are getting enabled/disabled by the radiogroup, the audio chain of each one ends with a pass~ object. The pass~ object normally passes audio signals through unchanged, but it sends out a constant signal value of 0 whenever its patcher is disabled. This is crucial so that the subpatch doesn’t get stuck sending out a constant non-zero signal when it’s disabled. The fact that all the subpatches send out 0 when they’re disabled means that they don’t get in the way of the one subpatch that is enabled, when the signals all are added together in the right inlet of the patcher pan~ object.

Granulation of a recorded sound

Image

In classic granular synthesis, grains are very short windowed segments of sound, normally from 5 ms to 100 ms in length. A stream of sound grains be spaced at exactly the same time interval as the grain length, or at some greater interval of time. The spacing can even be randomized (some random time interval greater than or equal to the grain length). A single stream of grains is all you can do with a single groove~ object.

Although it’s not demonstrated here, you could have a multiplicity of such streams going with multiple groove~ objects, or with multiple instances in a poly~ object, which would result in some overlapping of grains, making a “cloud” of grains, and if it’s a dense enough cloud it starts to sound like one continuous sound.

This is an example patch that creates one steady stream of grains randomly chosen from a 10-second recording. You can set the grain length and the grain spacing to whatever timings you want. Here we use a 5 ms attack time and a 5 ms release time, so the minimum grain length in our case is 10 ms. Therefore, we limit the minimum grain spacing to 10 ms, too. (The number box setting the time interval for the metro object has had its minimum value set to 10 in the Inspector.) Each grain starts at a randomly-chosen start time in a 10-second buffer~. Each grain is also assigned a random loudness and a random panning. To make grains that are more like notes than grains, you can make grain lengths/spacings that are greater than 100 ms.

Test movie timing to make editing decisions

Image

You can use the gettime message to ask jit.qt.movie for a report of its video’s current time location (in QuickTime time units). The report comes out of the right outlet of jit.qt.movie as the word ‘time’ followed by the current time. If you send the gettime message at regular reliable intervals of time, you can use the resulting time number to test for a particular time (or range of times), and thus can take a particular action in your program at the desired time in a movie.

This can be useful for realtime editing of the movie itself, using the current time location to decide to leap to another location in the movie. In this case, we’re assuming that we already know the timescale of the movie, and that we’re synchronizing it with some music with a tempo of 75 beats per minute. So with a little arithmetic, we can figure out the relationship between milliseconds, QuickTime time units, and metric units of the music. In this example, we query (ask for and get) the movie’s time every 25 milliseconds, which is every 1/40 of a second, which is 15 QuickTime time units at the timescale of 600, which is every 128th note in the music. And we can calculate that there are 480 time units per beat, and thus 1920 time units in a 4/4 measure of music. We do an integer division by 1920 to convert time units into measures, and thus can detect the downbeat of each measure.

In this example, when we get to the downbeat of measure 17 (i.e., after 16 measures have elapsed), we make a probabilistic decision. Should we go ahead, or should we jump back to a previous place in the movie? The example shows one model for weighted decision making; this model is useful if you have a really small set of choices and really simple probabilities. Here, three choices each have a 1/6 probability of occurring, and a fourth choice (to proceed ahead) has a 3/6 probability of occurring because 3 of the 6 possible random numbers do nothing.

Testing for a range of numbers

Image

If you want to detect when a number has occurred that fits within a particular range, you’ll want to use “logical operators” to test conditions such as “is less than”, “is less than or equal to” or “is greater than this and less than that”. Most logical operators send out the number 1 (meaning “true”) if the condition is met, and 0 otherwise. The split object sends out its left outlet all input numbers that fall within a specified minimum and maximum, and sends the rest of its input numbers out the right outlet. The “and” operator && sends out a 1 if both of its inputs are true (non-zero), and 0 otherwise.