Code Search for Developers
 
 
  

jcom.parameter.cpp from Jamoma at Krugle


Show jcom.parameter.cpp syntax highlighted

/* 
 * jcom.paramater
 * External for Jamoma: parameter definition using pattr
 * By Tim Place, Copyright © 2006
 * 
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html 
 */

#include "jcom.parameter.h"		// everything we need is in here
#include "ext_pattr_bundle.h"	// pattr definitions

// Globals
t_class		*param_class;		// Required: Global pointer for our class
bool		g_pattr_valid;		// Did pattr init successfully?
	
int param_list_compare(t_atom *x, long lengthx, t_atom *y, long lengthy);

/************************************************************************************/
// Class Definition

int main(void)				// main recieves a copy of the Max function macros table
{
	long		attrflags = 0;
	t_class		*c;
	t_object	*attr = NULL;
	long		offset;
	
	// Initialize Globals
	g_pattr_valid = false;
	common_symbols_init();
#ifndef JMOD_MESSAGE
	short		err = 0;
	err = ext_pattr_setup();
	if(err){
		post("Jamoma: pattr integration is not available - could not init pattr-bundle");
		g_pattr_valid = false;
	}
	else
		g_pattr_valid = true;
#endif

	// Define our class
	c = class_new(OBJECT_CLASS_NAME,(method)param_new, (method)param_free, 
		(short)sizeof(t_param), (method)0L, A_GIMME, 0);
	offset = calcoffset(t_param, common);
	class_obexoffset_set(c, offset + calcoffset(t_jcom_core_subscriber_common, obex));

	if(g_pattr_valid == true)
		pattr_obex_init(c);			// set up the pattr obex
		
	// Make methods accessible for our class:
	// Note that we can't make the bang method directly accessible here (must go through another function)
	//	because the function pointer is in out struct, which hasn't been defined yet
	class_addmethod(c, (method)param_dispatched,			"dispatched",	A_GIMME, 0L);
	class_addmethod(c, (method)param_int,					"int",			A_DEFLONG,	0L);
	class_addmethod(c, (method)param_float,					"float",		A_DEFFLOAT,	0L);
 	class_addmethod(c, (method)param_list,					"list",			A_GIMME, 0L);
 	class_addmethod(c, (method)param_symbol,				"anything",		A_GIMME, 0L);
	class_addmethod(c, (method)param_ui_refresh,			"ui/refresh",	0L);
	class_addmethod(c, (method)param_inc,					"inc",			A_GIMME, 0L);
	class_addmethod(c, (method)param_dec,					"dec",			A_GIMME, 0L);
	class_addmethod(c, (method)param_inc,					"+",			A_GIMME, 0L);
	class_addmethod(c, (method)param_dec,					"-",			A_GIMME, 0L);
	class_addmethod(c, (method)param_dump,					"dump",			0L);
	class_addmethod(c, (method)param_bang,					"bang",			0L);
	class_addmethod(c, (method)param_assist,				"assist",		A_CANT, 0L); 
#ifndef JMOD_MESSAGE
	if(g_pattr_valid == true){
		// required to manually add because of our pattr-wrapping for parameters
		class_addmethod(c, (method)param_getvalueof,			"getvalueof",	A_CANT, 0);
		class_addmethod(c, (method)param_setvalueof,			"setvalueof",	A_CANT, 0);
		class_addmethod(c, (method)pattr_obex_notify,			"notify",		A_CANT, 0); 	
	}
#endif

	if(g_pattr_valid == true)
		jcom_core_subscriber_classinit_extended(c, attr, offset, false);	// don't define name attr
	else
		jcom_core_subscriber_classinit_extended(c, attr, offset, true);		// define a name attr
		
	// ATTRIBUTE: ramp
	attr = attr_offset_new("ramp", _sym_symbol, attrflags,
		(method)0, (method)param_setramp, calcoffset(t_param, attr_ramp));
	class_addattr(c, attr);

	// ATTRIBUTE: type - options are msg_generic, msg_int, msg_float, msg_symbol, msg_toggle, msg_list, msg_none
	attr = attr_offset_new("type", _sym_symbol, attrflags,
		(method)0, (method)param_settype, calcoffset(t_jcom_core_subscriber_extended, attr_type));
	class_addattr(c, attr);
	
	// ATTRIBUTE: ui/freeze - toggles a "frozen" ui outlet so that you can save cpu
	attr = attr_offset_new("ui/freeze", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_param, attr_ui_freeze));
	class_addattr(c, attr);
	
	// ATTRIBUTE: slavemode - indicates that the instance is slave to another parameter/message
	attr = attr_offset_new("slave", _sym_long, attrflags,
	 	(method)0, (method)0, calcoffset(t_param, attr_slavemode));
	class_addattr(c, attr);

	// ATTRIBUTE: stepsize - how much increment or decrement by
	attr = attr_offset_new("stepsize", _sym_float32, attrflags,
		(method)0, (method)0, calcoffset(t_param, attr_stepsize));
	class_addattr(c, attr);

	// ATTRIBUTE: priority - used to determine order of parameter recall in a preset
	attr = attr_offset_new("priority", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_param, attr_priority));
	class_addattr(c, attr);

	// ATTRIBUTE: value
	attr = attr_offset_array_new("value", _sym_atom, LISTSIZE, attrflags,
		   (method)0, (method)0, calcoffset(t_param, list_size), calcoffset(t_param, attr_value));
	class_addattr(c, attr);

	// Finalize our class
	class_register(CLASS_BOX, c);
	param_class = c;
	
	jcom_core_init();
	return 0;
}


