What is a difference between [gen] and [gen~]?

Baek Santarek's icon

Hi guys,

  1. what is a difference between the two?

  2. Does data domain [gen] offer more precision over standard Max objects? Or is it "only" about being less CPU heavy?

Thank you!

👽'tW∆s ∆lienz👽's icon

there's no increase in precision, and it's not really about being less CPU heavy(some standard Max objects might be more efficient than if you worked your own math in 'gen'... but maybe you meant less CPU heavy than 'gen~'..)
if i recall correctly, it was just a convenient addition: 'gen~' was the initial environ, offering sample-accurate operations, 'gen' took that same environ and offered those operations in the event realm(the only difference is 'gen~' is on the audio scheduler, while 'gen' is on the event scheduler)

Baek Santarek's icon

Sorry, I am a bit confused by the answer. I completely understand the purpose of [gen~] but I still don't understand the purpose of [gen] (event realm).

I'll try to ask differently.

When should I use [gen] (event realm) instead of classic Max objects? What is the main advantage of [gen] (event realm) when it's running with the same precision as classic Max objects?

Thanks!

👽'tW∆s ∆lienz👽's icon

When should I use [gen] (event realm) instead of classic Max objects?

if you can do what you want with classic Max objects, then only use those, otherwise use [gen](event realm) all other times.

What is the main advantage...?

none. you can write math in a different way, more concisely, it can also attach to a clock differently, and allows for easier programming('easier' is just my opinion), but most things can be done without gen-event-realm anyways.

Baek Santarek's icon

Ah, OK! So I guess main advantage of gen(event realm) is codebox, right?

EDIT: Advantage when compared to classic Max objects I mean.

👽'tW∆s ∆lienz👽's icon

ya, codebox makes things there more like a regular programming language. more concise. that's an advantage. if you needed a sine wave or a phasor or other signal-like operations, but translated to event-math, that's another advantage.
but you could still do these things with classic Max objects... gen-event-realm simply makes it easier to program because the math is expressed in a more logical way - codebox is also called 'genexpr', which is also like the classic Max object: 'expr'(see helpfile)... so you could also see an advantage that gen-event-realm is like a nicely extended version of the 'expr' object.

Baek Santarek's icon

I see. Thanks a lot, Raja!

Graham Wakefield's icon

I've used gen for things that don't need to happen at audio rate.

For example, to initialize the content of a buffer~ that happens once (e.g. setting up an impulse response, filter coefficients, window function, etc.), rather than using a codebox in gen~ with some kind of once-only wrapper (like if(elapsed==0) {...}, which is my usual trick) or a wrapper that only happens very sporadically (again, rather than writing if(changed(someparam)) {...}). Another example where I used gen was my 'turn midi events into a byte buffer' patch, which again meant responding to sporadic events and writing into a buffer~.

One very specific advantage of the latter is that gen can trigger processing for more than one incoming message event per audio sample clock, whereas gen~ will only poll param values and will only process the algorithm once per sample clock.

Also, if you happen to have got more used to writing in gen~ than MSP, then gen can be a handy space to have to complement it :-)

Bradley Korth's icon

The biggest advantage of using gen in the event domain is the use of mc.gen. For example, this could allow me to have 100 counters without having 100 counter objects.

Asher's icon

if you can do what you want with classic Max objects, then only use those, otherwise use [gen](event realm) all other times.

Wait – does gen's internal processing run in the event domain? I was under the impression that it calculated the genExpr script in the space of one signal vector on the audio thread (like snapshot~). The object is still subject to the limit on calculations per vector and I frequently receive the "gen: audio processing exception: Too many iterations (runaway loop?)" message with using for and while loops. In my experience with experimenting with programming in gen patchers, the signal vector size does affect the amount of
calculations in For and While loops with BOTH gen and gen~.

