Forums > Dev

pattr objectname confusion

January 24, 2008 | 4:39 pm

To anyone who might be able to help….
Below is the C file for an object I am developing. All works fine with this object, except that I just cannot work out how to set the object instance’s name (ie the name pattr uses to bind to the object). I had initially thought, looking through the pattr sdk, that the object_register/object_attach method was the way to go.
The only example in code I see is the regob example in the sdk.

My questio is;
1 – Am I correct in assuming that this is the method for registering ‘client’ objects, created during initialization of the regob object, and NOT the manner in which to name the instance of my object? (I have tried including the object_register/attach method in the new method of my object, but to no avail).
As you can see from the code, I have created an attribute named ‘name’, which I don’t really need to have as an attribute, I just added it to test that the symbol_unique command works as I imagined, which it seems to do. Ideally I would like the object instance’s name to be set as with the pattr object, ie as a typed in first argument. I figure that if I could work out just how to create the ‘name’ in the first place then I should be able to work that out.
Thanks to anyone who might be abke to help on this..I must have tried a fair few configurations to try and make this work, but there’s obviously something I’m not ‘getting’!
regards
Leigh

/*
lhpattr
Copyright 2004 – Cycling ’74
jeremy bernstein – jeremy@bootsquad.com
*/

#include "ext.h"
#include "ext_common.h"
#include "ext_obex.h"

typedef struct lhpattr
{
t_object ob;
void *obex;
float fval;
float fprv;
float ffinal;
t_symbol *symval;
t_atom atomarray[32];
long atomarraycount;
char mode;
void *out;
float minval;
float maxval;
float encadj;
float modadj;
float modrtn;
} t_lhpattr;

void *lhpattr_new(t_symbol *s, long argc, t_atom *argv);
void lhpattr_free(t_lhpattr *x, t_symbol *s);
void lhpattr_assist(t_lhpattr *x, void *b, long m, long a, char *s);
void lhpattr_anything(t_lhpattr *x, t_symbol *s, long argc, t_atom *argv);
void lhpattr_bang(t_lhpattr *x);
void lhpattr_output(t_lhpattr *x);
void lhpattr_pattrmode(t_lhpattr *x, int mode);
t_max_err lhpattr_setattr(t_lhpattr *x, void *attr, long ac, t_atom *av);
t_max_err lhpattr_fval(t_lhpattr *x, void *attr, long ac, t_atom *av);
t_max_err lhpattr_encadj(t_lhpattr *x, void *attr, long ac, t_atom *av);
t_max_err lhpattr_modadj(t_lhpattr *x, void *attr, long ac, t_atom *av);
// pattr support function prototypes
t_max_err lhpattr_getvalueof(t_lhpattr *x, long *ac, t_atom **av);
t_max_err lhpattr_setvalueof(t_lhpattr *x, long ac, t_atom *av);

void *lhpattr_class;

int main(void)
{
t_class *c;
void *attr;
long attrflags = 0;

c = class_new("lhpattr", (method)lhpattr_new, (method)lhpattr_free, (short)sizeof(t_lhpattr),
0L, A_GIMME, 0);

// initialize the common symbols, since we want to use them
common_symbols_init();

// register the byte offset of obex with the class
class_obexoffset_set(c, calcoffset(t_lhpattr, obex));

// add some attributes

attr = attr_offset_new("min", _sym_float32, attrflags,
(method)0L, (method)lhpattr_setattr, calcoffset(t_lhpattr, minval));
class_addattr(c, attr);

attr = attr_offset_new("max", _sym_float32, attrflags,
(method)0L, (method)lhpattr_setattr, calcoffset(t_lhpattr, maxval));
class_addattr(c, attr);

attr = attr_offset_new("enc", _sym_float32, attrflags,
(method)0L, (method)lhpattr_encadj, calcoffset(t_lhpattr, encadj));
class_addattr(c, attr);

attr = attr_offset_new("mod", _sym_float32, attrflags,
(method)0L, (method)lhpattr_modadj, calcoffset(t_lhpattr, modadj));
class_addattr(c, attr);

attr = attr_offset_new("ffinal", _sym_float32, attrflags,
(method)0L, (method)lhpattr_setattr, calcoffset(t_lhpattr, ffinal));
class_addattr(c, attr);

attr = attr_offset_new("fval", _sym_float32, attrflags,
(method)0L, (method)lhpattr_fval, calcoffset(t_lhpattr, fval));
class_addattr(c, attr);

attr = attr_offset_new("name", _sym_symbol, attrflags,
(method)0L, (method)0L, calcoffset(t_lhpattr, symval));
class_addattr(c, attr);

attr = attr_offset_array_new("array", _sym_atom, 32, attrflags,
(method)0L, (method)0L,
calcoffset(t_lhpattr, atomarraycount), calcoffset(t_lhpattr, atomarray));
class_addattr(c, attr);

// add methods to the class
class_addmethod(c, (method)lhpattr_bang, "bang", 0);

// these methods support the pattr set of objects
class_addmethod(c, (method)lhpattr_getvalueof, "getvalueof", A_CANT,0);
class_addmethod(c, (method)lhpattr_setvalueof, "setvalueof", A_CANT,0);

// add methods for dumpout and quickref
class_addmethod(c, (method)object_obex_dumpout, "dumpout", A_CANT, 0);
class_addmethod(c, (method)object_obex_quickref, "quickref", A_CANT, 0);

// we want this class to instantiate inside of the Max UI; ergo CLASS_BOX
class_register(CLASS_BOX, c);
lhpattr_class = c;

return 0;
}

