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 – and 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.

Leave a Reply

Your email address will not be published. Required fields are marked *