Max Externals: How to get an atom array with flexible length?

Shakeeb Alireza's icon

I'm trying to build my first c-api max external to run external code which can say retrieve data from the web and then output a message with a somewhat arbitrary number of atoms. Is it possible, directly or via the other types to create a (dynamic?) atom array without knowing beforehand the number of atoms which will populate it?

To make this a bit clearer, one can see in the max 8.0.2 sdk docs, there's a section called 'Atoms and Messages', which builds up an array of atoms that can be outputed with a bang using the `outlet_everything` method. I'll quote the relevant code snippet here:

void myobject_bang(t_object *x)
{
t_atom argv[3];
atom_setlong(argv, 43);
atom_setsym(argv + 1, gensym("crazy"));
atom_setfloat(argv + 2, 8.34);
outlet_anything(x->m_outlet, gensym("green"), 3, argv);
}


In this example, argv is initialized with a length of 3, which is fine if all atom arrays have a length of three, but if one wishes to be flexible, well then is there a well-known go to method or workaround?

Thanks in advance for any help!

Shak

Iain Duncan's icon

Hi Shak, I'm not sure if this is useful or not, but I was discussing this for mine with Alex Harker (who really knows max external dev) and he had a good point that it might be better to just over allocate and not have to worry about your routine calling dynamic memory allocation, given how cheap ram is now but how max threading is not something you want accidentally waiting. So I just went for allocating 1024 atoms myself and then keeping track of how many of those slots I used. That might be acceptable to you if you have a max length that is reasonable?

Luigi Castelli's icon

Hi there,

it depends how much flexibility you need and how general you want to be.
Obviously it also depends on your maximum list length.

Dynamically allocating 1024 atoms in the new method and then managing the array is probably gonna work most of the times but it won't cover all scenarios. The good thing about this approach is that you don't have to worry about dynamic allocation, so no threading issues. The cons is that you may be wasting memory, however I do agree with Iain (and Alex) that memory is cheap so no big deal if you are over allocating.

Here are two scenarios where this approach won't work:

1) A good example is [multislider] which is an object that is used all over the place in the Max world. Its limit is 32767 sliders. Do you really want to allocate that much memory when most likely the user will set its size at 8, 16 or even 256 sliders?
So a good solution would be to have an attribute in your object that lets the user set the maximum size.
You allocate when the user changes the size. Other than that, no allocations will take place during normal use of the object.

2) A different and more general example are the list operators.
In that case you need to be able to process lists of any size but you won't know the size until you receive the list in your object inlet(s).

There is a very handy little API function especially made for this purpose:
It will allocate memory on the stack if the allocation size is below a certain threshold or on the heap if above the threshold. You can allocate lists of any dimension, but beware that there could be a dynamic allocation in response to a Max message.

atom_dynamic_start();
atom_dynamic_end();

These are defined in ext_proto.h
This option might be a better fit for the specific user case outlined in the initial post.

There are also OBEX_UTIL_ATOM macros defined in ext_obex_util.h that would serve the same purpose.

Hope this helps.

- Luigi

Shakeeb Alireza's icon

Brilliant. Very helpful indeed. Thank you Iain and Luigo for your helpful answers.

Indeed, I defaulted to the over-allocation method initially which is not so bad during prototyping but I was curious about solutions to what must be a general problem and I didn't really find the topic directly addressed in the API docs.

I really appreciate the excellent pointers about the methods in the API which address this use case.

Thanks again.

Best,

Shak

Iain Duncan's icon

Oh great, I didn't know about that one either. Thanks Luigi, I'll be adopting this too.

iain