/************************************************************************************/
// Object Life
#pragma mark -
#pragma mark life cycle

void *param_new(t_symbol *s, long argc, t_atom *argv)
{
	short		i;
	long		attrstart = attr_args_offset(argc, argv);
	t_param		*x = (t_param *)object_alloc(param_class);
	t_symbol	*name = _sym_nothing;

	if(attrstart && argv)
		atom_arg_getsym(&name, 0, attrstart, argv);
	else
		name = symbol_unique();

	if(x){
		for(i=num_outlets; i > 0; i--)
			x->outlets[i-1] = outlet_new(x, 0);
		object_obex_store((void *)x, _sym_dumpout, (t_object *)x->outlets[k_outlet_dumpout]);
		
		x->ui_qelem = qelem_new(x, (method)param_ui_queuefn);
		x->ramp_qelem = qelem_new(x, (method)param_ramp_setup);

		// set defaults...
		x->attr_ramp = NULL;
		x->ramper = NULL;

		// defaulted to one long above, set list to be of size 1
		x->list_size = 1;
		for(i = 0; i < LISTSIZE; i++)	
			atom_setlong(&x->atom_list[i], 0); // atom_setlong(&x->attr_value, 0);
		x->name = name;
		atom_setsym(&x->name_atom, name);
		x->attr_ui_freeze = 0;
		x->attr_slavemode = 0;
		x->attr_stepsize = 1.0;
		x->attr_priority = 0;						// default is no priority
		x->param_output = &param_output_generic;		// set function pointer to default
		
#ifdef JMOD_MESSAGE
		jcom_core_subscriber_new_extended(&x->common, name, ps_subscribe_message);
#else
		jcom_core_subscriber_new_extended(&x->common, name, ps_subscribe_parameter);
#endif
		attr_args_process(x, argc, argv);			// handle attribute args
		if(g_pattr_valid == true)
			pattr_obex_setup(x, name);				// set up out internal pattr instance

		defer_low(x, (method)jcom_core_subscriber_subscribe, 0, 0, 0);
		
		// If no type was specified by the user we call the accessor here
		// this is important because memory is configured - not just setting a default!
		if(x->common.attr_type == NULL){
			t_atom a;
			atom_setsym(&a, ps_msg_generic);
			object_attr_setvalueof(x, ps_type, 1, &a);
		}
		if(x->attr_ramp == NULL){
			t_atom a;
			atom_setsym(&a, ps_none);
			object_attr_setvalueof(x, ps_ramp, 1, &a);
		}
	}
	return (x);										// return the pointer to our new instantiation
}


void param_free(t_param *x)
{	
	jcom_core_subscriber_common_free((t_jcom_core_subscriber_common *)x);
	qelem_free(x->ui_qelem);
	qelem_free(x->ramp_qelem);
	if(x->ramper)
		delete x->ramper;
}


#ifndef JMOD_MESSAGE
/************************************************************************************/
// Communication with PSTO (pattrstorage)
#pragma mark -
#pragma mark pattr support

