A useful subpatch for mixing and balancing two sounds

Image

To mix two sounds together equally, you just add them together. If you know that both sounds will frequently be at or near full amplitude (peak amplitude at or near 1) then you probably want to multiply each sound by 0.5 after you add them together, to avoid clipping. However, if you want to mix two sounds unequally, with one sound having a higher gain than the other, a good way to accomplish that is to give one sound a gain between 0 and 1 and give the other sound a gain that’s equal to 1 minus that amount. Thus, the sum of the two gain factors will always be 1, so the sum of the sounds will not clip. When sound A has a gain of 1, sound B will have a gain of 0, and vice versa. As one gain goes from 0 to 1, the gain of the other sound will go from 1 to 0, so you can use this method to create a smooth crossfade between two sounds.

This example employs that mixing technique and implements it as a patch that can be used as an object inside another patch. It’s handy for easily mixing and/or adjusting the balance of two audio signals. Save the patch as a file with a distinct and memorable name such as “mix~.maxpat” somewhere in the Max file search path. Then you can use it as a subpatch (also often called an “abstraction”) in any other patch just by making an object named “mix~”. The audio signals go into the left and middle inlets and the mix value from 0 to 1 goes into the right inlet. There are three ways to specify the balance: 1) as an argument typed into the object box, 2) as a float in the right inlet, or 3) as a signal in the right inlet. Using a signal to control mixing is the best choice if you intend to change the mix dynamically.

Whatever goes in the inlets of the mix~ object in the main patch comes out the corresponding inlet objects in the mix~ subpatch, and the mixed signal comes out the outlet. The sig~ object provides a constant signal in which every sample has the same value, in this case a constant value of 1. The argument #1 will be replaced by whatever is typed into the mix~ object box as an argument in the parent patch; if nothing is typed in, it will be 0, and if a signal is attached in the main patch then the signal value will be used. This allows the user to type in an argument to specify the initial balance value in one of the *~ objects, and the -~ object provides 1 minus that value to the other *~ object. That initial balance value can be replaced by sending in a float or a signal.

Mixing multiple audio processes

Image

pinger: a beeping test sound.

This patch is designed to be used as an abstraction (subpatch) in the next example. In order for the next example to work, you should download this example and save it with the filename “pinger.maxpat” somewhere in the Max file search path.

Its purpose is just to generate a recognizable sound. It emits very short sinusoidal beeps of a specified frequency, at a rate of a specified number of beeps per second, panning back and forth from left to right a specified number of times per second. These three parameters — tone frequency, note rate, and panning rate — are specified as arguments 1, 2, and 3 in the parent patch.

Because this abstraction was designed just to be used as a test tone in a particular example, it just uses the simple #1#2, and #3 arguments as a way of providing the parameter values (as unchangeable constants typed in the parent patch). To make a more versatile program, one could also provide inlets to receive variable values, and could use patcherargs to provide useful default initial values. Compare, for example, the lmap abstraction.

 

Mixing multiple audio processes

For this example to work correctly you will need to first download the pinger abstraction above and save it with the filename “pinger.maxpat” somewhere in the Max file search path.

This example shows the use of the matrix~ object to mix together different sounds. Think of matrix~ as an audio mixer/router (a kind of combination of mixer and patch bay). The first two arguments specify the number of inlets and outlets, and the third argument specifies the default gain factor for each inlet-outlet connection.

Inlets and outlets of matrix~ are numbered starting from 0. So, in this example there are 16 inlets (numbered 0 to 15) and 2 outlets (numbered 0 to 1). (There’s always an extra outlet on the right, from which informational messages are sometimes sent.)

Messages to the left inlet of matrix~ generally take the form of a four-item list to specify an inlet, an outlet to be connected that inlet, a gain factor (multiplier) for sounds that will flow from that inlet to that outlet, and a ramp time to transition smoothly to that gain factor (to avoid clicks). You can send as many such messages as you’d like, to specify as many connections as you want.

