Max 5 API Reference
00001 /* 00002 myobex 00003 Copyright 2004 - Cycling '74 00004 jeremy bernstein - jeremy@bootsquad.com 00005 */ 00006 00007 #include "ext.h" 00008 #include "ext_common.h" 00009 #include "ext_obex.h" 00010 00011 typedef struct _myobex 00012 { 00013 t_object ob; 00014 void *obex; 00015 uchar charval; 00016 long longval; 00017 double floatval; 00018 t_symbol *symval; 00019 t_atom atomarray[32]; 00020 long atomarraycount; 00021 char mode; 00022 void *out; 00023 } t_myobex; 00024 00025 void *myobex_new(t_symbol *s, long argc, t_atom *argv); 00026 void myobex_free(t_myobex *x); 00027 void myobex_assist(t_myobex *x, void *b, long m, long a, char *s); 00028 void myobex_anything(t_myobex *x, t_symbol *s, long argc, t_atom *argv); 00029 void myobex_bang(t_myobex *x); 00030 void myobex_output(t_myobex *x); 00031 void myobex_float(t_myobex *x, double f); 00032 void myobex_int(t_myobex *x, long c); 00033 00034 // attribute method prototypes, for attributes which override their defaults 00035 t_max_err myobex_floatval_rounded(t_myobex *x, void *attr, long *ac, t_atom **av); 00036 t_max_err myobex_pattrmode_set(t_myobex *x, void *attr, long ac, t_atom *av); 00037 00038 // pattr support function prototypes 00039 t_max_err myobex_getvalueof(t_myobex *x, long *ac, t_atom **av); 00040 t_max_err myobex_setvalueof(t_myobex *x, long ac, t_atom *av); 00041 00042 void *myobex_class; 00043 00044 void main(void) 00045 { 00046 t_class *c; 00047 void *attr; 00048 long attrflags = 0; 00049 00050 c = class_new("myobex", (method)myobex_new, (method)myobex_free, (short)sizeof(t_myobex), 00051 0L, A_GIMME, 0); 00052 00053 // initialize the common symbols, since we want to use them 00054 common_symbols_init(); 00055 00056 // register the byte offset of obex with the class 00057 class_obexoffset_set(c, calcoffset(t_myobex, obex)); 00058 00059 // add some attributes 00060 attr = attr_offset_new("charval", _sym_char, attrflags, 00061 (method)0L, (method)0L, calcoffset(t_myobex, charval)); 00062 class_addattr(c, attr); 00063 00064 attr = attr_offset_new("longval", _sym_long, attrflags, 00065 (method)0L, (method)0L, calcoffset(t_myobex, longval)); 00066 class_addattr(c, attr); 00067 00068 attr = attr_offset_new("floatval", _sym_float64, attrflags, 00069 (method)0L, (method)0L, calcoffset(t_myobex, floatval)); 00070 class_addattr(c, attr); 00071 00072 // this attribute doesn't actually reference any data directly, but 00073 // operates upon another attribute's data. we use a custom 'get' method 00074 // and disable the set method using attribute flags. 00075 attrflags = ATTR_SET_OPAQUE_USER | ATTR_SET_OPAQUE; 00076 attr = attr_offset_new("floatval_rounded", _sym_float64, attrflags, 00077 (method)myobex_floatval_rounded, (method)0L, 0L); 00078 class_addattr(c, attr); 00079 00080 // reset attr flags to 0 00081 attrflags = 0; 00082 attr = attr_offset_new("symval", _sym_symbol, attrflags, 00083 (method)0L, (method)0L, calcoffset(t_myobex, symval)); 00084 class_addattr(c, attr); 00085 00086 attr = attr_offset_array_new("array", _sym_atom, 32, attrflags, 00087 (method)0L, (method)0L, 00088 calcoffset(t_myobex, atomarraycount), calcoffset(t_myobex, atomarray)); 00089 class_addattr(c, attr); 00090 00091 // this attribute will determine which of the previous attributes will 00092 // be visible to pattr, for the getvalueof and setvalueof methods. since 00093 // setting this value should cause a few things to happen, we're using a 00094 // custom set method. 00095 attr = attr_offset_new("pattrmode", _sym_char, attrflags, 00096 (method)0L, (method)myobex_pattrmode_set, calcoffset(t_myobex, mode)); 00097 class_addattr(c, attr); 00098 00099 // add methods to the class 00100 class_addmethod(c, (method)myobex_bang, "bang", 0); 00101 class_addmethod(c, (method)myobex_float, "float", A_FLOAT, 0); 00102 class_addmethod(c, (method)myobex_int, "int", A_LONG, 0); 00103 class_addmethod(c, (method)myobex_anything, "list", A_GIMME,0); 00104 class_addmethod(c, (method)myobex_anything, "anything", A_GIMME,0); 00105 class_addmethod(c, (method)myobex_assist, "assist", A_CANT,0); 00106 00107 // these methods support the pattr set of objects 00108 class_addmethod(c, (method)myobex_getvalueof, "getvalueof", A_CANT,0); 00109 class_addmethod(c, (method)myobex_setvalueof, "setvalueof", A_CANT,0); 00110 00111 // add methods for dumpout and quickref 00112 class_addmethod(c, (method)object_obex_dumpout, "dumpout", A_CANT, 0); 00113 class_addmethod(c, (method)object_obex_quickref, "quickref", A_CANT, 0); 00114 00115 // we want this class to instantiate inside of the Max UI; ergo CLASS_BOX 00116 class_register(CLASS_BOX, c); 00117 myobex_class = c; 00118 } 00119 00120 // custom attribute get methods all need to be implemented using this basic form 00121 t_max_err myobex_floatval_rounded(t_myobex *x, void *attr, long *ac, t_atom **av) 00122 { 00123 float floatval; 00124 00125 if (ac && av) { 00126 if (*ac && *av) { 00127 // memory passed in; use it 00128 } 00129 else { 00130 if (!(*av = (t_atom *)getbytes(sizeof(t_atom)))) { 00131 *ac = 0; 00132 return MAX_ERR_OUT_OF_MEM; 00133 } 00134 *ac = 1; 00135 } 00136 // query the attribute's value. we could do this directly, too (x->floatval) 00137 // but then that wouldn't be so pedagogically useful, would it? 00138 floatval = object_attr_getfloat(x, gensym("floatval")); 00139 atom_setfloat(*av, (float)((long)(floatval + 0.5))); 00140 } 00141 return MAX_ERR_NONE; 00142 } 00143 00144 // custom attribute set methods all need to be implemented using this basic form 00145 t_max_err myobex_pattrmode_set(t_myobex *x, void *attr, long ac, t_atom *av) 00146 { 00147 t_box *b; 00148 long mode; 00149 00150 /* note that we're using this attribute to perform the notification call, too. 00151 as such, we call it whenever data changes, not just when we're changing the mode */ 00152 if (ac && av) { 00153 mode = atom_getlong(av); 00154 00155 if (mode != x->mode) { 00156 x->mode = mode; 00157 } 00158 00159 // now, notify pattr that something has changed 00160 // get the box pointer from the obex 00161 object_obex_lookup(x, gensym("#B"), (t_object **)&b); 00162 // we call this on the box, not on the object 00163 object_notify(b, _sym_modified, 0L); 00164 00165 // by the way, attributes notify pattr themselves, and don't require this 00166 00167 // trigger output from the left outlet, since we've changed the info of note 00168 myobex_output(x); 00169 } 00170 return MAX_ERR_NONE; 00171 } 00172 00173 void myobex_bang(t_myobex *x) 00174 { 00175 myobex_output(x); 00176 } 00177 00178 void myobex_output(t_myobex *x) 00179 { 00180 switch(x->mode) { 00181 case 0: outlet_int(x->out, x->charval); break; 00182 case 1: outlet_int(x->out, x->longval); break; 00183 case 2: outlet_float(x->out, x->floatval); break; 00184 case 3: outlet_anything(x->out, x->symval, 0, 0L); break; 00185 case 4: outlet_float(x->out, object_attr_getfloat(x, gensym("floatval_rounded"))); break; 00186 case 5: 00187 if (x->atomarray[0].a_type != A_SYM) 00188 outlet_list(x->out, NULL, x->atomarraycount, x->atomarray); 00189 else 00190 outlet_anything(x->out, atom_getsym(x->atomarray), x->atomarraycount - 1, x->atomarray + 1); 00191 break; 00192 default: break; 00193 } 00194 } 00195 00196 00197 void myobex_float(t_myobex *x, double f) 00198 { 00199 object_attr_setfloat(x, gensym("floatval"), f); 00200 object_attr_setlong(x, gensym("pattrmode"), 2); 00201 } 00202 00203 void myobex_int(t_myobex *x, long c) 00204 { 00205 object_attr_setfloat(x, gensym("longval"), c); 00206 object_attr_setlong(x, gensym("pattrmode"), 1); 00207 } 00208 00209 void myobex_anything(t_myobex *x, t_symbol *s, long ac, t_atom *av) 00210 { 00211 if (ac && av) { 00212 if (s == _sym_list) { 00213 object_attr_setvalueof(x, gensym("array"), ac, av); 00214 x->atomarraycount = ac; 00215 } 00216 else { 00217 t_atom *a; 00218 00219 if (a = (t_atom *)getbytes(sizeof(t_atom) * (ac + 1))) { 00220 atom_setsym(a, s); 00221 sysmem_copyptr(av, a + 1, sizeof(t_atom) * ac); 00222 object_attr_setvalueof(x, gensym("array"), ac + 1, a); 00223 freebytes(a, sizeof(t_atom) * (ac + 1)); 00224 x->atomarraycount = ac + 1; 00225 } 00226 else { 00227 error("myobex: could not allocate memory for atom array"); 00228 return; 00229 } 00230 } 00231 object_attr_setlong(x, gensym("pattrmode"), 5); 00232 } 00233 else { 00234 x->symval = s; 00235 object_attr_setlong(x, gensym("pattrmode"), 3); 00236 } 00237 } 00238 00239 t_max_err myobex_getvalueof(t_myobex *x, long *ac, t_atom **av) 00240 { 00241 if (ac && av) { 00242 if (*ac && *av) { 00243 // memory passed in; use it. but responsibly 00244 if (*ac > x->atomarraycount) 00245 *ac = x->atomarraycount; 00246 } 00247 else { 00248 switch (x->mode) { 00249 case 5: *ac = x->atomarraycount; break; 00250 default: *ac = 1; break; 00251 } 00252 if (!(*av = (t_atom *)getbytes(sizeof(t_atom) * (*ac)))) { 00253 *ac = 0; 00254 return MAX_ERR_OUT_OF_MEM; 00255 } 00256 } 00257 switch (x->mode) { 00258 case 0: atom_setlong(*av, x->charval); break; 00259 case 1: atom_setlong(*av, x->longval); break; 00260 case 2: atom_setfloat(*av, x->floatval); break; 00261 case 3: atom_setsym(*av, x->symval); break; 00262 case 4: atom_setfloat(*av, object_attr_getfloat(x, gensym("floatval_rounded"))); break; 00263 case 5: sysmem_copyptr(x->atomarray, *av, sizeof(t_atom) * (*ac)); break; 00264 default: break; 00265 } 00266 } 00267 return MAX_ERR_NONE; 00268 } 00269 00270 t_max_err myobex_setvalueof(t_myobex *x, long ac, t_atom *av) 00271 { 00272 if (ac && av) { 00273 if (ac == 1) { 00274 switch(av->a_type) { 00275 case A_LONG: myobex_int(x, atom_getlong(av)); break; 00276 case A_FLOAT: myobex_float(x, atom_getfloat(av)); break; 00277 case A_SYM: myobex_anything(x, atom_getsym(av), 0, NULL); break; 00278 default: break; 00279 } 00280 } 00281 else { 00282 if (av->a_type == A_SYM) 00283 myobex_anything(x, atom_getsym(av), ac - 1, av + 1); 00284 else 00285 myobex_anything(x, _sym_list, ac, av); 00286 } 00287 } 00288 return MAX_ERR_NONE; 00289 } 00290 00291 void myobex_assist(t_myobex *x, void *b, long m, long a, char *s) 00292 { 00293 if (m == 1) { //input 00294 sprintf(s, "int, float, list, set, anything"); 00295 } 00296 else { //output 00297 if (a == 0) 00298 sprintf(s, "anything out"); 00299 else 00300 sprintf(s, "dumpout"); 00301 } 00302 } 00303 00304 void myobex_free(t_myobex *x) 00305 { 00306 ; 00307 } 00308 00309 void *myobex_new(t_symbol *s, long ac, t_atom *av) 00310 { 00311 t_myobex *x; 00312 t_atom a; 00313 00314 // we use object_alloc here, rather than newobject 00315 if (x = (t_myobex *)object_alloc(myobex_class)) { 00316 // add a dumpout outlet 00317 object_obex_store(x, _sym_dumpout, outlet_new(x, NULL)); 00318 00319 // add a left outlet 00320 x->out = outlet_new(x, 0L); 00321 00322 // set defaults before attribute args are processed! 00323 x->charval = 0; 00324 x->longval = 0; 00325 x->floatval = 0; 00326 x->symval = _sym_nothing; 00327 x->atomarraycount = 0; 00328 00329 x->mode = 0; 00330 00331 attr_args_process(x, ac, av); 00332 } 00333 return (x); 00334 }
Copyright © 2008, Cycling '74