programmatic change of class attribute filter and enumval list?


    May 20 2014 | 4:06 pm
    In the Max SDK... given an attribute "fooattrib" which is declared on a max class and points to a char field in the class struct fooattrib is style=enumindex and enumvals="jane, sam" and filterset_clip=0,1 An object in Max has been created based on this class.
    Now a state change happens in my external. I want to change the enumvals and filterset_clip to be... enumvals="jane, sam, melonie" and filterset_clip=0,2
    How can I achieve this? Or something similar to this? I have yet to find a way to redefine attr's of attr's of classes. That would be great because then I could make the change and it would cascade to all the objects instantiated.
    If not possible to do something like that just mentioned, could I define the class *minus* fooattrib and then on object instantiation create a object attribute on that specific object...and then somehow later during this state change delete/change that specific object attribute?
    Ideas?

    • May 24 2014 | 11:59 am
      Hi Diablodale,
      since no C74 guru has replied yet, I will give you an example of how this could be accomplished:
      Let's say you have two attributes "foonames" and "fooattrib". We will change the enumindex and filter_clip of "fooattrib" programmatically, based on the values that "foonames" takes on.
      #define MAX_NAMES 64
      
      typedef struct _myobj
      {
          t_jbox          box;
          t_symbol        *foonames[MAX_NAMES];
          long            foonamecount;
          char            fooattrib;
      } t_myobj;
      
      in main we define two class attributes...
      CLASS_ATTR_SYM_VARSIZE(c,           "foonames",         ATTR_FLAGS_NONE, t_myobj, foonames, foonamecount, MAX_NAMES);
      CLASS_ATTR_DEFAULT_SAVE_PAINT(c,    "foonames",         ATTR_FLAGS_NONE, "Jane Sam");
      	
      CLASS_ATTR_CHAR(c,                  "fooattrib",        ATTR_FLAGS_NONE, t_myobj, fooattrib);
      CLASS_ATTR_ENUMINDEX(c,             "fooattrib",        ATTR_FLAGS_NONE, "Jane Sam");
      CLASS_ATTR_DEFAULT_SAVE_PAINT(c,    "fooattrib",        ATTR_FLAGS_NONE, "0");
      CLASS_ATTR_FILTER_CLIP(c,	    "fooattrib",        0, 1);
      
      the magic happens in the notify function...
      t_max_err myobj_notify(t_myobj *x, t_symbol *sym, t_symbol *msg, void *sender, void *data)
      {
          t_object *attr;
          t_object *attr2;
          t_symbol *attrname;
          
          if (msg == gensym("attr_modified")) {
              attr = (t_object *)data;
      	attrname = (t_symbol *)object_method(attr, gensym("getname"));
      	if (attrname == gensym("foonames")) {
                  attr2 = object_attr_get(x, gensym("fooattrib"));
                  if (attr2) {
                      t_atom argv[MAX_NAMES];
                      long argc = x->foonamecount;
                      long i;
                      
                      // update enumvals
                      for (i = 0; i < argc; i++) {
                          atom_setsym(argv+i, x->foonames[i]);
                      }
                      object_attr_setvalueof(attr2, gensym("enumvals"), argc, argv);
                      
                      // update filter_clip
                      attr_addfilter_clip(attr2, 0, argc-1, 1, 1);
                      
                      // check that fooattrib is still in range
                      if (x->fooattrib >= argc) {
                          x->fooattrib = argc-1;
                      }
                          
                      // notify that attribute has been changed
                      object_notify(x, gensym("attr_modified"), attr2);
                  }
              }
          }
          return jbox_notify((t_jbox *)x, sym, msg, sender, data);
      }
      
      There is one thing I am not 100% sure about: when calling attr_addfilter_clip() there should be a new filter_clip object being created and added to the attribute. I am not sure what happens to the previous filter_clip object... Logically it should be freed but since I have no access to the C74 codebase I cannot guarantee it. If it doesn't get freed then we have a memory leak. I don't know if the Max API makes provisions for it to be changed dynamically after creation. I can tell you that in my short and quick tests the code works without problems though.
      This could suggest that instead of using a filter_clip object, it could be better to use a custom setter for "fooattrib" and manage the clipping in there. Perhaps this could be a better alternative...
      Hope this helps
      - Luigi
    • Jun 04 2014 | 3:36 pm
      It would be nice to know what strategy you ended up using and if you go it working in the end...
      - Luigi