A gen~ Tale: Follow(er) The Leader
The story goes like this....
I’m working away on my Max patch and I realize that I could really use an envelope follower — but not just any old envelope follower. I’m working with some very quick rhythmic elements (sometimes at audio rate), so my envelope follower is going to need to be as sample-accurate as possible.
Since the gen~ object runs on a per-sample basis internally, it’s perfect for this type of accuracy. I head over to check out the gen~ examples folder to see if there’s one there already.
Nope. There's no example!
But here’s one of my favorite things about Max, almost all the examples and patches can serve another purpose with the addition (or removal) of a few patch cords or objects. What you're about to see is an example of just that.
What I do find is this example of an implementation of the Max slide~ object in gen~. You can find it here:
Help > Examples > Gen > gen~.slide
When I open the gen~ object up and look at its internals, I quickly realize that I can switch it to a follower with some nifty additions.
This slide~ example patch works by monitoring the output. You can see the output running back up and into the history operator, which allows you to have a feedback loop (it adds one sample of delay).
That output value then runs into the right inlets of the > (greater than) operator and the minus - (minus) operator.
The > operator is receiving the input value (It’s either one or zero in the beginning) and — depending on whether this is greater than or less than the value into the > operator's right inlet — it sends a one or zero to the ? operator.
The ? operator selects between the second or the third inlet depending on whether the first argument is true (1) or false (0). The value sent to the second inlet of the ? operator will be passed to the outlet of the ? operator if the value at the first inlet is true and the value sent to the third inlet of the ? operator will be passed to the outlet if the value into the ? operator is false.
The key object in this Gen patcher that gives us our envelope is the - (minus) operator. Each time our input value switches between one or zero, the - operator is subtracting the current output value (minus 1 sample of delay because of history) from either one or zero. This value is then multiplied by the slide up and slide down values, which in turn are run into our ? operator (which is functioning as a Boolean switch here), thus giving us our slide (or its soon-to-be envelope).
So how do we turn this into an envelope follower?
The key ingredient in converting this patch to an envelope is to turn the toggle switch, converting the one or zero switches into a trigger inside the gen~ patcher that will accept a real-time audio signal and generate a one or zero, depending on the signal value passing the threshold amount we've set.
To do that, we need to declare the threshold as a parameter value using the param operator with the following attributes set: param threshold @min 0 @max 1 @default .5.
This does two things:
It sets the initial state of our > operator (.5)
It also allows us to have our attribute accessible via an attrui object outside of the gen~ patch, giving us the ability to change the threshold in real-time in the parent Max patcher.
Now let’s add a > (greater than) operator, and used our named parameter threshold. Here's what our patching looks like:
We want to add one more object just above the > threshold operator to give us greater accuracy when detecting the threshold.
Let’s add an abs (absolute value) operator. This will give us the absolute value of our incoming signal, translating any negative values to positive ones.
Now that we've modified the slide up/slide down portion of the patch, all we need to do to trigger our envelope is to send in an audio signal to the first inlet of our gen~ patch and set the threshold to our desired amount.
Set the envelope up to 0 and envelope down (this is the amount in samples) to something lower. If we play in a drum loop, we can see the envelope being generated each time the signal goes above our threshold.
We have a follower!
Ok, now let’s do some fun stuff with our follower — we’re almost done here.
Let’s pipe the audio through to an additional * operator to allow us to use the envelope as a transient shaper of our incoming signal.
Run the audio from the outlet of the in 1 operator directly to the left inlet of the * operator. We’re adding our envelope follower output to the right inlet of the * operator to shape the audio.
But before we do that, we want to add a little more control to our envelope follower.
Something that a lot of envelope followers allow you to do is to invert the follower. This is useful as a control signal and for shaping in certain ways, such as ducking other sounds for the kick drum etc.
We’re going to do this with two operators, and also add one more param operator so we have a simple switch accessible from outside of the gen~ object that allows us to invert our envelope.
Beneath the + operator, let's add a !- 1 (subtraction with the inlets reversed) operator.
We need to expose the flip param to the Max patcher outside of our gen~ object by adding another param operator: param flip @min 0 @max 1 @default 0
Once we've set up the parameter, we'll add a named version of the mix operator (mix flip), and connect a patch cord from the outlet of the + operator to the input of the !- operator and to the left input of the mix flip operator.
Connect a patch cord from the outlet of the !- 1 operator to the right inlet of the mix flip operator, and a patch cord from the outlet of the mix flip operator to the right inlet of the * (multiply) operator.
We’re in business!
Now we can go back to Max and run some audio into our gen~ envelope follower, dial in the threshold and also invert the follower to our liking.
Here's our final gen~ patch:
And the Max patch:
Check out this video of the patch in action and download the example below.
Happy patching!
by Tom Hall on March 4, 2020