t_max_err lhpattr_setattr(t_lhpattr *x, void *attr, long ac, t_atom *av)
{
if (ac && av) {
t_symbol *name = object_method(attr, _sym_getname);
long pattrmode = 0;

if (name == gensym("min")) {
x->minval = atom_getfloat(av);
pattrmode = 2;
} else if (name == gensym("name")) {
x->symval = atom_getsym(av);
pattrmode = 1;
} else if (name == gensym("max")) {
x->maxval = atom_getfloat(av);
pattrmode = 3;
} else if (name == gensym("ffinal")) {
x->ffinal = atom_getfloat(av);
pattrmode = 6;
return MAX_ERR_NONE;
}
lhpattr_pattrmode(x, pattrmode);
}
return MAX_ERR_NONE;
}

t_max_err lhpattr_fval(t_lhpattr *x, void *attr, long ac, t_atom *av)
{
if (ac && av) {
float f = atom_getfloat(av);
float mod = x->modrtn;
float min = object_attr_getfloat(x, gensym("min"));
float max = object_attr_getfloat(x, gensym("max"));
if (f > max) {
f = max;
}
else if (f < min) {
f = min;
}
if (f != x->fprv) {
x->fval = f;
x->fprv = f;
if (((f != max)&&(f != min))||((f == min)&&(mod > 0))||((f == max)&&(mod < 0))) {
f += mod;
}
object_attr_setfloat(x, gensym("ffinal"), f);
x->ffinal = f;
lhpattr_pattrmode(x, 0);
lhpattr_output(x);
}

}
return MAX_ERR_NONE;
}

t_max_err lhpattr_encadj(t_lhpattr *x, void *attr, long ac, t_atom *av)
{
if (ac && av) {
float enc = atom_getfloat(av);
float mod = x->modrtn;
float min = object_attr_getfloat(x, gensym("min"));
float max = object_attr_getfloat(x, gensym("max"));
float f = object_attr_getfloat(x, gensym("fval"));
if (((f != max)&&(f != min))||((f == min)&&(enc > 0))||((f == max)&&(enc < 0))) { f += enc;
object_attr_setfloat(x, gensym("fval"), f);
}
if (((f != max)&&(f != min))||((f == min)&&(mod > 0))||((f == min)&&(mod < 0))) { f += mod;
if (f > max) {
f = max;
}
else if (f < min) {
f = min;
}
object_attr_setfloat(x, gensym("ffinal"), f);
x->ffinal = f;
lhpattr_pattrmode(x, 0);
lhpattr_output(x);
}
}
return MAX_ERR_NONE;
}

