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

dsmd's icon

I like this feature a lot. Mixing up abstractions with codebox code.

I am using the go gendsp files. A goldmine of useful gen based abstractions.
They use the naming convention of a dot in between the package and abstraction like go.harmonic. That dot is not allowed in function names in codebox. Is there a workaround or trick to use the name as is?

The only thing I found is working is to resave the abstraction under a different name like goHarmonic. Then save this in the project.

Roman Thilenius's icon

can objectmappings.txt work for that situation? like it does in the max canvas?

(take care, you must include the ".gendsp" in the object name if you do.)

dsmd's icon

interesting suggestion!

I can't get it to work though.

What I have done is.

  1. create a folder named "init" in the go package.

  2. added a file named "go-objectmappings.txt" to that folder.

Content of go-objectmappings.txt:

max objectfile goChance go.chance.gendsp;

Is this what you meant?

Roman Thilenius's icon

that sounds right, but i cant test it here locally.

in case it generally does not work with "objectmappings", i would try to use "substitutions" next.

dsmd's icon

I'm not entirely sure how this would work.

Wouldn't the method name in the end be substituted for the method name with dot?