In this example we have connected eight stereo pinger objects to the 16 inlets of matrix~, and we will mix them all together for a single stereo output. The pinger objects are just stand-ins for what could potentially be any eight different audio processes you might want to mix together. The arguments to pinger specify frequency of the beep tone, the number of notes per second, and the rate of panning. For example, the first pinger plays a 220 Hz tone 1 time per second (i.e., at a rate of 1 Hz), panning left to right once every two seconds (i.e. at a rate of 0.5 Hz). The next pinger plays a 330 Hz tone at a rate of 1.5 notes per second (i.e. once every 666.6667 milliseconds), panning left to right once every three seconds (i.e., at a rate of 0.33333 Hz), and so on. The result is 8 tones (harmonics 2 through 9 of the fundamental frequency of 110 Hz) at 8 different harmonically-related rhythmic rates, panning back and forth at 8 different harmonically-related rhythmic rates.

With matrix~ you can mix these eight tones in any proportion you want, but how can you easily control all eight amplitudes at once? If you had a MIDI fader box, you could map the eight control values from the faders to the gain factors of the various connections. In the absence of such a fader box, we use the multislider object, set to have 8 sliders, that sends out a list of eight values from 0. to 1. corresponding to the vertical position of each slider as drawn with the mouse. So, by clicking and/or dragging with the mouse on the multislider you can set eight level values for use by matrix~. That list of eight values is sent to the right inlet of the right message box so we can see the values, and it’s also sent to the left inlet of the left message box where the values are used in sixteen different connection messages to matrix~.

Take a moment to examine and understand those messages. The first message says “connect the first inlet [inlet 0] to the first outlet [outlet 0] multiplied by a gain factor [the value of the first slider] with a transition time of 100 milliseconds, and so on. Each pair of messages controls a pair of inlets corresponding to one of the pingers, and sets the gain with which that pinger will go to the output.

Turn on audio audio by clicking on the ezdac~, then try out the patch by moving the sliders in the multislider. Note that when you add together eight different audio processes, each playing at full volume, you need to be careful about the sum of all your gain factors. A more elaborate patch would, at the least, provide a volume control for the final summed signal. Even more desirably, perhaps, the final volume control could be constantly controlled automatically, proportionally to the sum of the slider values, to prevent clipping of the output signal.

Using matrix~ for audio routing and mixing

Image

The matrix~ object is an audio mixer/router that can be configured with any number of inlets and outlets. The arguments specify the number of audio inlets, the number of audio outlets (there’s always one additional outlet on the right), and the initial gain for the connections of inlets to outlets. Each inlet is potentially connectable to each outlet with a unique gain setting. The gain of the connections is changed by sending messages in the left inlet.

The messages in the left inlet of matrix~ specify an inlet number (numbered starting from 0), an outlet number, a gain factor for scaling the amplitude of that connection, and a ramp time in milliseconds to arrive at that amplitude. You can send as many such messages as needed to establish all the desired connections.

The patch on the left shows how matrix~ can be used to route a signal to multiple destinations. The first message connects inlet 0 to outlet 0 with a gain factor of 1 and a ramp time of 10 milliseconds, which is to say that it quickly opens the first outlet. The next message sets all four outlets to an amplitude of 0.25, but assigns a different fade time to each outlet, which shows that matrix~ can be used as a mixer as well as a simple router. The third message quickly turns off all four outlets (turns them all to 0 amplitude in 10 ms).

This method of sending a message for each possible connection may seem a bit cumbersome, but in fact it’s about the most efficient way to control a large matrix (a virtual patchbay) of possible connections. With some clever message management, you can control or automate a great many constantly-changing connections. The patch on the right automates a constantly-changing mix of four sound sources.

Every four seconds (or whatever time interval you choose) the metro bangs an uzi object which outputs four messages (numbers from 0 to 3 out its right outlet, and four bangs out its left outlet), which in turn trigger four messages to matrix~. Each bang from uzi chooses a random amplitude from -12 dB to -42 dB, packs it with a connection number and a transition time, and formats that as a connection message for matrix~.