t_max_err lhpattr_modadj(t_lhpattr *x, void *attr, long ac, t_atom *av)
{
if (ac && av) {
float mod = atom_getfloat(av);
float min = object_attr_getfloat(x, gensym("min"));
float max = object_attr_getfloat(x, gensym("max"));
float f = object_attr_getfloat(x, gensym("fval"));
x->modrtn = mod;
if (((f != max)&&(f != min))||((f == min)&&(mod > 0))||((f == max)&&(mod < 0))) { f += mod;
if (f > max) {
f = max;
}
else if (f < min) {
f = min;
}
object_attr_setfloat(x, gensym("ffinal"), f);
x->ffinal = f;
lhpattr_pattrmode(x, 0);
lhpattr_output(x);
}
}
return MAX_ERR_NONE;
}

void lhpattr_pattrmode(t_lhpattr *x, int mode)
{
t_box *b;

if (mode != x->mode) {
x->mode = mode;
}

// now, notify pattr that something has changed
// get the box pointer from the obex
object_obex_lookup(x, gensym("#B"), (t_object **)&b);
// we call this on the box, not on the object
object_notify(b, _sym_modified, 0L);

// trigger output from the left outlet, since we’ve changed the info of note
// lhpattr_output(x);
}

void lhpattr_bang(t_lhpattr *x)
{
lhpattr_output(x);
}
void lhpattr_output(t_lhpattr *x)
{
outlet_float(x->out, x->ffinal);
}

void lhpattr_anything(t_lhpattr *x, t_symbol *s, long ac, t_atom *av)
{
if (ac && av) {
if (s == _sym_list) {
object_attr_setvalueof(x, gensym("array"), ac, av);
x->atomarraycount = ac;
}
else {
t_atom *a;
if (a = (t_atom *)getbytes(sizeof(t_atom) * (ac + 1))) {
atom_setsym(a, s);
sysmem_copyptr(av, a + 1, sizeof(t_atom) * ac);
object_attr_setvalueof(x, gensym("array"), ac + 1, a);
freebytes(a, sizeof(t_atom) * (ac + 1));
x->atomarraycount = ac + 1;
}
else {
error("lhpattr: could not allocate memory for atom array");
return;
}
}
lhpattr_pattrmode(x, 7);
}
}

t_max_err lhpattr_getvalueof(t_lhpattr *x, long *ac, t_atom **av)
{
if (ac && av) {
if (*ac && *av) {
// memory passed in; use it. but responsibly
if (*ac > x->atomarraycount)
*ac = x->atomarraycount;
}
else {
switch (x->mode) {
case 7: *ac = x->atomarraycount; break;
default: *ac = 1; break;
}
if (!(*av = (t_atom *)getbytes(sizeof(t_atom) * (*ac)))) {
*ac = 0;
return MAX_ERR_OUT_OF_MEM;
}
}
switch (x->mode) {
case 0: atom_setfloat(*av, x->fval); break;
case 1: atom_setsym(*av, x->symval); break;
case 2: atom_setfloat(*av, x->minval); break;
case 3: atom_setfloat(*av, x->maxval); break;
case 4: atom_setfloat(*av, x->encadj); break;
case 5: atom_setfloat(*av, x->modadj); break;
case 6: atom_setfloat(*av, x->ffinal); break;
case 7: sysmem_copyptr(x->atomarray, *av, sizeof(t_atom) * (*ac)); break;
default: break;
}
}
return MAX_ERR_NONE;
}

t_max_err lhpattr_setvalueof(t_lhpattr *x, long ac, t_atom *av)
{
if (ac && av) {
if (ac == 1) {
switch(x->mode) {
case 0: x->fval = atom_getfloat(av); lhpattr_fval(x, NULL, ac, av); break;
case 1: x->symval = atom_getsym(av); break;
case 2: x->minval = atom_getfloat(av); break;
case 3: x->maxval = atom_getfloat(av); break;
case 4: x->encadj = atom_getfloat(av); break;
case 5: x->modadj = atom_getfloat(av); break;
case 6: x->ffinal = atom_getfloat(av); break;
default: break;
}
}
else {
if (av->a_type == A_SYM)
lhpattr_anything(x, atom_getsym(av), ac – 1, av + 1);
else
lhpattr_anything(x, _sym_list, ac, av);
}
}
return MAX_ERR_NONE;
}

void lhpattr_assist(t_lhpattr *x, void *b, long m, long a, char *s)
{
if (m == 1) { //input
sprintf(s, "int, float, list, set, anything");
}
else { //output
if (a == 0)
sprintf(s, "anything out");
else
sprintf(s, "dumpout");
}
}

