Feature request: subpatcher invocation from within codebox / GenExpr

Dan Gayle's icon

Currently, composing gen~ algorithms from reusable abstractions requires working at the visual patcher level. It would be very useful to be able to invoke a gen abstraction as a function call from within a GenExpr.

gen (which loads a .gendsp abstraction) and setparam (which drives named parameters inside a subpatcher) are both exclusively visual objects. There is no equivalent within GenExpr codebox code. The only related construct in GenExpr is Param (capital P), which declares an externally-drivable parameter, but requires passing params via setparam in the parent patcher.

This means that if you're authoring a complex algorithm inside a codebox, you cannot call out to an abstraction. You have to either inline everything, or split your design across mixed codebox/visual-patcher layers, which can get unwieldy.

Something along the lines of this would be cool, no need for complex import statements:

out1, out2 = gen("example.filter", in1, freq: cutoff, q: resonance);

This would allow building modular, composable DSP algorithms entirely within the codebox authoring context, treating abstractions as first-class callable units rather than requiring a context switch to visual patching just to wire in a subpatcher.

Graham Wakefield's icon

Hi Dan,

Actually this already works, but the syntax is a little different.

Let's say you save a gen patcher as "supadupa.gendsp", either in the same folder as your main Max patch, or in some searchable path, then you can invoke it as if it was a function inside a codebox, e.g. :

out1 = supadupa(in1);

The only thing to watch out for is to not use characters in the gendsp file name that would not be valid characters for a function name in GenExpr. It should start with a letter, then can have letters, numbers and underscores in the name -- but not a "." character for example. (Oh, and also make sure not to use a file name that is a built-in gen operator!)

If the gendsp has Param objects, you can also address these in the function call, e.g.:

out1 = supadupa(in1, myparam=74);

If there is any embedded state, such as history or data, or any stateful operators such as phasor, cycle, delta, etc. , then each literal instance of the supadupa() call in your codebox will create a new instance of all the state. (Note that this does not apply to multiple calls within a for loop, as these are only a single literal instance.)

This has always been a very rarely-used feature -- I'm not sure how many people even know about it.

Graham