(max) resonators and more poly~

High feedback, short-time delay lines can be used to resonate specified frequencies in a source signal. It’s the principle behind the resonators module in Cecilia. Creating a usable Max patch that performs this function takes a few steps, but can produce some very interesting sonic results.

To follow the discussion, you need to download the parent patcher, ResonatorBank.maxpat, and the poly~ subpatcher resonatorDelay~.maxpat.

specifying delay times as a function of pitch

For usability purposes, it is easier to specify the pitch you want to resonate, and convert that pitch to a corresponding delay time. In other words, you want to find the period of the frequency. The math to do that is simple:

T = 1/f

In Max, time is specified in milliseconds by default, so you would modify the equation to:

T = 1000/f

The subpatcher (p) midiToDelayTime performs this function, expecting pitch input in the form of MIDI note. The parent patch is setup to input MIDI notes from a MIDI keyboard or use a coll object to store sets of pitches (counted and routed to the different voices of the resonator bank). The converted delay times are sent to individual voices of the poly~ resonatorDelay by use of the target message.

using poly~ to create a bank of resonators, and more

By using poly~ we can create a bank of resonator processors. The resonatorDelay~ subpatcher is just a delay line (tapin~/tapout~) with feedback and adjustable output gain. (You need to adjust output gain down significantly as you increase delay line feedback.) But the use of poly~ allows for the adjustment of one additional, extremely needed parameter: signal vector size. The signal vector size determines the number of samples in a vector that are operated on in one function, and the size divided by the sample rate determines your minimum possible delay time. Smaller vectors give shorter possible delay times, but add a heavy hit to your cpu load. You can specify a different signal vector size for a poly~ object by use of the @vs attribute. The smaller vector applies only to the poly~ object, and won’t affect your cpu load as much as if you set the small size for the entire patcher. In the example patcher, I’ve set the signal vector size to 8 samples.

To understand the difference, Max usually operates at a 64 sample vector size (viewable in the audio status window). That size gives a minimum delay time of

64/44,100 = (approx) 1.45 ms, or about F5

Moving the signal vector size to 8 samples gives a minimum delay time of

8/44,100 = (approx) 0.18 ms, or about E8

Using the small vector size only in the poly~ saves you a few % points of cpu load, which can help in a complicated, processor-intensive patcher.

final note

You will notice that audio input and delay times to the poly~ are both sent to the first inlet. This combination works because the resonatorDelay~ subpatch defines both an in~ 1 (audio input to first inlet) and in 1 (data input to first inlet). Max understands to route the inputs by data type in the subpatch. Combining data inputs in a single inlet can help you reduce the number of inlets you need for a subpatch. Many audio objects make use of this data handling ability.