typedmess --- mess0, mess1, mess2 --- s->s_thing

    Dev

    Luigi Castelli
    Jul 20 2007 | 6:07 pm
    Hi there,
    can someone shed some light on the typedmess function and the messN macros ? mess0, mess1, mess2, etc... seem to be wrappers for the getfn functions to send untyped messages to objects.
    1 - Can someone provide an example on how to use mess1 for instance ? my confusion lies in the fact that even though the SDK says th messN macros are to be used for untyped messages they do work for typed messages as well. Why the distinction then ?
    2 - In connection to those I am also confused about the usage of the s_thing field in the t_symbol data structure. It seems that the s_thing is used to indicate to which object the message is supposed to be sent to. However I don't quite understand how the binding mechanism works.
    3 - In my specific case I would like to send the 'size' message to an existing buffer~ object from my own custom external. I would appreciate it if someone would explain the following line of code taken from index~.c
    if ((b = (t_buffer *)(s->s_thing)) && ob_sym(b) == ps_buffer) { x->l_buf = b; }
    Is that the correct way to go to send the 'size' message to buffer~ (the 'size' message takes 1 argument) ?
    Should I use typedmess or messN ? Any checks I need to do ?
    Thanks for any knowledge you guys are able to provide.
    - Luigi
    ------------------------------------------------------------ THIS E-MAIL MESSAGE IS FOR THE SOLE USE OF THE INTENDED RECIPIENT AND MAY CONTAIN CONFIDENTIAL AND/OR PRIVILEGED INFORMATION. ANY UNAUTHORIZED REVIEW, USE, DISCLOSURE OR DISTRIBUTION IS PROHIBITED. IF YOU ARE NOT THE INTENDED RECIPIENT, CONTACT THE SENDER BY E-MAIL AT SUPERBIGIO@YAHOO.COM AND DESTROY ALL COPIES OF THE ORIGINAL MESSAGE. WITHOUT PREJUDICE UCC1-207. ------------------------------------------------------------
    Park yourself in front of a world of choices in alternative vehicles. Visit the Yahoo! Auto Green Center. http://autos.yahoo.com/green_center/

    • Eric Lyon's icon
      Eric Lyon
      Jul 21 2007 | 7:20 pm
      Hi Luigi,
      Here is my interpretation of that code:
      if ((b = (t_buffer *)(s->s_thing)) && ob_sym(b) == ps_buffer) { x->l_buf = b; }
      First you're setting b to point to s_thing which is the object (if any) bound to symbol "s", cast as a buffer. Then you're checking to see if that object is in fact a buffer. If it is, you store that buffer in x->l_buf. This code doesn't send any messages to the object. I'd look at dblclick as an example of sending a message.
      One of my dblclicks looks like this, and it's swiped directly from one of the Max examples (can't recall which one).
      void bashfest_dblclick(t_bashfest *x) {
      t_buffer *b; t_symbol *wavename = x->wavename;
      if ((b = (t_buffer *)(wavename->s_thing)) && ob_sym(b) == gensym("buffer~")) mess0((t_object *)b,gensym("dblclick")); }
      Maybe you could use something like that to send a buffer a size message.
      Let us know if it works.
      Best,
      Eric
      Share
    • Luigi Castelli's icon
      Luigi Castelli's icon
      Luigi Castelli
      Jul 21 2007 | 10:48 pm
      Hi Eric,
      what you say makes perfect sense.
      I am wondering if I should use mess1 and not mess0 since the 'size' message requires an argument (the size in ms).
      No, but wait... 'dblckick' is an untyped message so they use the messN macros. 'size' is a typed message, so maybe I should use typedmess instead.
      Well... I am still a little confused. If someone at C74 could academically clarify it all I would be grateful.
      On top of it all I just discovered some code by Peter Castine who writes a ForwardAnything method as follows:
      void ForwardAnything(Symbol* iRecip, Symbol* iMsg, short iArgC, Atom iArgV[])
      { static Symbol* sSymThrough = NIL;
      Object* thing = (Object*) iRecip->s_thing;
      // Initialize our static symbol first time through if (sSymThrough == NIL) sSymThrough = gensym("through");
      // Make sure we have a vaild thing if (thing == NIL) return; // no good if (thing->o_magic != MAGIC) return; // still no good if (ob_class(thing)->c_sym != sSymThrough) return; // last check
      // If we make it to here, we're good to go typedmess(thing, iMsg, iArgC, iArgV);
      }
      I would love for Peter or someone to explain to me what's actually happening in this code, since I cannot make much sense out of it. Why all those checks? and what's the o_magic field all about ?
      Thanks for the bandwidth.
      - Luigi
      --- Eric Lyon wrote:
      > > Hi Luigi, > > Here is my interpretation of that code: > > if ((b = (t_buffer *)(s->s_thing)) && ob_sym(b) == ps_buffer) { > x->l_buf = b; > } > > First you're setting b to point to s_thing which is the object (if > any) bound to symbol "s", cast as a buffer. Then you're checking to > see if that object is in fact a buffer. If it is, you store that > buffer in x->l_buf. This code doesn't send any messages to the > object. I'd look at dblclick as an example of sending a message. > > One of my dblclicks looks like this, and it's swiped directly from > one of the Max examples (can't recall which one). > > void bashfest_dblclick(t_bashfest *x) > { > > t_buffer *b; > t_symbol *wavename = x->wavename; > > if ((b = (t_buffer *)(wavename->s_thing)) && ob_sym(b) == > gensym("buffer~")) > mess0((t_object *)b,gensym("dblclick")); > } > > Maybe you could use something like that to send a buffer a size > message. > > Let us know if it works. > > Best, > > Eric >
      ------------------------------------------------------------ THIS E-MAIL MESSAGE IS FOR THE SOLE USE OF THE INTENDED RECIPIENT AND MAY CONTAIN CONFIDENTIAL AND/OR PRIVILEGED INFORMATION. ANY UNAUTHORIZED REVIEW, USE, DISCLOSURE OR DISTRIBUTION IS PROHIBITED. IF YOU ARE NOT THE INTENDED RECIPIENT, CONTACT THE SENDER BY E-MAIL AT SUPERBIGIO@YAHOO.COM AND DESTROY ALL COPIES OF THE ORIGINAL MESSAGE. WITHOUT PREJUDICE UCC1-207. ------------------------------------------------------------
      ____________________________________________________________________________________Ready for the edge of your seat? Check out tonight's top picks on Yahoo! TV. http://tv.yahoo.com/
    • Eric Lyon's icon
      Eric Lyon's icon
      Eric Lyon
      Jul 22 2007 | 10:23 pm
      Hi Luigi,
      I would recommend to spend some quality time with ext_mess.h and the SDK 4.5.5 Manual ;^)
      Actually I couldn't resist trying, and verified that it's pretty straightforward to send a message using typedmess(). Probably some of the macros you mentioned would make it even easier.
      Cheers,
      Eric === // wavename is a t_symbol member of the object // t_floatarg is defined as double for Max
      void buffet_resize_buffer(t_buffet *x, t_floatarg newsize) { short argc = 1; t_atom *argv; t_symbol *sizemsg;
      argv = (t_atom *) malloc(sizeof(t_atom)); sizemsg = gensym("size"); SETFLOAT(argv,newsize);
      t_buffer *b;
      if ((b = (t_buffer *)(x->wavename->s_thing)) && ob_sym(b) == gensym("buffer~")) { if( ! b->b_valid ){ // error message } else { post("sending a message"); typedmess((void *)b, sizemsg, argc, argv); post("all done"); } } else { // error message } free(argv); }
    • Thijs Koerselman's icon
      Thijs Koerselman's icon
      Thijs Koerselman
      Jul 26 2007 | 9:06 am
      You don't have to use malloc() and free(), do you? I find this bit cleaner and easier to understand, and probably safer too, since you don't check if the malloc failed or not. (?)
      cheers, -thijs
      void buffet_resize_buffer(t_buffet *x, t_floatarg newsize) { t_buffer *b; short argc = 1; t_atom argv;
      SETFLOAT(&argv,newsize);
      if ((b = (t_buffer *)(x->wavename->s_thing)) && ob_sym(b) == gensym("buffer~")) { if( ! b->b_valid ){ // error message } else { post("sending a message"); typedmess((void *)b, gensym("size"), argc, &argv); post("all done"); } } else { // error message } }
      On 7/22/07, Eric Lyon wrote: > > > > > void buffet_resize_buffer(t_buffet *x, t_floatarg newsize) > { > short argc = 1; > t_atom *argv; > t_symbol *sizemsg; > > argv = (t_atom *) malloc(sizeof(t_atom)); > sizemsg = gensym("size"); > SETFLOAT(argv,newsize); > > t_buffer *b; > > if ((b = (t_buffer *)(x->wavename->s_thing)) && ob_sym(b) == > gensym("buffer~")) { > if( ! b->b_valid ){ > // error message > } else { > post("sending a message"); > typedmess((void *)b, sizemsg, argc, argv); > post("all done"); > } > } else { > // error message > } > free(argv); > } > >
    • Eric Lyon's icon
      Eric Lyon's icon
      Eric Lyon
      Aug 01 2007 | 8:53 am
      > You don't have to use malloc() and free(), do you?
      No, but I used it so I wouldn't need an annoying ampersand in the function call :)
      > I find this bit cleaner > and easier to understand,
      Your version is tighter, but "easier to understand" is somewhat subjective.
      > and probably safer too, > since you don't check if > the malloc failed or not. (?) >
      Good point, though I wonder how often malloc() would fail to be able to find enough memory for a single t_atom these days ...
      Best,
      Eric
    • Peter Castine's icon
      Peter Castine's icon
      Peter Castine
      Aug 02 2007 | 9:43 pm
      Quote: Luigi Castelli wrote on Sun, 22 July 2007 00:48 ----------------------------------------------------
      > I would love for Peter or someone to explain to me what's actually > happening in this code, ----------------------------------------------------
      Not that there's anything particularly proprietary about it, but this was not Open Source code. I guess it is now.
      The code is based on information I cobbled together out of the SDK, combined with some coding conventions followed inside the Litter Power code base. I've already replied to Luigi privately, but since the question and the code are now on the list, we might has well include my extended comments on this forum:
      >void >ForwardAnything(Symbol* iRecip, Symbol* iMsg, short >iArgC, Atom iArgV[]) > >{ > static Symbol* sSymThrough = NIL;
      we want to cache gensym("through") rather than recalculate it every time, because gensym() is, as these things go, expensive. However, we can't initialize to a fuctnion call like gensym() at compile time! So, initialize to NIL at compile time, and test for NIL at runtime (as below, the if statement is still cheaper than calling gensym()) and the first time the function is called the static variable is set up properly.
      The way this function is called, minimizing gensym() calls is probably not worth the effort. But this technique is force of habit for me.
      > Object* thing = (Object*) iRecip->s_thing; > > // Initialize our static symbol first time through > if (sSymThrough == NIL) > sSymThrough = gensym("through"); > > // Make sure we have a vaild thing > if (thing == NIL) > return; // no good > if (thing->o_magic != MAGIC) > return; // still no good
      In Max lots of pointers get passed around, particularly void*, and using 1980's C-programming style, there is no compile-time type checking or the like. So the o_magic member is set by newobject() to a "magic value" and by freeobject() it is set to null (or something different from MAGIC). I believe this convention was introduced in Max by Miller, in any case it is used to provide a sanity check against bad pointers at runtime. While not absolutely necessary, it is a Good Idea. You may think that you will never pass a bad pointer to this function, but you might be wrong!
      There is a good Wikipedia article on using conspicuous bit patterns to try to trap memory allocation errors and pointer misuse. I don't have internet right now, but if you Google wikipedia.org for 0xFEEDBEEF or 0xDEADBEEF or 0x0A0A0A0A you should be able to find it. It explains the thinking behind the MAGIC convention used in Max.
      > if (ob_class(thing)->c_sym != sSymThrough) > return; // last check >
      Have you looked at the definition of the macro ob_class? It's another Max idiosyncracy. Anyway, the left side of the condition returns a symbol that is the name of an object's class. There is an invisible class 'through' which is the backend for all receive objects (there may be some legacy involved here; if you look at Miller's early Max papers, some of the common core objects had different names back in 1986).
      > // If we make it to here, we're good to go > typedmess(thing, iMsg, iArgC, iArgV); > >}
      Spero che questo aiuti, Peter (relegated to an internet cafe in sunny Florida)