Hi all,

Let's assume you have an external, with this kind of code in it:

...
typedef struct _MyExternal {
  ...
  int        var_a;
  int        var_b;
  int        var_c;
  int        var_d;
  ...
  t_symbol* obj_name;
 ...
} t_MyExternal;
...

void MyExternal_calcandprint(t_MyExternal *x) {
  x->var_d = x->var_a + x->var_b + x->var_c;
  post("The external has obj_name %s with values %d (%d+%d+%d)", x->obj_name->s_name, x->var_d, x->var_a, x->var_b, x->var_c );
}

void MyExternal_seta(t_MyExternal *x, t_float f) {
  x->var_a = f;
  MyExternal_calcandprint(x);
}

void MyExternal_setb(t_MyExternal *x, t_float f) {
  x->var_b = f;
  MyExternal_calcandprint(x);
}

void MyExternal_setc(t_MyExternal *x, t_float f) {
  x->var_c = f;
  MyExternal_calcandprint(x);
}
...
  class_addmethod(MyExternal_class, (t_method)MyExternal_seta, gensym("seta"), A_FLOAT, 0);
  class_addmethod(MyExternal_class, (t_method)MyExternal_setb, gensym("setb"), A_FLOAT, 0);
  class_addmethod(MyExternal_class, (t_method)MyExternal_seta, gensym("setc"), A_FLOAT, 0);
...

So, let's say I want to set these variables from PD, in a message like this:

[ ;               <
[ recvobj seta 3; |
[ recvobj setb 4; |
[ recvobj setc 5; <

So, even if this content is in one message box, all of these message will be received individually, and so

  • first MyExternal_seta will run, calling MyExternal_calcandprint
  • then MyExternal_setb will run, calling MyExternal_calcandprint again
  • then MyExternal_setc will run, calling MyExternal_calcandprint yet again

The thing is, these messages could come from different message boxes, but all sort of close in time, and this is the case I want to handle - I want each set* function to run individually as they do - but I'd want MyExternal_calcandprint to run only once, once all the variables have been set.

However it is kind of impossible to predetermine whether only a, or also b and c will be changed in a call. So I imagine, if there existed a function, say, pd_defer_ctrl which I could use like:

void MyExternal_setc(t_MyExternal *x, t_float f) {
  x->var_c = f;
  pd_defer_ctrl( 5, x->MyExternal_calcandprint );
}

it would help me with my problem, if it worked like this - if PD is not in "defer mode", then it enters it, and sets a threshold of 5 ms from now; then it adds MyExternal_calcandprint to a queue. Then when next set* message comes in, PD sees its already in "defer mode", sees it arrived before the threshold of 5 ms has expired - and so it first checks if MyExternal_calcandprint is already in the queue, and if it is, it does not add it again. Finally, once the threshold of 5 ms has expired, PD then runs all the functions in the defer queue.

Is there something like that I could use in a PD external?


EDIT: Turns out Max/MSP probably already has such an API function, because I can see in bonk~.c source:

...
#ifdef MSP
static void bonk_write(t_bonk *x, t_symbol *s)
{
    defer(x, (method)bonk_dowrite, s, 0, NULL);
}
...

.... but I guess there is nothing like that for Pure Data...