Defer and Usurp with regular Max/MSP attributes
I am working on a complex UI external that has a ‘numelems’ attribute.
The attribute is implemented as follows:
CLASS_ATTR_LONG(c, "numelems", ATTR_FLAGS_NONE, t_myobject, numelems); CLASS_ATTR_ACCESSORS(c, "numelems", NULL, myobject_numelems_set); CLASS_ATTR_LABEL(c, "numelems", ATTR_FLAGS_NONE, "Number of Elements"); CLASS_ATTR_DEFAULT_SAVE_PAINT(c, "numelems", ATTR_FLAGS_NONE, "4"); CLASS_ATTR_FILTER_CLIP(c, "numelems", 1, 1024); CLASS_ATTR_ORDER(c, "numelems", ATTR_FLAGS_NONE, "1");
The attribute uses a custom setter because every time a new ‘numelems’ is set, several memory allocations, event generations and data calculations are performed. This becomes especially slow when the number of elements is set to a high value. The problem is that in a Max patcher the ‘numelems’ attribute could be set repeatedly by the user at high priority. Obviously, this should be avoided at all costs since it could potentially bring the Max scheduler to a halt.
Immediately I am thinking that something needs to be deferred… :)
So, learning from the good ol’ Jitter, I would like to give the attribute getter and setter respectively the DEFER_LOW and USURP_LOW behavior. That’s because I want both the latest high priority value when the next ‘numelems’ change is triggered at low priority and no low priority queue backlog from generating more events at high priority than can be processed at low priority. Obviously that goes hand in hand with a deferred getter to preserve the order of execution in case the attribute is queried by the user.
Now, I see ATTR_GET_DEFER_LOW | ATTR_SET_USURP_LOW flags in ext_obex.h, however it says they are "placeholders for potential future functionality".
Has this functionality been already implemented as of Max 6.0.4 ?
If not, what would be the way to achieve the same without using attribute flags?
Should I create custom getter and setter and put a
defer_low() in my getter and a
qelem() in my setter?
Any comment/advice is highly appreciated.
I’m doing it with a simple defer_low() inside my setter, with a lot of stuff going on in your setter, you should probably use qelem().
Since you limit "numelems" to 1024, maybe there is is also a way to allocate the memory in advance in your new() method?
thanks for your reply…
Yes, the ‘obvious’ way would be to manually code a defer_low() or qelem() in the setter/getter methods, however I wanted to find out if Max could already do that for you automatically. Attribute flags such as ATTR_GET_DEFER_LOW or ATTR_SET_USURP_LOW made me hope for that.
In any case your answer brings up an interesting point.
Is it generally better to allocate memory in advance (meaning in the ‘new’ method) or not?
In the above example even though I do limit "numelems" to 1024 each element is pretty big.
I would rather allocate memory as need be, instead of doing a big allocation in advance, but I could be wrong…
I am aware it depends on many factors specific to one’s project, however It would be interesting to know if people recommend/prefer one technique over the other and why.
Thanks for listening.
These flags only apply to Jitter objects currently.