Problem with buffer references in several instances of external object


    Jul 25 2021 | 7:02 pm
    Hi! I'm dealing with some sort of undefined behavior with buffer references in my external object (after fresh Max patcher start).
    I'm developing an object which is using references to (and also manages) two globally-defined buffers. My initialization routines are the same as in examples. While it works fine when I have one external object initialized, I have problems where I have two of them (I haven't tested more yet.). My second instance of external object is using different buffers with different names, but for some reason it can't find them.
    I've placed some logs like this (in the _new function):
    
    
     if (!buffer_ref_exists(x->first_buf)) {
    object_post((t_object *)x, "Incorrect buffer1 reference!");
    }
    if (!buffer_ref_exists(x->second_buf)) {
    object_post((t_object *)x, "Incorrect buffer2 reference!");
    } And it prints them, so it shows that buffers do not exists (or something similar, I don't know what it actually checks inside).
    But, when I'm deleting this object and creating a new one (with the same arguments), everything works fine.
    What can it be? Race condition of some kind? Incorrect buffer API usage? Wrong initialization routines? Some bug in the SDK?

    • Jul 26 2021 | 6:10 am
      When the new-method of your object is called doesn't mean that all other objects in the patcher are initialized already. Try the loadbang method or call a defered method to find the buffers.
    • Jul 26 2021 | 8:44 am
      Your way of testing doesn't make a lot of sense. As 11OLSEN said, in the case where your object is being instantiated BEFORE any buffer objects, you'll encounter the scenario you described. The way you account for that is to implement a notify method, so that your object will get notified by any new buffer object coming into existence. That will give you a chance to bind to the newly created buffer. For some examples look at the simpwave~.c and index~.c files in the Max SDK.
      - Luigi
    • Jul 26 2021 | 8:55 am
      My main reference is simpwave~ example. The test I described in the topic is not fully correct because my main logic is inside my notify method. And this is where it does not work, because for some reason buffers are initialized later for the second instance of my external object.
      I do not see specific logic in the simpwave~ where it should deal with such race conditions. From what I understand it tries to claim the buffer in the simpwave_perform64, and this function is called constantly due that this object need to output something. My situation is different. What I need to achieve is to trigger some logic when buffer is modified. I don't need to output signal and do computation constantly.
      This is how my notify method looks like:
      t_max_err MYOBJ_notify(t_MYOBJ *x, t_symbol *s, t_symbol *msg, void *sender, void *data) { t_buffer_obj* rec_buf; t_buffer_obj* loop_buf; rec_buf = buffer_ref_getobject(x->rec_buf); loop_buf = buffer_ref_getobject(x->loop_buf); object_post((t_object *)x, "Buffer notification triggered (msg: %s)", msg->s_name); if (!buffer_ref_exists(x->loop_buf)) { object_post((t_object *)x, "Incorrect loop buffer reference!"); } if (msg == ps_buffer_modified) { if (data == rec_buf) { process_buffer(x); object_post((t_object *)x, "Rec buf modified"); } if (data == loop_buf) { object_post((t_object *)x, "Loop buf modified"); } } if (data == rec_buf) { return buffer_ref_notify(x->rec_buf, s, msg, sender, data); } else if (data == loop_buf) { return buffer_ref_notify(x->loop_buf, s, msg, sender, data); } else { object_post((t_object *)x, "Can't find buffer reference!", data); return MAX_ERR_GENERIC; } }
      When rec_buf buffer is modified, I call a trigger for my logic. The issue is that even after patcher is loaded, for some reason it still can't find references to the buffer, and I need to re-create the object to make it work.
    • Jul 26 2021 | 10:32 am
      I think I found where is an issue. It is in my notify method. By replacing end of it like this
      else { object_post((t_object *)x, "Can't find exact buffer reference"); buffer_ref_notify(x->loop_buf, s, msg, sender, data); buffer_ref_notify(x->rec_buf, s, msg, sender, data); return MAX_ERR_NONE; }
      it started to see the buffers after patcher is loaded and I make changes to them.
      From documentation there is a statement that calling buffer_ref_notify is mandatory. I'm not sure that in my case where I have two buffers calling it like this is correct (since notify trigger is sent to one specific buffer, not for all buffers). I used this topic as a reference https://cycling74.com/forums/notify-method-when-accessing-two-buffers/, but it looks like implementation from there is not correct, and _notify method should call buffer_ref_notify to all buffers when it can't identify the specific buffer.
      Anyway, this behavior is very implicit and error-prone.