MC.gen is even more confusing to me as it can (if i'm interpreting everything correctly): Receive an MC audio input, sample it within the space of a signal vector, and then convert it to Max event on output. Scary stuff. (EDIT: does this mean you can do polyphonic midi with MC.gen?)

Would really kill for an article or more documentation on how gen~/gen actually functions under the hood in comparison to Max event messages. E.G. If im performing a buffer operation in Gen(no tilde) vs writing to a buffer with peek~/poke~ max objects and messages... which is faster? Ideally would like a comparison of Max messages, gen, gen~, and js objects in terms of optimising algorithm design, because right now the information around the different modalities for scripting and control flow is rather opaque – the only things ive found are stuff about scheduling and and some clues from Graham on the Daisy forums. Please show us the way!!!!!!!

Bradley Korth's icon

mc.gen~ runs in the audio domain. mc.gen runs in the event domain.

If you mean gen~, the thing I like to use it for is the fact that it can perform calculations a bit faster in the audio domain than regular MSP objects, and that it is synchronized to the sample. MSP objects aren't always in sync with each other, but the inner workings of a gen~ are. The other thing is that sometimes I can use it instead of poly~ and avoid having to create a separate file for the poly~.

js objects, on the other hand, are what I like to use when I have a lot of logic to deal with that never touches the audio domain. You can do it in the general Max domain, but its readability is not as good, and you might need plenty of subpatchers.

Asher's icon

No sorry, I do mean gen(no tilde). You can obviously trigger gen with a bang and set parameters with Max events. However, I assumed (maybe incorrectly) that the actual genExpr script invoked by the gen object runs on the audio thread. I figured this to be the case because like I said before, the gen object is still subject to the calculation limit described here by Graham, where 'For safety, gen~ forces a limit on how many loop iterations can happen on each vector -- this limit is currently defined as 100000 * vector size.'

👽'tW∆s ∆lienz👽's icon

calculated the genExpr script in the space of one signal vector on the audio thread(like snapshot~)

the non-tilde version('gen') works with audio engine off(no audio thread involved.. snapshot~ can't work with audio off..(?))... if you look at the helpfile for the event-version, it's referring to 'event domain' and the 'sample rate' it refers to, is still in the event-domain, as with 'metro' specifying @interval by milliseconds:

One very specific advantage of the latter is that gen can trigger processing for more than one incoming message event per audio sample clock, whereas gen~ will only poll param values and will only process the algorithm once per sample clock.

🤯 wat??
(oh wait... i think i see what you mean... like 'uzi' can trigger gen to calculate event-thread inputs faster than gen~ will calculate audio-thread inputs... i think i need to see more examples with this specifically, having trouble picturing this difference..🤔🧐)

mc.gen~ runs in the audio domain. mc.gen runs in the event domain

ya (just like 'gen~' runs in audio, and 'gen' runs in event domain)...
..but i've not even tried mc.gen out yet! (100 parallel counters!! 😜🤘)
🤯 @chans 8 = 🤯 🤯 🤯 🤯 🤯 🤯 🤯 🤯

Asher's icon

Okay, I think I've worked out what the issue is which came from a misinterpretation on my part: in gen patchers, it seems like the vectorsize is fixed at 1, meaning that you can never perform more than 100000 (1 * 100000) calculations in a single triggering of the genExpr script. You can distribute the events over multiple ticks with a counter and @active 1 parameter, although took me a little bit to work out the syntax. Weirdly, I couldn't get > (100000 * vectorsize) control loops working in the gen~ patchers as either, which goes contrary to the....one forum post from 6 years ago lol. Anyway see this little study below to prove im not completely talking out of my ass.

gen vector debug.maxpat
Max Patch

vectorDebug.gendsp
gendsp 2.69 KB

👽'tW∆s ∆lienz👽's icon

^ah interesting, i've not looked at the .gendsp in detail, but i definitely see what you're saying about the limit now. Graham might be able to tell us more specifics about that limit, not sure how it exists under the hood - it's confusing for me to think about a 'vectorsize' when dealing with the event-realm, let alone a vectorsize of '1' (audio samples are collected into vectors for more efficient calculation and for sample-streaming to remain properly synchronized at sample-rate in audio-thread, but there seems no need to think in terms of a 'vector-size' within event-realm?...) i wonder, too, if scheduler preferences would make any difference on the total allowable calculations(scheduler interval, scheduler slop, poll throttle, queue throttle, event interval, etc.?)