Forums > Dev

Attribute weirdness

December 10, 2010 | 9:48 pm

Hi,

II’m experiencing some weird attribute behaviour with one of my externals.

In the new routine I call:

attr_args_process (x, argc, argv);

The local variable then appears to be set correctly up until the end of the new routine.

At the next functon call to the object (that I am aware of) the local variable is no longer correct.

There is NOWHERE in the code where I set the local variable other than the top of the new routine (before the call to attr_args_process).

Any advice?

Alex


December 10, 2010 | 9:58 pm

Forgot to say. The externals are loaded in an abstraction with the attribute set using @chan #1…..

It works when I manually create the object… arrrrghhh…

Thanks

Alex


December 10, 2010 | 11:46 pm

Done some testing on a cut down version. In certain cases the attributes seemed to be parsed/set by MaxMSP *ontop* of the call to attr_args_process. The custom setters I have are being called twice…..

Is this a bug, or could it be caused by incorrect implementation. I’m pretty sure the same code works without issue in Max 4….

Thanks

Alex


December 11, 2010 | 10:49 am

Send some source code over. I’m sure it’s something one of us can quickly spot.


December 11, 2010 | 10:55 am

Hi Jeremy – following debug I’ve found it is a problem to do with the attribute being saved and a replaceable argument.

I’m not sure if this is *correct* behaviour but any advice you have is appreciated – source code shouldn’t be necessary but if it’s not clear from the below I’ll post it:

I have an abstraction that loads the external and tries to set one of the attributes using a replacable argument. Right now in a test version this looks like this:

[pctest~ 6144 4096 @offset 2048 @length 6144 @chan #1]

When I reload the abstraction with an argument I get the correct value in the new routine, but then I believe the saved value gets reloaded afterwards (I’m deferring low in the new routine to check the value just after). That’s why I’m seeing a second call to the other attributes. In the case of attributes that are set directly in the abstraction they are simply reloaded as the same value which is fine, but the replaceable argument has not (obviously) been saved with the abstraction….

Does this correspond to *correct* behaviour (I can see how it might). Is there a workaround other than making the attribute non-saveable?

Thanks

Alex


December 11, 2010 | 5:45 pm

Go ahead and send the source to me privately (jeremy (at) cycling74.com), if you don’t want to post it. But I would like to see the source before I get too far into checking this out.


December 11, 2010 | 5:54 pm

Hi,

I have a cut down example. I’m not too precious about the original source, but it’s 1000 lines long – most of which is irrelevant.

Even this could be smaller…. As far as I can see the new routine is called *then* saved attributes are reloading, so replaceable arguments have been saved in the abstraction as whatever a 0 would produce…..

The source works in max 4 because you can’t save attributes and that line was not being compiled.

Hope this all makes sense…



#include 
#include 
#include 

void *this_class;

typedef struct _pctest
{
    t_pxobject x_obj;
	void *obex;

	// Attributes

	long fft_size;
	long chan;
	long offset;
	long length;

} t_pctest;

void pctest_free(t_pctest *x);
void *pctest_new(t_symbol *s, short argc, t_atom *argv);

t_max_err pctest_length_set(t_pctest *x, t_object *attr, long argc, t_atom *argv);
t_max_err pctest_fftsize_set(t_pctest *x, t_object *attr, long argc, t_atom *argv);

void pctest_dsp(t_pctest *x, t_signal **sp, short *count);

int main(void)
{
	post ("YES");
	this_class = class_new("pctest~",
						   (method)pctest_new,
						   (method)pctest_free,
						   sizeof(t_pctest),
						   NULL,
						   A_GIMME,
						   0);

	class_addmethod(this_class, (method)pctest_dsp, "dsp", A_CANT, 0);

	class_addmethod(this_class, (method)object_obex_quickref, "quickref", A_CANT, 0);

	// Add attributes

	t_object *attr;

	class_obexoffset_set(this_class, calcoffset(t_pctest, obex));

	attr = attr_offset_new("fftsize", gensym("long"), 0, (method)0L,(method)pctest_fftsize_set, calcoffset(t_pctest, fft_size));
	class_addattr(this_class, attr);
	CLASS_ATTR_SAVE(this_class, "fftsize", 0);

	attr = attr_offset_new("length", gensym("long"), 0,(method)0L,(method)pctest_length_set, calcoffset(t_pctest, length));
	class_addattr(this_class, attr);
	CLASS_ATTR_SAVE(this_class, "length", 0);

	attr = attr_offset_new("offset", gensym("long"), 0,(method)0L,(method)0L, calcoffset(t_pctest, offset));
	attr_addfilter_clip(attr, 0, 0, 1, 0);
	class_addattr(this_class, attr);
	CLASS_ATTR_SAVE(this_class, "offset", 0);

	attr = attr_offset_new("chan", gensym("long"), 0, (method)0L,(method)0L, calcoffset(t_pctest, chan));
	attr_addfilter_clip(attr, 1, 4, 1, 1);
	class_addattr(this_class, attr);
	CLASS_ATTR_SAVE(this_class, "chan", 0);

	// Add dsp and register 

	class_dspinit(this_class);
	class_register(CLASS_BOX, this_class);

	return 0;
}

void pctest_free(t_pctest *x)
{
	dsp_free(&x->x_obj);
}

void testattr (t_pctest *x, t_symbol *s, short argc, t_atom *argv)
{
	post ("check chan %ld", x->chan);
}

void *pctest_new(t_symbol *s, short argc, t_atom *argv)
{
	// Setup the object and make inlets / outlets

	t_pctest *x = (t_pctest *)object_alloc(this_class);

    dsp_setup((t_pxobject *)x, 1);
    outlet_new((t_object *)x,"signal");

	// Set attributes from arguments

	attr_args_process (x, argc, argv);

	post ("the chan is %ld %ld", x->chan, x);
	defer_low(x, testattr, 0, 0, 0);

	return (x);
}

t_max_err pctest_length_set(t_pctest *x, t_object *attr, long argc, t_atom *argv)
{
	post ("Length set %ld %ld", x, atom_getlong(argv));

	return MAX_ERR_NONE;
}

t_max_err pctest_fftsize_set(t_pctest *x, t_object *attr, long argc, t_atom *argv)
{
	post ("FFT Called %ld %ld", x, atom_getlong(argv));
	return MAX_ERR_NONE;
}

void pctest_dsp(t_pctest *x, t_signal **sp, short *count)
{
}


December 11, 2010 | 6:08 pm

Saved attributes are definitely restored after typed-in values (which makes sense if you consider that Max doesn’t have a pointer to your object until you’ve returned from the new() function). This is one reason why CLASS_ATTR_SAVE() is recommended for use with UI objects, and not for normal newobj objects — manual attribute freezing is better in that case.

Your object code is 100% ok, as far as I can tell. If you get rid of the attr saving, you’ll be fine.


December 11, 2010 | 6:56 pm

Thanks Jeremy – yes that confirms everything I suspected. Everything else works fine – I just wasn’t aware that CLASS_ATTR_SAVE() is not recommended for non-UI objects (or really sure of the workings of freezing attributes).

Now I can see that removing it makes everything work and the same possibilities are still available to the user.

Thanks again,

Alex


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