Forums > Dev

multiple atoms return by A_GIMMEBACK

February 1, 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


February 1, 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
>
>

http://www.nano-soundworks.com


February 1, 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


February 7, 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
>
>


February 7, 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


February 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);
> }
> }
>


February 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


Viewing 7 posts - 1 through 7 (of 7 total)