// FROM psto
t_max_err param_setvalueof(t_param *x, long argc, t_atom *argv)
{
	if(argc && argv) {
		sysmem_copyptr(argv, &x->atom_list[0], sizeof(t_atom) * argc);
		x->list_size = argc;
		x->param_output(x);
	}	
	return MAX_ERR_NONE;
}

// TO psto
t_max_err param_getvalueof(t_param *x, long *argc, t_atom **argv)
{
	if(argc && argv){
		if(*argc && *argv) {
			// use passed in memory
		} 
		else { 
			if(x->list_size > 1)
				*argv = (t_atom *)getbytes(sizeof(t_atom) * x->list_size);
			else
				*argv = (t_atom *)getbytes(sizeof(t_atom));
		}
		
		*argc = x->list_size > 1 ? x->list_size : 1;
		sysmem_copyptr(&x->atom_list[0], *argv, sizeof(t_atom) * (*argc));
	}
	return MAX_ERR_NONE;
}

#endif


/************************************************************************************/
// Methods bound to input/inlets
#pragma mark -
#pragma mark attribute accessors

// ATTRIBUTE: TYPE
// This is crucial because it sets function pointers for the optimized clipping, bang, and other functions
t_max_err param_settype(t_param *x, void *attr, long argc, t_atom *argv)
{
	t_symbol *arg = atom_getsym(argv);
	x->common.attr_type = arg;

	if(arg == ps_msg_int){
		x->param_output = &param_output_int;
	}
	else if(arg == ps_msg_float){
		x->param_output = &param_output_float;
	}
	else if(arg == ps_msg_symbol){
		x->param_output = &param_output_symbol;
	}
	else if(arg == ps_msg_toggle){
		x->param_output = &param_output_int;
	}
	else if(arg == ps_msg_generic){
		x->param_output = &param_output_generic;
	} 
	else if(arg == ps_msg_list){
		x->param_output = &param_output_list;
	}
#ifdef JMOD_MESSAGE
	else if(arg == ps_msg_none){
		x->param_output = &param_output_none;
	}
#endif // JMOD_MESSAGE
	else{
#ifdef JMOD_MESSAGE
		error("Jamoma - invalid type specified for %s jcom.message in the %s module.", x->name->s_name, x->common.module_name->s_name);
#else
		error("Jamoma - invalid type specified for %s jcom.parameter in the %s module.", x->name->s_name, x->common.module_name->s_name);
#endif
		x->common.attr_type = ps_msg_generic;
		x->param_output = &param_output_generic;
	}

	qelem_set(x->ramp_qelem);	// set up the rampunit with callbacks appropriate to this data type

	return MAX_ERR_NONE;
	#pragma unused(attr)
}


// ATTRIBUTE: RAMP
// This is crucial because it sets function pointers
t_max_err param_setramp(t_param *x, void *attr, long argc, t_atom *argv)
{
	t_symbol *arg = atom_getsym(argv);
	x->attr_ramp = arg;
	
	qelem_set(x->ramp_qelem);	// place a call to param_ramp_setup() at the end of the low-priority queue

	return MAX_ERR_NONE;
	#pragma unused(attr)
}


/************************************************************************************/
// Methods bound to input/inlets
#pragma mark -
#pragma mark methods

// Method for Assistance Messages
void param_assist(t_param *x, void *b, long msg, long arg, char *dst)
{
	if(msg==1) 						// Inlet
		strcpy(dst, "input");
	else{							// Outlets
		switch(arg){
			case k_outlet_set:
					strcpy(dst, "set: connect to ui object");
					break;
			case k_outlet_direct:
					strcpy(dst, "direct: values");
					break;
			case k_outlet_dumpout:
					strcpy(dst, "dumpout");
					break;
		}
 	}		
}


