This week, I'm going to finish out our short series on Gen with a quick look at perhaps the least well-known of the Gen family: the gen object. Yep, "gen" without the tilde.
One of the parts of working with gen~ that either bedeviled beginning users or involved some extra patching for to others was managing the transition between the single-sample audio domain of the gen~ object and the event-driven Max world outside of the gen~ object itself. Those problems tended to take the form of several questions:
What techniques can I use to trigger my gen~ object?
How can I handle output timing?
The gen object was born during the development of Max 8’s MC functionality (you’ll note that there are mc.gen~andmc.gen objects, for example).
So what’s it for?
Simply put, the gen object lets you create Gen patches whose Max event-domain processing routines are similar to what you can do with audio using the gen~ object. In addition, the gen object lets you work with the kind of embedded code expressions you’ll recognize right away from working with the Max expr object.
Let’s start with that. You can use the gen object as a replacement for the Max expr object by using the @expr attribute: just type @expr, followed by the expr-syntax of the calculation you want to perform. Using the @expr attribute this way operates as you expect regular Max objects to work: the left inlet of the gen object is the “hot” inlet that triggers output.
The @hot attribute, followed by a 1 will modify your gen object so that any inlet will trigger the calculation. Nice, huh?
Our mutual friend Mr. Zicarelli tells me that gen @expr as a way to of doing calculation will actually be faster than the expr object – particularly if you keep performing the calculation multiple times.
In addition to typing mathematical expressions directly into the gen object box, you can use it in the more traditional Gen manner where you edit an embedded patcher that uses standard gen~ operators. And, as is the case with the standard gen~ object, any parameters you add to your embedded patcher using the param operator will automatically be accessible as attributes via the attrui object or by sending Max messages to the gen object.
As we’ve seen, you can use the standard “hot” outlet method to trigger output using the @expr attribute (and modify it to your liking using the @hot 1 attribute), But the gen object gives you a couple of other interesting options.
One of the standard questions in the gen~ world involved what to do because the gen~ object didn’t understand bang messages. Good news – the event-based gen object does just that.
But the gen object also has the equivalent of its own internal metro object that lets you specify the rate at which the gen object outputs data.
You use the @interval attribute to set the output rate in milliseconds, and the @active attribute to enable/disable output.
Here’s an interesting use of these features along with the @expr attribute to create an event-domain LFO whose rate you can change (When you change the value for the @interval attribute, the object’s sample rate is updated and the patch is recompiled):
The gen object, though humble, lets you to work at any resolution in the event domain.
From gen~ to gen
One of the places where I’ve personally found the gen object to be incredibly helpful lies in moving my old gen~ patches into the event domain. What surprised me is that I often don’t need to do much of anything to my patches to port them over. I’ll leave you with two examples.
Just for fun, I cracked open the somewhat complex gen~ patcher that makes the Vizzie ATTRACTR module tick to see if I could reuse it. Porting it was a good deal simpler than I ever expected: I copied the contents of the original gen~ patcher (shown here)…
…created a gen object, opened it, and pasted my original gen~ patcher’s contents in. Everything I pasted in copied over with no problem – a sure sign that all the operators were all interoperable.
Once I had a look at my inlets, I realized that everything was there – since in 1 used a value of 0 to “freeze” the device, all I needed to do was to hang a toggle on the first inlet of the gen object. Similarly, to set the rate of the calculation, I added the @interval 20 @active 1 attributes to my gen object, and then hooked up a live.dial and a message box pair to send the message interval <value> to the gen object. Resetting the calculation is as simple as sending the reset message.. Presto! Event-domain Navier-Stokes patching with gen!
As you know, I’m a big LFO user. Since I was on a roll, I wondered about how tough it’d be to take my go-to gen~ LFO patching and try that inside the gen object.
While it’s often the case that what happens in the audio domain stays in the audio domain (viva Las Vegas), it’s often the case that I’ll be dragging out some snapshot~ objects to drop things into the event domain for use as parameters.
Everything from my standard LFO patch pasted in just fine once again, but I needed to do just a little bit of housekeeping, which basically involved using a phasor operator inside of the gen patcher as a starting point (I used an external phasor~ object when working at audio rate), which converted the left inlet of my gen object to a Frequency input. I did a little parameter rearrangement, and added a final scale operator to move things into the 0. – 1.0 range that Vizzie modules expected.
The result was a quick and very peppy little module I could drop into a bpatcher and use with my Vizzie programming.
Hmmm. I guess I could convert the OSCIL8r and 4OSCIL8R Vizzie modules to use this technique, couldn’t I?
Anyway, I hope this give you a quick look at a slightly less-well-known but still really useful member of the Gen family. Happy patching!
Great article, and thanks for covering event-domain gen. It would be amazing to see you expand on this: "The gen object, though humble, lets you work at any resolution in the event domain." I think I know what you mean by resolution, but it's not obvious when to change event resolution and why this is such a powerful feature.