void lhpattr_free(t_lhpattr *x, t_symbol *s)
{
}
void *lhpattr_new(t_symbol *s, long ac, t_atom *av)
{
t_lhpattr *x;
// we use object_alloc here, rather than newobject
if (x = (t_lhpattr *)object_alloc(lhpattr_class)) {
// add a dumpout outlet
object_obex_store(x, _sym_dumpout, outlet_new(x, NULL));
// add a left outlet
x->out = floatout(x);
// set defaults before attribute args are processed!
x->fval = 0;
x->fprv = 0;
x->ffinal = 0;
x->minval = 0;
x->maxval = 0;
x->encadj = 0;
x->modadj = 0;
x->symval = symbol_unique();
x->atomarraycount = 0;
x->mode = 0;
object_register(gensym("_leightest"), x->symval, x);
object_attach(gensym("_regob_test"), x->symval, x);
attr_args_process(x, ac, av);

}
return (x);
}


January 24, 2008 | 5:11 pm

Doh – copy n paste error – the line

> object_attach(gensym("_regob_test"), x->symval, x);

should have been
> object_attach(gensym("_leightest"), x->symval, x);


January 24, 2008 | 9:21 pm

Don’t you just set the object’s boxname (scriptname)?

void patcher_setboxname(t_patcher *p, t_box *b, t_symbol *s);


January 26, 2008 | 6:35 am

Hi John,

Thanks for your quick reply. I found it a little perplexing at first, being a dev new bee, but the ‘setboxname’ led me via a couple of searches to a post from Mattijs, which led me to this solution.
I wouldn’t pretend to begin to fully understand the whole workings of it, but the object naming now works great when creating an instance including the @name attribute, and also with a symbol_unique in the absence of a typed attribute. I’d be intrigued to know if my method is sensible/over coded/downright badly dangerous!
Once again many thanks!!
Regards,
Leigh

ps – I didn’t post the complete C file just the changed ‘struct’ and ‘*lhpattr_new’.

typedef struct lhpattr
{
t_object ob;
void *obex;
t_patcher *p;
t_box *b;
float fval;
float fprv;
float ffinal;
t_symbol *symval;
t_atom atomarray[32];
long atomarraycount;
char mode;
void *out;
float minval;
float maxval;
float encadj;
float modadj;
float modrtn;
} t_lhpattr;

void *lhpattr_new(t_symbol *s, long ac, t_atom *av)
{
t_lhpattr *x;
t_symbol *myname;
// we use object_alloc here, rather than newobject
if (x = (t_lhpattr *)object_alloc(lhpattr_class)) {
// add a dumpout outlet
object_obex_store(x, _sym_dumpout, outlet_new(x, NULL));
// add a left outlet
x->out = floatout(x);
// set defaults before attribute args are processed!
x->fval = 0;
x->fprv = 0;
x->ffinal = 0;
x->minval = 0;
x->maxval = 0;
x->encadj = 0;
x->modadj = 0;
x->symval = symbol_unique();
x->atomarraycount = 0;
x->mode = 0;
attr_args_process(x, ac, av);
myname = x->symval;
x->p = (t_patcher *)gensym("#P")->s_thing;
x->b = (t_box *)gensym("#B")->s_thing;
patcher_setboxname(x->p, x->b, myname);

}
return (x);
}

.Quote: johnpitcairn wrote on Thu, 24 January 2008 21:21
—————————————————-
> Don’t you just set the object’s boxname (scriptname)?
>
> void patcher_setboxname(t_patcher *p, t_box *b, t_symbol *s);
>
>
—————————————————-


January 26, 2008 | 8:46 pm

Hi again..
It seems my elation was short lived as;
The @name argument certainly does set the scripting name, when viewed in the inspector, unfortunately it isn’t seen by pattrstorage at all.
On saving a patch with an already created object with a @name argument, then reloading, the scripting name of the object is given a [1] extension, which IS seen by pattrstorage. I’m guessing there is some kind of double setting going on there, but my code experience can’t work out just how.
Can anyone see where I am now going wrong?
All advice much appreciated.
regards
Leigh


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