A Ruby script for generating Jitter attributes

Writing your own Max or Jitter externals in C or C++ isn’t terribly hard, once you’ve wrapped your head around the API’s C approach to object oriented programming. However, it does involve a fair bit of boilerplate. This is especially true for adding attributes to an object ? an triply so if this attribute has custom getter and setter methods.

The cv.jit collection now contains more than a few externals and I find myself spending more time trying to find ways to automate some of the repetitive tasks that are required for keeping it up to date. One of the tools I just made is a nifty Ruby script for automatically generating all the necessary attribute-related boilerplate. Simply invoke it at the command line with only a few arguments and it generates a .c file containing the necessary code. It parses the arguments “-c”, “-l”, “-f”, “-d”, “-s” and “-a” as “char”, “long”, “float32”, “float64”, “symbol and “atom” types. Numbers (if there are any) as the number of elements in a list. The arguments “-get” and “-set” specify that the attribute has a custom getter and setter, while “-clip” will add a filter to clip argument values. Any other argument is going to be parsed as the name of the attribute, unless it begins with a “-“, in which case, it’s interpreted as your external’s name (periods are automatically converted to underscores.)

For example:

ruby ./jitargs.rb -f -cv.jit.bigbrother foo

This generates a file “jitter_args.c” in the current directory that looks like this:

//setter/getter declarations

//attribute variables
float foo;

//setters/getters

//attribute registration
attr = (t_jit_object *)jit_object_new(_jit_sym_jit_attr_offset,"foo",_jit_sym_float32,
attrflags,(method)0L,(method)0L,calcoffset(t_cv_jit_bigbrother,foo));
jit_attr_addfilterset_clip(attr,0,1,TRUE,TRUE);
jit_class_addattr(_cv_jit_bigbrother_class,attr);

//attribute initialization
x->foo = 0;

If you wish to add more attributes, just run the script again with different arguments, new code will be inserted in the appropriate place. For example, by running the following:


ruby ./jitargs.rb -a -get -set 2 -cv.jit.bigbrother bar

The file above is modified to:

//setter/getter declarations
t_jit_err cv_jit_bigbrother_set_bar(t_cv_jit_bigbrother *x, void *attr, long ac, t_atom *av);
t_jit_err cv_jit_bigbrother_get_bar(t_cv_jit_bigbrother *x, void *attr, long *ac, t_atom **av);

//attribute variables
long barcount;
t_atom bar[2];
float foo;

//setters/getters
t_jit_err cv_jit_bigbrother_set_bar(t_cv_jit_bigbrother *x, void *attr, long ac, t_atom *av){
if(ac < 2){ //Not enough parameters? return JIT_ERR_NONE; } return JIT_ERR_NONE; } t_jit_err cv_jit_bigbrother_get_bar(t_cv_jit_bigbrother *x, void *attr, long *ac, t_atom **av){ int i; if ((*ac)&&(*av)) { //memory passed in, use it } else { //otherwise allocate memory *ac = 2; if (!(*av = jit_getbytes(sizeof(t_atom)*(*ac)))) { *ac = 0; return JIT_ERR_OUT_OF_MEM; } } for(i=0;i<2;i++)av[i] = x->bar[i];

return JIT_ERR_NONE;
}

//attribute registration
attr = (t_jit_object *)jit_object_new(_jit_sym_jit_attr_offset_array, "bar", _jit_sym_atom, 2,
attrflags, (method)cv_jit_bigbrother_get_bar,(method)cv_jit_bigbrother_set_bar,
calcoffset(t_cv_jit_bigbrother, barcount),calcoffset(t_cv_jit_bigbrother,bar));
jit_class_addattr(_cv_jit_bigbrother_class,attr);

attr = (t_jit_object *)jit_object_new(_jit_sym_jit_attr_offset,"foo",_jit_sym_float32,
attrflags,(method)0L,(method)0L,calcoffset(t_cv_jit_bigbrother,foo));
jit_attr_addfilterset_clip(attr,0,1,TRUE,TRUE);
jit_class_addattr(_cv_jit_bigbrother_class,attr);

//attribute initialization
jit_atom_setlong(&x->bar[0],0);
jit_atom_setlong(&x->bar[1],0);
x->foo = 0;

All you need to do now is copy and paste the code at the appropriate places. Of course, if I was really crazy, I would write a script that parses and modifies the actual external source but I’ll leave that as an exercise for the reader.

Download the script.