multiple atoms return by A_GIMMEBACK


    Feb 01 2008 | 11:30 am
    Hi list,
    I'd like to use A_GIMMEBACK, to register a method which returns multiple
    atoms, as opposed to just one. The only documentation I found was this post
    by Joshua a while a go:
    t_max_err obex_tester_gimmeback(t_obex_tester *x, t_symbol *s, long
    ac, t_atom *av, t_atom *rv)
    {
    post("obex tester gimmeback av = %d",atom_getlong(av));
    if (ac && av) {
    atom_setlong(rv,atom_getlong(av)*atom_getlong(av));
    } else {
    atom_setlong(rv,-1);
    }
    return MAX_ERR_NONE;
    }
    I want to do something similar, but with more than one return value, say an
    array of 16 atoms. Is this possible? How would I register a function like
    that in my class?
    I know using an untyped method would be easier to return values, but the
    reason I want to use A_GIMMEBACK is that I'd like to expose the method to
    JS/JAVA as well.
    Thijs

    • Feb 01 2008 | 2:08 pm
      I just realized that if I'm going to be passing atoms around, I might as
      well turn the array into an attribute and query that using object_attr_get*.
      If the same is possible using A_GIMMEBACK and there is still a valid reason
      for using it in modern obex/jitter land, I'd love to hear about it.
      Cheers,
      Thijs
      On Feb 1, 2008 11:30 AM, Thijs Koerselman wrote:
      > Hi list,
      >
      > I'd like to use A_GIMMEBACK, to register a method which returns multiple
      > atoms, as opposed to just one. The only documentation I found was this post
      > by Joshua a while a go:
      >
      >
      > t_max_err obex_tester_gimmeback(t_obex_tester *x, t_symbol *s, long
      > ac, t_atom *av, t_atom *rv)
      > {
      > post("obex tester gimmeback av = %d",atom_getlong(av));
      > if (ac && av) {
      > atom_setlong(rv,atom_getlong(av)*atom_getlong(av));
      > } else {
      > atom_setlong(rv,-1);
      > }
      > return MAX_ERR_NONE;
      > }
      >
      > I want to do something similar, but with more than one return value, say
      > an array of 16 atoms. Is this possible? How would I register a function like
      > that in my class?
      >
      > I know using an untyped method would be easier to return values, but the
      > reason I want to use A_GIMMEBACK is that I'd like to expose the method to
      > JS/JAVA as well.
      >
      >
      > Thijs
      >
      >
      --
    • Feb 01 2008 | 6:28 pm
      I don't know if/where this is documented, but the short answer is
      that you create a new atomarray object. If you're making a jitter
      object, where you want the gimmeback to report out the dumpoutlet in
      the maxwrapper and return an array from calling the method like the
      jit.qt.videoout object's getvoclist method, then here's how that is
      done in case it's useful.
      In Max class definition:
      // define a max wrapper method which uses the standard dumpout call
      to output GIMMEBACK vals
      max_addmethod_defer_low((method)max_jit_obex_gimmeback_dumpout,
      "getvoclist");
      In Jitter class definition:
      // define the method as A_CANT so it won't be exposed to Max directly
      jit_class_addmethod(_jit_qt_videoout_class, (method)
      jit_qt_videoout_getvoclist, "getvoclist", A_CANT, 0L);
      // define a typed wrapper method for use in JS/Java. the max wrapper
      will also call this one and send out outlet
      jit_class_addtypedwrapper(_jit_qt_videoout_class, (method)
      jit_qt_videoout_getvoclist, "getvoclist", A_GIMMEBACK, 0L);
      t_jit_err jit_qt_videoout_getvoclist(t_jit_qt_videoout *x, t_symbol
      *s, long ac, t_atom *av, t_atom *rv)
      {
      // this is simplified from the actual source, but assume we have
      argc/argv atoms in our object...
      //create a new atom array object, atoms are copied into object, and
      set an atom with type object
      atom_setobj(rv, object_new(ps_nobox, ps_atomarray, c->voc_argc, x-
      >voc_argv));
      return JIT_ERR_NONE;
      }
      Hope this helps.
      -Joshua
    • Feb 07 2008 | 12:19 pm
      Hi Joshua,
      Sorry for the late reply, I got caught up in other things.
      Thanks a lot for the example code, I really appreciate it. I'm going to give
      it a try today but I think this is exactly what I'm looking for. I'm pretty
      sure all of this is not documented anywhere. A search for A_GIMMEBACK in the
      pdf's doesn't even come up with anything.
      Just to make sure I understand what's going on... The symbol/ac/av from the
      gimmeback method call are not used, only rv. The rv pointer is the place
      where you copy the atom array to. This array can be of any size and is set
      by the argc/argv arguments which you pass its constructor. The memory for
      this array is freed after the dumpoutlet call, or after converting the
      return values to JS/Java datastructures. Is that correct?
      Could you possibly explain a bit about the jit_class_addtypedwrapper()
      function? What does it do exactly? The docs only say "Retrieves typed
      wrapper messlist pointer associated with name provided. "... that doesn't
      exactly ring a bell here.
      Best,
      Thijs
      On Feb 1, 2008 6:28 PM, Joshua Kit Clayton wrote:
      >
      >
      > I don't know if/where this is documented, but the short answer is
      > that you create a new atomarray object. If you're making a jitter
      > object, where you want the gimmeback to report out the dumpoutlet in
      > the maxwrapper and return an array from calling the method like the
      > jit.qt.videoout object's getvoclist method, then here's how that is
      > done in case it's useful.
      >
      >
      > In Max class definition:
      >
      > // define a max wrapper method which uses the standard dumpout call
      > to output GIMMEBACK vals
      > max_addmethod_defer_low((method)max_jit_obex_gimmeback_dumpout,
      > "getvoclist");
      >
      > In Jitter class definition:
      >
      > // define the method as A_CANT so it won't be exposed to Max
      > directly
      > jit_class_addmethod(_jit_qt_videoout_class, (method)
      > jit_qt_videoout_getvoclist, "getvoclist", A_CANT, 0L);
      > // define a typed wrapper method for use in JS/Java. the max
      > wrapper
      > will also call this one and send out outlet
      > jit_class_addtypedwrapper(_jit_qt_videoout_class, (method)
      > jit_qt_videoout_getvoclist, "getvoclist", A_GIMMEBACK, 0L);
      >
      >
      > t_jit_err jit_qt_videoout_getvoclist(t_jit_qt_videoout *x, t_symbol
      > *s, long ac, t_atom *av, t_atom *rv)
      > {
      > // this is simplified from the actual source, but assume we have
      > argc/argv atoms in our object...
      > //create a new atom array object, atoms are copied into object, and
      > set an atom with type object
      > atom_setobj(rv, object_new(ps_nobox, ps_atomarray, c->voc_argc, x-
      > >voc_argv));
      > return JIT_ERR_NONE;
      > }
      >
      >
      > Hope this helps.
      >
      > -Joshua
      >
      >
    • Feb 07 2008 | 8:38 pm
      On Feb 7, 2008, at 4:19 AM, Thijs Koerselman wrote:
      > Thanks a lot for the example code, I really appreciate it. I'm
      > going to give it a try today but I think this is exactly what I'm
      > looking for. I'm pretty sure all of this is not documented
      > anywhere. A search for A_GIMMEBACK in the pdf's doesn't even come
      > up with anything.
      Yeah, this is one of those "bleeding edge" kinds of features in Max
      4.5 + that we hope to document better in the Max 5 SDK. For now,
      forum questions are probably the best way to get info on this. We'll
      try to be relatively responsive on it (though we are busy with Max 5
      work).
      > Just to make sure I understand what's going on... The symbol/ac/av
      > from the gimmeback method call are not used, only rv.
      Technically the symbol ac av are used as input. rv is the return
      value output.
      > The rv pointer is the place where you copy the atom array to. This
      > array can be of any size and is set by the argc/argv arguments
      > which you pass its constructor. The memory for this array is freed
      > after the dumpoutlet call, or after converting the return values to
      > JS/Java datastructures. Is that correct?
      Yes. It is an A_OBJ atom which you can't pass through outlets, but
      can be used internally by C code, or the JS/Java wrappers. It's freed
      by the caller using freeobject. Here's our Jitter
      max_jit_obex_gimmeback_dumpout() function which illustrates how such
      methods are used in our max jitter wrappers, but it's similar for our
      JS/Java/Lua method calling wrappers too.
      void max_jit_obex_gimmeback_dumpout(void *x, t_symbol *s, long ac,
      t_atom *av)
      {
      t_atom rv;
      t_atom *rav=NULL;
      long rac=0;
      object_method_typed(max_jit_obex_jitob_get(x),s,ac,av,&rv);
      if (rv.a_type == A_NOTHING) return;
      if (rv.a_type==A_OBJ) {
      object_getvalueof(rv.a_w.w_obj,&rac,&rav);
      } else {
      rac = 1;
      rav = &rv;
      }
      if (s&&s->s_name[0]=='g'&&s->s_name[1]=='e'&&s->s_name[2]=='t')
      s = gensym(s->s_name+3);
      max_jit_obex_dumpout(x,s,rac,rav);
      if (rv.a_type==A_OBJ) {
      if (rac&&rav)
      freebytes(rav,rac*sizeof(t_atom));
      if(rv.a_w.w_obj)
      freeobject(rv.a_w.w_obj);
      }
      }
      > Could you possibly explain a bit about the
      > jit_class_addtypedwrapper() function? What does it do exactly? The
      > docs only say "Retrieves typed wrapper messlist pointer associated
      > with name provided. "... that doesn't exactly ring a bell here.
      It adds a typed function that can be called from JS/Java/Lua (or even
      C) for otherwise A_CANT methods that are only callable from C.
      Usually this is the place where we use A_GIMMEBACK. Max messages
      can't call A_GIMMEBACK or A_CANT methods directly either FWIW, which
      is why we have the max wrapper dumpout function included above for
      our Jitter object max wrappers.
      Hope this helps.
      -Joshua
    • Feb 23 2008 | 1:08 pm
      Hi Joshua,
      I finally got around to implementing it. Its pretty clear to me how this all
      works now. The Lua/JS interface is very essential for what I'm trying to
      achieve, and I'm really happy its all working now.
      I understand from your last email that the atomarray object supports the
      pattr sdk, and that's why you are able to call object_getvalueof() on it,
      right?
      Thanks a lot for all the detailed inside information. This was really
      helpful.
      Cheers,
      Thijs
      On Thu, Feb 7, 2008 at 8:38 PM, Joshua Kit Clayton wrote:
      >
      > Yes. It is an A_OBJ atom which you can't pass through outlets, but
      > can be used internally by C code, or the JS/Java wrappers. It's freed
      > by the caller using freeobject. Here's our Jitter
      > max_jit_obex_gimmeback_dumpout() function which illustrates how such
      > methods are used in our max jitter wrappers, but it's similar for our
      > JS/Java/Lua method calling wrappers too.
      >
      > void max_jit_obex_gimmeback_dumpout(void *x, t_symbol *s, long ac,
      > t_atom *av)
      > {
      > t_atom rv;
      > t_atom *rav=NULL;
      > long rac=0;
      >
      > object_method_typed(max_jit_obex_jitob_get(x),s,ac,av,&rv);
      > if (rv.a_type == A_NOTHING) return;
      > if (rv.a_type==A_OBJ) {
      > object_getvalueof(rv.a_w.w_obj,&rac,&rav);
      > } else {
      > rac = 1;
      > rav = &rv;
      > }
      > if (s&&s->s_name[0]=='g'&&s->s_name[1]=='e'&&s->s_name[2]=='t')
      > s = gensym(s->s_name+3);
      > max_jit_obex_dumpout(x,s,rac,rav);
      > if (rv.a_type==A_OBJ) {
      > if (rac&&rav)
      > freebytes(rav,rac*sizeof(t_atom));
      > if(rv.a_w.w_obj)
      > freeobject(rv.a_w.w_obj);
      > }
      > }
      >
    • Feb 23 2008 | 6:27 pm
      On Feb 23, 2008, at 5:08 AM, Thijs Koerselman wrote:
      > I finally got around to implementing it. Its pretty clear to me how
      > this all works now. The Lua/JS interface is very essential for what
      > I'm trying to achieve, and I'm really happy its all working now.
      Glad to hear.
      > I understand from your last email that the atomarray object
      > supports the pattr sdk, and that's why you are able to call
      > object_getvalueof() on it, right?
      Correct.
      -Joshua