// DUMP: use for debugging - dump state to the Max window
void param_dump(t_param *x)
{
	char	s[256];
	t_atom	a[4];
	
	if(x->common.hub != NULL){
		sprintf(s, "dump/%s:clipmode", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setsym(&a[1], x->common.attr_clipmode);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:description", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setsym(&a[1], x->common.attr_description);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:priority", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setlong(&a[1], x->attr_priority);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:ramp", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setsym(&a[1], x->attr_ramp);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:range", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setfloat(&a[1], x->common.attr_range[0]);
		atom_setfloat(&a[2], x->common.attr_range[1]);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:repetitions", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setlong(&a[1], x->common.attr_repetitions);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:type", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setsym(&a[1], x->common.attr_type);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:ui/freeze", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		atom_setlong(&a[1], x->attr_ui_freeze);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);

		sprintf(s, "dump/%s:value", x->common.attr_name->s_name);
		atom_setsym(&a[0], gensym(s));
		jcom_core_atom_copy(&a[1], &x->attr_value);
		object_method_typed(x->common.hub, ps_feedback, 2, a, NULL);
	}
}


// 'bang' method for user input
void param_bang(t_param *x)
{
#ifdef JMOD_MESSAGE
	t_atom	a;
	
	atom_setsym(&a, gensym(""));
	outlet_int(x->outlets[k_outlet_direct], x->attr_value.a_w.w_long);
	outlet_anything(x->outlets[k_outlet_set], _sym_set, 1, &a);

	// call on the hub to pass our data onward
	if(x->common.hub != NULL){
		jcom_core_atom_copy(&a, &x->name_atom);
		object_method_typed(x->common.hub, ps_feedback, 1, &a, NULL);
	}
#else
	x->param_output(x);
#endif
}


// Actual bang functions
void param_output_generic(void *z)
{
	t_param *x = (t_param *)z;
	
	if(x->list_size == 1){
		param_clip_generic(x);
		if(x->attr_value.a_type == A_LONG)
			outlet_int(x->outlets[k_outlet_direct], x->attr_value.a_w.w_long);
		else if(x->attr_value.a_type == A_FLOAT)
			outlet_float(x->outlets[k_outlet_direct], x->attr_value.a_w.w_float);
		else if(x->attr_value.a_type == A_SYM)
			outlet_anything(x->outlets[k_outlet_direct], x->attr_value.a_w.w_sym, 0, NULL);
	}
	else if(x->list_size > 1){
		param_clip_generic(x);
		outlet_anything(x->outlets[k_outlet_direct], _sym_list, x->list_size, x->atom_list);
	} 
	else{	// zero args
		param_output_none(x);
	}
	param_send_feedback(x);
}


void param_output_int(void *z)
{
	t_param *x = (t_param *)z;

	param_clip_int(x);
	outlet_int(x->outlets[k_outlet_direct], x->attr_value.a_w.w_long);
	param_send_feedback(x);
}


void param_output_float(void *z)
{
	t_param *x = (t_param *)z;

	param_clip_float(x);
	outlet_float(x->outlets[k_outlet_direct], x->attr_value.a_w.w_float);
	param_send_feedback(x);
}


void param_output_symbol(void *z)
{
	t_param *x = (t_param *)z;

	outlet_anything(x->outlets[k_outlet_direct], x->attr_value.a_w.w_sym, 0, NULL);
	param_send_feedback(x);
}


void param_output_list(void *z)
{
	t_param *x = (t_param *)z;
	
	param_clip_list(x);
	outlet_anything(x->outlets[k_outlet_direct], _sym_list, x->list_size, x->atom_list);
	param_send_feedback(x);
}


void param_output_none(void *z)
{
	t_param *x = (t_param *)z;
	t_atom output[1];
	t_atom *out = (t_atom *)(&output);

	// bang direct output
	outlet_bang(x->outlets[k_outlet_direct]);
	
	// call on the hub to pass our data onward
	// We can not use (method)param_send_feedback here as it assumes an additional argument
	if(x->common.hub != NULL){
		jcom_core_atom_copy(out, &x->name_atom);
		object_method_typed(x->common.hub, ps_feedback, 1, out, NULL);
	}
}


// INC & DEC
void param_inc(t_param *x, t_symbol *msg, short argc, t_atom *argv)
{
	float	stepmult = 1.0;
	long	ramptime = 0;		// ms
	t_atom	a[3];				// value, 'ramp', value
	short	a_len = 1;
	
	// Check for Arguments...
	if(argc){
		// Look for arg to specify the number of steps to move
		if(argv->a_type == A_FLOAT){
			stepmult = argv->a_w.w_float;
			argc--;
			argv++;
		}
		else if(argv->a_type == A_LONG){
			stepmult = argv->a_w.w_long;
			argc--;
			argv++;
		}
		
		// Look for args to specify a ramp time
		if(argc){
			if(argv->a_type == A_SYM){
				if(argv->a_w.w_sym == ps_ramp){
					argc--;
					argv++;
					if(argc){
						ramptime = atom_getlong(argv);
						if(ramptime){
							atom_setsym(a+1, ps_ramp);
							atom_setlong(a+2, ramptime);
							a_len = 3;
						}
					}
				}
			}
		}
	}

	if(x->attr_slavemode)
		outlet_anything(x->outlets[k_outlet_direct], ps_inc, 0, NULL);
	else{
		if(x->ramper)
			x->ramper->stop();
			
		if(x->common.attr_type == ps_msg_int)
			atom_setlong(a, x->attr_value.a_w.w_long + (x->attr_stepsize * stepmult));
		else if((x->common.attr_type == ps_msg_float) || (x->common.attr_type == ps_msg_generic))
			atom_setfloat(a, x->attr_value.a_w.w_float + (x->attr_stepsize * stepmult));
		else if(x->common.attr_type == ps_msg_toggle){
			if(x->attr_value.a_w.w_long == 1)
				x->attr_value.a_w.w_long = 0;
			else
				x->attr_value.a_w.w_long = 1;
			param_output_int(x);
			return;
		}
		else{
			error("%s parameter (in the %s module) is an inappropriate type for the 'inc' message.");
			return;
		}
	}
	param_dispatched(x, msg, a_len, a);
}


void param_dec(t_param *x, t_symbol *msg, short argc, t_atom *argv)
{
	float	stepmult = 1.0;
	long	ramptime = 0;		// ms
	t_atom	a[3];				// value, 'ramp', value
	short	a_len = 1;
	
	// Check for Arguments...
	if(argc){
		// Look for arg to specify the number of steps to move
		if(argv->a_type == A_FLOAT){
			stepmult = argv->a_w.w_float;
			argc--;
			argv++;
		}
		else if(argv->a_type == A_LONG){
			stepmult = argv->a_w.w_long;
			argc--;
			argv++;
		}
		
		// Look for args to specify a ramp time
		if(argc){
			if(argv->a_type == A_SYM){
				if(argv->a_w.w_sym == ps_ramp){
					argc--;
					argv++;
					if(argc){
						ramptime = atom_getlong(argv);
						if(ramptime){
							atom_setsym(a+1, ps_ramp);
							atom_setlong(a+2, ramptime);
							a_len = 3;
						}
					}
				}
			}
		}
	}

	if(x->attr_slavemode)
		outlet_anything(x->outlets[k_outlet_direct], ps_dec, 0, NULL);
	else{
		if(x->ramper)
			x->ramper->stop();
			
		if(x->common.attr_type == ps_msg_int)
			atom_setlong(a, x->attr_value.a_w.w_long - (x->attr_stepsize * stepmult));
		else if((x->common.attr_type == ps_msg_float) || (x->common.attr_type == ps_msg_generic))
			atom_setfloat(a, x->attr_value.a_w.w_float - (x->attr_stepsize * stepmult));
		else if(x->common.attr_type == ps_msg_toggle){
			if(x->attr_value.a_w.w_long == 1)
				x->attr_value.a_w.w_long = 0;
			else
				x->attr_value.a_w.w_long = 1;
			param_output_int(x);
			return;
		}
		else{
			error("%s parameter (in the %s module) is an inappropriate type for the 'dec' message.");
			return;
		}
	}
	param_dispatched(x, msg, a_len, a);
}


// INT INPUT
void param_int(t_param *x, long value)
{
	if (x->attr_slavemode)
		outlet_int(x->outlets[k_outlet_direct], value);
	else {	
		x->list_size = 1;
		if(x->common.attr_repetitions == 0){
			if(value == atom_getlong(&x->attr_value))
				return;
		}
		// new input - halt any ramping...
		if(x->ramper)
			x->ramper->stop();
		atom_setlong(&x->attr_value, value);
		x->param_output(x);
	}
}


// FLOAT INPUT
void param_float(t_param *x, double value)
{
	if (x->attr_slavemode)
		outlet_float(x->outlets[k_outlet_direct], value);
	else {
		x->list_size = 1;
		if(x->common.attr_repetitions == 0){
			if(value == atom_getfloat(&x->attr_value))
				return;
		}
		// new input - halt any ramping...
		if(x->ramper)
			x->ramper->stop();
	
		atom_setfloat(&x->attr_value, value);
		x->param_output(x);
	}
}


// SYMBOL INPUT
void param_symbol(t_param *x, t_symbol *msg, short argc, t_atom *argv)
{
	if (x->attr_slavemode)
		outlet_anything(x->outlets[k_outlet_direct], msg, argc, argv);
	else {	
		x->list_size = 1;
		if(x->common.attr_repetitions == 0){
			if(jcom_core_atom_compare(x->common.attr_type, &x->attr_value, argv))
				return;
		}
		atom_setsym(&x->attr_value, msg);
		x->param_output(x);
	}
}


void param_ui_refresh(t_param *x)
{
	if (!x->attr_slavemode)
		outlet_anything(x->outlets[k_outlet_set], _sym_set, x->list_size, &x->attr_value);
}


// Send feedback to the hub
void param_send_feedback(t_param *x)
{
	t_atom output[LISTSIZE + 1];
	t_atom *out = (t_atom *)(&output);
	
	// send to our ui outlet
	if(x->attr_ui_freeze == 0)
		qelem_set(x->ui_qelem);
	
	// call on the hub to pass our data onward
	if(x->common.hub != NULL){
		jcom_core_atom_copy(out, &x->name_atom);
		jcom_core_atom_copy(out+1, &x->attr_value);
		// copy any remaining atoms
		if(x->list_size > 1) 
			sysmem_copyptr(&x->atom_list[1], out + 2, sizeof(t_atom) * (x->list_size - 1));
		object_method_typed(x->common.hub, ps_feedback, x->list_size + 1, out, NULL);
	}
	// notify pattr that we have modified data
#ifndef JMOD_MESSAGE
	object_notify(x, _sym_modified, NULL);
#endif
}


// Send values to a potentially connected ui object at the first outlet
void param_ui_queuefn(t_param *x)
{
	outlet_anything(x->outlets[k_outlet_set], _sym_set, x->list_size, &x->attr_value);
}


// messages received from jcom.hub
void param_dispatched(t_param *x, t_symbol *msg, short argc, t_atom *argv)
{
	if (x->attr_slavemode)
		outlet_anything(x->outlets[k_outlet_direct], _sym_list, argc, argv);
	else {
		// new input - halt any ramping...
		if(x->ramper)
			x->ramper->stop();
		
		if(argc == 1 ){
			// If repetitions are disabled, we check for a repetition by treating
			// this as a 1 element list
			if(x->common.attr_repetitions == 0 && param_list_compare(x->atom_list, 
				x->list_size, argv, argc)) 
				return;

			x->list_size = 1;				
			jcom_core_atom_copy(&x->attr_value, argv);
			x->param_output(x);
		} else if(argc > 1) {
			param_list(x, msg, argc, argv);
		}
		else{ 	// no args
#ifndef JMOD_MESSAGE
			// generic parameters may have no arg -- i.e. to open a dialog that defines the arg
			if(x->common.attr_type == ps_msg_generic)
				x->list_size = 0;
#endif			
			x->param_output(x);
		}
	}
}

// Returns true if lists are identical
int param_list_compare(t_atom *x, long lengthx, t_atom *y, long lengthy)
{
	// If lists differ in length they're obviously not the same
	if(lengthx == lengthy) {
		short type;
		for(int i = 0; i < lengthx; i++) {
			if((x->a_type) != (y->a_type))
				return 0; // not identical, types differ
			
			type = x->a_type;
			if((type == A_FLOAT) && (x->a_w.w_float != y->a_w.w_float))
				return 0;
			else if((type == A_LONG) && (x->a_w.w_long != y->a_w.w_long))
				return 0;
			else if((type == A_SYM) && (x->a_w.w_sym != y->a_w.w_sym))
				return 0;
			
			x++; y++;  // keep going
		}
	} 
	else {
		return 0; // list lengths differ
	}
	
	return 1;
}

// LIST INPUT <value, ramptime>
void param_list(t_param *x, t_symbol *msg, short argc, t_atom *argv)
{
	float	value, time;
	
	if (x->attr_slavemode)
		outlet_anything(x->outlets[k_outlet_direct], _sym_list, argc, argv);
		
	// Check the second to last item in the list first, which when ramping should == the string ramp
	t_atom* ramp = argv + (argc - 2);
	if(ramp->a_type == A_SYM && ramp->a_w.w_sym == ps_ramp) {
		// XXX this currently doesn't handle ramping with lists
		value = atom_getfloat(argv);
		time = atom_getfloat(argv+(argc-1));

		if(time <= 0){
			jcom_core_atom_copy(&x->attr_value, argv);
			x->param_output(x);
			return;
		}	

		if(x->common.attr_repetitions == 0){
			if(param_list_compare(x->atom_list, x->list_size, argv, argc))
				return;	// nothing to do
		}
		x->ramper->set(atom_getfloat(&x->attr_value));
		x->ramper->go(value, time);
	} 
	else{
		// Don't output if the input data is identical
		if(!x->common.attr_repetitions) {
			if(param_list_compare(x->atom_list, x->list_size, argv, argc))
				return;	// nothing to do
		}
		
		// Avoid copying more than one atom if the type only can have one argument
		if(x->common.attr_type != ps_msg_list || x->common.attr_type != ps_msg_generic
			|| x->common.attr_type != ps_msg_none) {
			// If attr_type is != to anyone of the above values then we know 
			// that it must be == to a scalar type.  This ensures it will behave
			// as a scalar and not a list.
			argc = 1;
		}
			
		for(int i = 0; i < argc; i++) {
			switch(argv[i].a_type) 
			{
				case A_LONG:
					atom_setlong(&x->atom_list[i], atom_getlong(argv + i));
					break;
				case A_FLOAT:
					atom_setfloat(&x->atom_list[i], atom_getfloat(argv + i));
					break;
				case A_SYM:
					atom_setsym(&x->atom_list[i], atom_getsym(argv + i));
					break;
				default:
					error("param_list: no type specification");
					break;
			}
		}
		x->list_size = argc;
		x->param_output(x);
	}
}


#pragma mark -
#pragma mark Ramp Units

void param_ramp_callback_float(void *v, float value)
{
	t_param *x = (t_param *)v;
	float	oldval = atom_getfloat(&x->attr_value);
	
	if(x->common.attr_repetitions || value != oldval){
		atom_setfloat(&x->attr_value, value);
		param_output_float(x);
	}
}


void param_ramp_callback_int(void *v, float value)
{
	t_param	*x= (t_param *)v;
	long	val	= value, oldval;

	oldval = atom_getlong(&x->attr_value);
	if (x->common.attr_repetitions || val != oldval){
		atom_setlong(&x->attr_value, value);
		param_output_int(x);
	}
}


void param_ramp_setup(t_param *x)
{
	// 1. destroy the old rampunit
	if(x->ramper != NULL)
		delete x->ramper;
		
	// 2. create the new rampunit
	// For backwards compatibility, we still accept 'linear' as an input value for @ramp
	// but we need to convert that to the actual name of the rampunit...
	if(x->attr_ramp == ps_linear)
		x->attr_ramp = gensym("linear.sched");
		
	if((x->common.attr_type == ps_msg_int) || (x->common.attr_type == ps_msg_toggle))
		x->ramper = new rampunit(x->attr_ramp->s_name, param_ramp_callback_int, (void *)x);
	else	// assume float type
		x->ramper = new rampunit(x->attr_ramp->s_name, param_ramp_callback_float, (void *)x);
		
	if(x->ramper == NULL)
		error("jcom.parameter (%s module): could not allocate memory for ramp unit!", x->common.module_name);
}




See more files for this project here

Jamoma

Jamoma is a flexible framework for the creation of modules in Max, MSP, and Jitter

Project homepage: http://sourceforge.net/projects/jamoma
Programming language(s): C++,JavaScript,XML
License: other

  c74/
    ext_pattr_bundle.c
    ext_pattr_bundle.h
  jcom.parameter.xcodeproj/
    project.pbxproj
  jcom.message.def
  jcom.message.pch
  jcom.message.vcproj
  jcom.parameter.clip.cpp
  jcom.parameter.cpp
  jcom.parameter.def
  jcom.parameter.h
  jcom.parameter.pch
  jcom.parameter.sln
  jcom.parameter.vcproj