Code Search for Developers
 
 
  

jcom.hub.cpp from Jamoma at Krugle


Show jcom.hub.cpp syntax highlighted

/* 
 * jcom.hub
 * External for Jamoma: dispatch messages to jcom.param objects (a potential replacement for jcom.hub)
 * 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.hub.h"
#include <functional>
#define value value_list[0]

// Globals
t_class		*hub_class;				// Required: Global pointer for our class

/** A function object for determining if one t_subscriber object should follow another t_subscriber.
 * This is determined by the alphabetical ordering of the names of the two t_subscribers.
 */
struct _subIsLess : binary_function<t_subscriber*, t_subscriber*, bool> {
	bool operator()(const t_subscriber* p, const t_subscriber* q)
		{	return jcom_core_string_compare(p->name->s_name, q->name->s_name); }
} subscriberIsLess;


/************************************************************************************/
// Main() Function

int main(void)				// main recieves a copy of the Max function macros table
{
	long attrflags = 0;
	t_class *c;
	t_object *attr;
	
	// Initialize Globals
	common_symbols_init();

	// Define our class
	c = class_new("jcom.hub",(method)hub_new, (method)hub_free, (short)sizeof(t_hub), (method)0L, A_GIMME, 0);
	class_obexoffset_set(c, calcoffset(t_hub, obex));
	
	// Make methods accessible for our class:
 	class_addmethod(c, (method)hub_symbol,				"anything",					A_GIMME, 0L);
	class_addmethod(c, (method)hub_subscribe,			"subscribe",				A_CANT, 0L);	// client object subscribing
	class_addmethod(c, (method)hub_unsubscribe,			"unsubscribe",				A_CANT, 0L);	// client object unsubscribing
	class_addmethod(c, (method)hub_receive,				"feedback",					A_GIMME, 0L);	// feedback from parameters and such
	class_addmethod(c, (method)hub_private,				"private", 					A_GIMME, 0L);	// internal communications such as jcom.remote
	class_addmethod(c, (method)hub_return,				"return",					A_GIMME, 0L);	// feedback from jcom.return
	class_addmethod(c, (method)hub_return_extended,		"return_extended",			A_GIMME, 0L);	// feedback from jcom.return
	class_addmethod(c, (method)hub_assist,				"assist",					A_CANT, 0L); 
    class_addmethod(c, (method)object_obex_dumpout,		"dumpout",					A_CANT,	0);
    class_addmethod(c, (method)object_obex_quickref,	"quickref",					A_CANT, 0);

	class_addmethod(c, (method)hub_paramnames_get,		"parameter_names/dump", 	0L);
	class_addmethod(c, (method)hub_paramnames_get,		"/parameter_names/dump", 	0L);
	class_addmethod(c, (method)hub_messagenames_get,	"message_names/dump", 		0L);
	class_addmethod(c, (method)hub_messagenames_get,	"/message_names/dump",		0L);
	class_addmethod(c, (method)hub_returnnames_get,		"return_names/dump", 		0L);
	class_addmethod(c, (method)hub_returnnames_get,		"/return_names/dump",		0L);
	class_addmethod(c, (method)hub_allnames_get,		"*_names/dump",				0L);
	class_addmethod(c, (method)hub_allnames_get,		"/*_names/dump",			0L);
	class_addmethod(c, (method)hub_paramvalues_get,		"parameter_values/dump",	0L);
	class_addmethod(c, (method)hub_paramvalues_get,		"/parameter_values/dump",	0L);
	
	class_addmethod(c, (method)hub_modulename_get,		"module_name/get",			0L);
	class_addmethod(c, (method)hub_modulename_get,		"/module_name/get",			0L);
	class_addmethod(c, (method)hub_algorithmtype_get,	"algorithm_type/get",		A_CANT);
	class_addmethod(c, (method)hub_algorithmtype_get,	"/algorithm_type/get",		A_CANT);
	class_addmethod(c, (method)hub_init,				"init",						0L);
	class_addmethod(c, (method)hub_init,				"/init",					0L);
	class_addmethod(c, (method)hub_autodoc,				"documentation/generate",	A_DEFSYM, 0L);
	class_addmethod(c, (method)hub_autodoc,				"/documentation/generate",	A_DEFSYM, 0L);
	class_addmethod(c, (method)hub_module_view_alg,		"module/view_internals",	0L);
	class_addmethod(c, (method)hub_module_view_alg,		"/module/view_internals",	0L);
	class_addmethod(c, (method)hub_preset_read,			"preset/read",				A_DEFSYM, 0L);
	class_addmethod(c, (method)hub_preset_read,			"/preset/read",				A_DEFSYM, 0L);
	class_addmethod(c, (method)hub_preset_write,		"preset/write",				A_DEFSYM, 0L);
	class_addmethod(c, (method)hub_preset_write,		"/preset/write",			A_DEFSYM, 0L);
	class_addmethod(c, (method)hub_preset_recall,		"preset/recall",			A_GIMME, 0L);	// number or name
	class_addmethod(c, (method)hub_preset_recall,		"/preset/recall",			A_GIMME, 0L);	// number or name
	class_addmethod(c, (method)hub_preset_copy,		"preset/copy",			A_GIMME, 0L);	// number or name
	class_addmethod(c, (method)hub_preset_copy,		"/preset/copy",			A_GIMME, 0L);	// number or name
	class_addmethod(c, (method)hub_preset_store,		"preset/store",				A_GIMME, 0L);	// number & optional name
	class_addmethod(c, (method)hub_preset_store,		"/preset/store",			A_GIMME, 0L);	// number & optional name
	class_addmethod(c, (method)hub_preset_default,		"preset/default",			0L);
	class_addmethod(c, (method)hub_preset_default,		"/preset/default",			0L);
	class_addmethod(c, (method)hub_preset_default,		"presets/clear",			0L);
	class_addmethod(c, (method)hub_preset_default,		"/presets/clear",			0L);
	class_addmethod(c, (method)hub_presets_dump,		"preset/post",				0L);
	class_addmethod(c, (method)hub_presets_dump,		"/preset/post",				0L);
	class_addmethod(c, (method)hub_ui_freeze,			"ui/freeze", 				A_LONG, 0L);
	class_addmethod(c, (method)hub_ui_freeze,			"/ui/freeze", 				A_LONG, 0L);
	class_addmethod(c, (method)hub_ui_refresh,			"ui/refresh",				0L);
	class_addmethod(c, (method)hub_ui_refresh,			"/ui/refresh",				0L);

	// ATTRIBUTE: name
	attr = attr_offset_new("name", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_name));
	class_addattr(c, attr);
	
	// ATTRIBUTE: module_type	[audio, video, control, etc.]
	attr = attr_offset_new("module_type", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_type));
	class_addattr(c, attr);

	// ATTRIBUTE: size [1U, 2U, 3U 1U-half, etc.]
	attr = attr_offset_new("size", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_size));
	class_addattr(c, attr);

	// ATTRIBUTE: skin ['default', etc.]
	attr = attr_offset_new("skin", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_skin));
	class_addattr(c, attr);
	
	// ATTRIBUTE: algorithm_type [poly, blue, none, control, jitter, video, default, etc.]
	attr = attr_offset_new("algorithm_type", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_algorithm_type));
	class_addattr(c, attr);
	
	// ATTRIBUTE: description
	attr = attr_offset_new("description", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_description));
	class_addattr(c, attr);
			
	// ATTRIBUTE: inspector
	attr = attr_offset_new("inspector", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_hub, attr_inspector));
	class_addattr(c, attr);

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


/************************************************************************************/
// Object Life

void *hub_new(t_symbol *s, long argc, t_atom *argv)
{
	short			i;
	long			attrstart = attr_args_offset(argc, argv);
	t_hub	*x = (t_hub *)object_alloc(hub_class);
	t_symbol		*name = _sym_nothing;
	
	if(attrstart && argv)
		atom_arg_getsym(&name, 0, attrstart, argv);
	else
		name = symbol_unique();

	if(x){
		for(i=k_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->init_qelem = qelem_new(x, (method)hub_qfn_init);

		x->attr_name = name;
		x->osc_name = _sym_nothing;
		x->attr_type = ps_audio;
		x->attr_description = _sym_nothing;
		x->attr_algorithm_type = ps_default;		// poly for audio, jitter for video, control for control
		x->attr_skin = ps_default;					// default tells the gui constructor js to choose for us
		x->attr_size = ps_1U;
		x->attr_inspector = 0;
		x->using_wildcard = false;
		x->in_object = NULL;						// module MUST have a jcom.in object
		x->out_object = NULL;						// the jcom.out object is optional
		x->gui_object = NULL;						// jcom.remote in the gui
		x->num_parameters = 0;
		for(i=0; i<16; i++)
			x->meter_object[i] = NULL;
		x->preview_object = NULL;
		
		x->preset = new presetList;							// begin with no presets
		x->subscriber = new subscriberList;						// ... and no subscribers
		
		attr_args_process(x, argc, argv);			// handle attribute args
		
		object_obex_lookup(x, gensym("#P"), (t_object **)&x->container);
		if(!x->container)
			x->container = (t_patcher *)gensym("#P")->s_thing;
		defer_low(x, (method)hub_examine_context, 0, 0, 0);
		
		x->jcom_send = NULL;
		x->jcom_receive = NULL;
		x->jcom_send_broadcast = NULL;
		if(!jcom_core_loadextern(ps_jcom_send, ps_jcom_remote_fromModule, &x->jcom_send))
			error("jcom.hub: loading jcom.send extern failed!");
		if(!jcom_core_loadextern(ps_jcom_receive, ps_jcom_remote_toModule, &x->jcom_receive))
			error("jcom.hub: loading jcom.receive extern failed!");
		else
			object_method(x->jcom_receive, ps_setcallback, &hub_receive_callback, x);
			
		if(!jcom_core_loadextern(ps_jcom_send, ps_jcom_broadcast_fromHub, &x->jcom_send_broadcast))
			error("jcom.hub: loading jcom.send (broadcast) extern failed!");
	}
	return (x);										// return the pointer to our new instantiation
}




typedef struct bpatcher {
	t_box b_box;
	short a,b;
	short c,d;
	short e,f;
	short g,h;
	short i,j;
	short k,l;
	short m,n;
	short o;
	Symbol *b_name;
	Atom b_argv[10];
	short b_argc;
} t_bpatcher;



void hub_examine_context(t_hub *x)
{
	t_patcher	*p = x->container;
	t_box		*box = p->p_box;
	t_symbol	*s = NULL;
	t_atombuf	*atoms = NULL;
	long		size = 0;
	t_atom		*argv = NULL;
	char		name[256];
	char		*nametest;
	unsigned short		i;

	if(p->p_vnewobj != NULL){							// THIS SHOULD INDICATE WE ARE NOT AT THE TOP LEVEL (i.e. not editing)						//	go up one level to look at how the module is instantiated
		box = (t_box *)p->p_vnewobj;
		atoms = (t_atombuf *)box->b_binbuf;
		if(!atoms){
			if(ob_sym(box) == gensym("bpatcher")){
				t_bpatcher *bp = (t_bpatcher *)box;
				size = bp->b_argc;
				argv = bp->b_argv;
				x->osc_name = atom_getsym(argv);
				strcpy(name, x->osc_name->s_name);
			}
		} 
		else{
			size = atoms->a_argc - 1;
			argv = atoms->a_argv + 1;		
			x->osc_name = atom_getsym(argv);
			strcpy(name, x->osc_name->s_name);
		}
		
		// if no arg is present, then try to use the scripting name of the object
		if(x->osc_name == _sym_nothing){
			p = box->b_patcher;	
			if(patcher_boxname(p, box, &s))
				strcpy(name, s->s_name);
			else{	
				// try to invent something intelligent for a name
				post("%s: this module was not given an osc name as an argument!  making up something that will hopefully work.", x->attr_name->s_name);				
				strcpy(name, "/");
				strcat(name, x->attr_name->s_name);
			}
		}
		// the name must begin with a /
		if(name[0] != '/'){
			char newname[256];
			
			strcpy(newname, "/");
			strcat(newname, name);
			strcpy(name, newname);
			error("%s: name arguments for modules must begin with a slash!  inserting one automatically", x->attr_name->s_name);
		}
		
		// search for illegal characters as specified by the OSC standard and replace them
		for(i=0; i<strlen(name); i++){
			if(name[i] == '[')
				name[i] = '.';
			else if(name[i] == ']')
				name[i] = 0;
		}
		
		// if arg contains a slash then we must complain
		nametest = name + 1;
		if(strchr(nametest, '/')){
			error("%s: OSC NAME GIVEN TO MODULES MAY NOT CONTAIN A SLASH OTHER THAN THE LEADING SLASH!", x->attr_name->s_name);
		}

		x->osc_name = gensym(name);
	}
	else
		x->osc_name = gensym("/editing_this_module");
		
	// Finally, we now tell subscribers (parameters, etc.) to subscribe
	if(x->jcom_send_broadcast){
		if(ps_jcom_broadcast_fromHub->s_thing)
			object_method_typed(x->jcom_send_broadcast, gensym("hub.changed"), 0, NULL, NULL);
	}
}

void hub_free(t_hub *x)
{
	subscriberIterator i;
	subscriberList *subscriber = x->subscriber;

	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		// notify the subscriber that the hub is going away
		object_method((*i)->object, ps_release);
		sysmem_freeptr(*i);
	}
	critical_exit(0);	

 	hub_presets_clear(x);
	qelem_free(x->init_qelem);
	if(x->jcom_send)
		object_free(x->jcom_send);
	if(x->jcom_receive)
		object_free(x->jcom_receive);
	if(x->jcom_send_broadcast)
		object_free(x->jcom_send_broadcast);
	delete x->subscriber;
	delete x->preset;
}


/************************************************************************************/
// Communication with jcom.param objects

// This method is called from clients such as jcom.parameter to register it with this hub
t_symbol* hub_subscribe(t_hub *x, t_symbol *name, void *subscriber_object, t_symbol *type)
{
	t_subscriber	*new_subscriber;
	
	if(subscriber_object == NULL){
		error("Null object cannot subscribe to jcom.hub");
		return _sym_nothing;
	}
	
	// Create the new item
	new_subscriber = (t_subscriber *)sysmem_newptr(sizeof(t_subscriber));
	new_subscriber->object = subscriber_object;
	new_subscriber->name = name;
	new_subscriber->type = type;

	critical_enter(0);
	// Merge new subscriber into subscriber list sorted alphabetically
	x->subscriber->merge(new_subscriber, subscriberIsLess);

	// special cases and other caching
	if(new_subscriber->type == ps_subscribe_in){
		x->in_object = subscriber_object;
		if(x->out_object){		// set up pointers between jcom.in and jcom.out
			object_method(x->in_object, ps_link_out, x->out_object);
			object_method(x->out_object, ps_link_in, x->in_object);
		}
	}
	if(new_subscriber->type == ps_subscribe_out){
		x->out_object = subscriber_object;
		if(x->in_object){		// set up pointers between jcom.in and jcom.out
			object_method(x->in_object, ps_link_out, x->out_object);
			object_method(x->out_object, ps_link_in, x->in_object);
		}
		for(int i=0; i<16; i++)
			object_method(x->out_object, ps_register_meter, i, x->meter_object[i]);
		object_method(x->out_object, ps_register_preview, x->preview_object);
	}

	if(new_subscriber->type == ps_subscribe_remote){
		int meternum = 0;
		sscanf( new_subscriber->name->s_name, "__meter__%i", &meternum);
		if(meternum > 0){
			x->meter_object[meternum-1] = new_subscriber->object;
			if(x->out_object)
				object_method(x->out_object, ps_register_meter, meternum-1, x->meter_object[meternum-1]);
		}
		else if(new_subscriber->name == ps___preview__){
			x->preview_object = new_subscriber->object;
			if(x->out_object)
				object_method(x->out_object, ps_register_preview, x->preview_object);				
		}
	}
	
	if(new_subscriber->type == ps_subscribe_parameter)
		x->num_parameters++;
	if(new_subscriber->name == ps__gui__)
		x->gui_object = subscriber_object;
	critical_exit(0);
		
	qelem_set(x->init_qelem);			// flag the queue for initialization
	return x->attr_name;				// return the module name to the parameter
}


void hub_unsubscribe(t_hub *x, void *subscriber_object)
{
	subscriberList	*subscribers = x->subscriber;
	
	// Search the linked list for this object and remove it
	t_subscriber* t;
	critical_enter(0);
	for(subscriberIterator item = subscribers->begin(); item != subscribers->end(); ++item) {
		t = *item;
		
		if(t->object == subscriber_object) {
			if(t->type == ps_subscribe_parameter)
				x->num_parameters--;
			else if(t->type == ps_subscribe_in){
				if(x->out_object)
					object_method(x->out_object, ps_unlink_out);
			}
			else if(t->type == ps_subscribe_out){
				if(x->in_object)
					object_method(x->in_object, ps_unlink_in);
			}
			else if(t->type == ps_subscribe_remote){
				char temp[32];
				for(short i=0; i<16; i++) {
					snprintf(temp, 32, "__meter__%i", i);
					if(t->name == gensym(temp)) {
						if(x->out_object)
							object_method(x->out_object, gensym("remove_meters"));
					}
				}
			}
			item = subscribers->erase(item);
			sysmem_freeptr(t);
			/** XXX why does this need to be here?  It seems Microsoft's compiler is generating code 
			 * that will preincrement (++) the item iterator in the for loop despite the fact that 
			 * the for loops if condition has been met and following conditional statement shouldn't
			 * execute.  Either that or something awkward about the the behavior of their STL 
			 * implementation */
			if(item == subscribers->end())
				break;

		}
	}

	critical_exit(0);
}


// Receive parameter values from jcom.parameter
void hub_receive(t_hub *x, t_symbol *name, short argc, t_atom *argv)
{
	char		namestring[256];
	t_symbol	*osc;
	
	strcpy(namestring, "/");						// perhaps we could optimize this operation
	strcat(namestring, argv->a_w.w_sym->s_name);	//	by creating a table when the param is bound
	osc = gensym(namestring);						//	then we could look-up the symbol instead of using gensym()

	if(x->in_object != NULL)
		object_method_typed(x->in_object, ps_algorithm_message, argc, argv, NULL);	// send to jcom.in
	if(x->out_object != NULL)
		object_method_typed(x->out_object, ps_algorithm_message, argc, argv, NULL);	// send to jcom.out

	hub_outlet_return(x, osc, argc-1, argv+1);
}


// Receive private messages from jcom.remote
void hub_private(t_hub *x, t_symbol *name, short argc, t_atom *argv)
{
	t_symbol		*private_id = _sym_nothing;	
	t_symbol		*private_message = _sym_nothing;
	t_symbol		*userpath = _sym_nothing;
	long			n = 0;
	
	private_id = atom_getsym(argv);
	argc--;
	argv++;
	private_message = atom_getsym(argv);
	argc--;
	argv++;
	if (private_id == ps__gui__)
	{
		if (private_message == ps_slash_preset_slash_default)			// 	/preset/default
			hub_preset_default(x);
		else if (private_message == ps_slash_preset_slash_load)			// 	/preset/load
			hub_preset_read(x, userpath);
		else if (private_message == ps_slash_preset_slash_recall)		// 	/preset/load
			hub_preset_recall(x, _sym_list, 1, argv);
		else if (private_message == ps_slash_preset_slash_copy)		// 	/preset/load
			hub_preset_copy(x, _sym_list, 1, argv);
		else if (private_message == ps_slash_preset_slash_write)			//	/preset/save
			hub_preset_write(x, userpath);
		else if (private_message == ps_slash_module_view_internals)		//	/module/view_internals
			hub_module_view_alg(x);
		else if (private_message == ps_slash_ui_slash_freeze) {			// 	/ui/freeze
			if (argc>0)
				n = atom_getlong(argv);
			hub_ui_freeze(x, n);
		}
		else if ( private_message == ps_slash_ui_slash_refresh )		//	/ui/refresh
			hub_ui_refresh(x);
		else
			hub_symbol(x, private_message, argc, argv);
	}
}


// Receive messages from jcom.return - don't send messages back to the algorithm
void hub_return(t_hub *x, t_symbol *name, short argc, t_atom *argv)
{
	char		namestring[256];
	t_symbol	*osc;
	
	strcpy(namestring, "/");						// perhaps we could optimize this operation
	strcat(namestring, argv->a_w.w_sym->s_name);	//	by creating a table when the param is bound
	osc = gensym(namestring);						//	then we could look-up the symbol instead of using gensym()
	hub_outlet_return(x, osc, argc-1, argv+1);
}


// A version of the above that performs wilcard substitution
void hub_return_extended(t_hub *x, t_symbol *name, short argc, t_atom *argv)
{
	char		namestring[256];
	t_symbol	*osc;
	
	strcpy(namestring, "/");						// perhaps we could optimize this operation
	strcat(namestring, argv->a_w.w_sym->s_name);	//	by creating a table when the param is bound
	if(namestring[strlen(namestring)-1] == '*'){
		namestring[strlen(namestring)-1] = 0;
		if(argv[1].a_type == A_LONG)
			sprintf(namestring, "%s%ld", namestring, argv[1].a_w.w_long);
		else if(argv[1].a_type == A_FLOAT)
			sprintf(namestring, "%s%f", namestring, argv[1].a_w.w_float);
		else // assuming symbol
			strcat(namestring, atom_getsym(argv+1)->s_name);
		osc = gensym(namestring);						//	then we could look-up the symbol instead of using gensym()
		hub_outlet_return(x, osc, argc-2, argv+2);		
	}
	else{
		osc = gensym(namestring);						//	then we could look-up the symbol instead of using gensym()
		hub_outlet_return(x, osc, argc-1, argv+1);
	}
}


// All messages being returned from the module should be funneled through this function!
void hub_outlet_return(t_hub *x, t_symbol *msg, short argc, t_atom *argv)
{
	outlet_anything(x->outlets[k_outlet_return], msg, argc, argv);

	if(x->osc_name == NULL)					// it's possible for this method to be called before osc_name is valid
		return;								//	...
	if(!ps_jcom_remote_fromModule->s_thing)	// we check this so jcom.send doesn't give us errors
		return;								//	because there may be no matching jcom.receives, and that's okay...
	if(x->jcom_send){
		char		mess[256];
		t_symbol	*osc;
		
		strcpy(mess, x->osc_name->s_name);
		strcat(mess, msg->s_name);
		osc = gensym(mess);
		object_method_typed(x->jcom_send, osc, argc, argv, NULL);
	}
}


t_symbol *hub_modulename_get(t_hub *x)
{
	t_atom	a;

	if(x->osc_name != NULL){
		if(x->osc_name != _sym_nothing){
			atom_setsym(&a, x->osc_name);	
			hub_outlet_return(x, gensym("/module_name"), 1, &a);
		}
	}
	return x->attr_name;
}


t_symbol *hub_algorithmtype_get(t_hub *x)
{
	return x->attr_algorithm_type;
}


void hub_init(t_hub *x)
{
	subscriberList	*subscriber = x->subscriber;
	subscriberIterator i;
		
	// Search the linked list for jcom.init objects and 'bang' them
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		if((*i)->type == ps_subscribe_init)
			object_method((*i)->object, ps_go);
	}
	
	critical_exit(0);
	defer_low(x, (method)hub_preset_default, 0, 0, 0L);
}


// send a local jcom.init message for the module
void hub_qfn_init(t_hub *x)
{
	hub_gui_build(x);							// immediately set up the GUI
	defer_low(x, (method)hub_init, 0, 0, 0);	// defer the rest of the initialization
}


// send info to gui constructor
void hub_gui_build(t_hub *x)
{
	subscriberList 	*subscriber = x->subscriber;

	if(x->gui_object != NULL){
		t_atom a[3];
		
		atom_setsym(&a[0], ps_ATTRIBUTES);
		if(x->attr_size){
			atom_setsym(&a[1], ps_size);
			atom_setsym(&a[2], x->attr_size);
			object_method_typed(x->gui_object, ps_dispatched, 3, a, NULL);
		}
		if(x->attr_inspector){
			atom_setsym(&a[1], ps_inspector);
			atom_setlong(&a[2], x->attr_inspector);
			object_method_typed(x->gui_object, ps_dispatched, 3, a, NULL);
		}
		if(x->attr_algorithm_type){
			atom_setsym(&a[1], ps_algorithm_type);
			atom_setsym(&a[2], x->attr_algorithm_type);
			object_method_typed(x->gui_object, ps_dispatched, 3, a, NULL);
		}
		if(x->attr_type){
			atom_setsym(&a[1], ps_module_type);
			atom_setsym(&a[2], x->attr_type);
			object_method_typed(x->gui_object, ps_dispatched, 3, a, NULL);
		}
		if(x->attr_skin){
			atom_setsym(&a[1], ps_skin);
			atom_setsym(&a[2], x->attr_skin);
			object_method_typed(x->gui_object, ps_dispatched, 3, a, NULL);
		}
		if(x->osc_name){
			atom_setsym(&a[1], ps_MODULE_TITLE);
			atom_setsym(&a[2], x->osc_name);
			object_method_typed(x->gui_object, ps_dispatched, 3, a, NULL);
		}
		if(x->attr_name){
			atom_setsym(&a[0], ps_MODULE_NAME);
			atom_setsym(&a[1], x->attr_name);
			object_method_typed(x->gui_object, ps_dispatched, 2, a, NULL);			
		}
		
		subscriberIterator i;
		t_subscriber* t;
		critical_enter(0);
		for(i = subscriber->begin(); i != subscriber->end(); ++i) {
			t = *i;
			if((t->type == ps_subscribe_message) || t->type == ps_subscribe_parameter){
				atom_setsym(&a[0], ps_PARAMETER);
				atom_setsym(&a[1], t->name);
				object_method_typed(x->gui_object, ps_dispatched, 2, a, NULL);			
			}
		}
		critical_exit(0);

		atom_setsym(&a[0], ps_BUILD);		
		object_method_typed(x->gui_object, ps_dispatched, 1, a, NULL);
	}
}


/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void hub_assist(t_hub *x, void *b, long msg, long arg, char *dst)
{
	if(msg==1) 						// Inlet
		strcpy(dst, "input");
	else{							// Outlets
		switch(arg){
			case k_outlet_return:
					strcpy(dst, "return: connect to return outlet");
					break;
			case k_outlet_dumpout:
					strcpy(dst, "psto: connect to dumpout");
					break;
		}
 	}		
}


// Return a list of parameters and message for this module
void hub_paramnames_get(t_hub *x)
{
	subscriberList	*subscriber = x->subscriber;	// head of the linked list
	t_atom			a;
	
	hub_outlet_return(x, ps_parameter_names_start, 0, NULL);
	
	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		t = *i;
		atom_setsym(&a, t->name);
		if(t->type == ps_subscribe_parameter)
			hub_outlet_return(x, ps_parameter_name, 1, &a);
	}
	critical_exit(0);
	hub_outlet_return(x, ps_parameter_names_end, 0, NULL);
}


// Return a list of parameters and message for this module
void hub_paramvalues_get(t_hub *x)
{
	subscriberList	*subscriber = x->subscriber;	// head of the linked list
	t_atom			*av;
	long			ac;
	char			osc[512];
	
	hub_outlet_return(x, ps_parameter_values_start, 0, NULL);
	
	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		t = *i;
		if(t->type == ps_subscribe_parameter){
			ac = NULL; av = NULL;										// init
			object_attr_getvalueof(t->object, ps_value, &ac, &av);		// get	
			sprintf(osc, "%s/%s", ps_parameter_value->s_name, t->name->s_name);
			hub_outlet_return(x, gensym(osc), ac, av);
		}
	}
		
	critical_exit(0);
	hub_outlet_return(x, ps_parameter_values_end, 0, NULL);
}


void hub_messagenames_get(t_hub *x)
{
	subscriberList	*subscriber = x->subscriber;	// linked list of subscribers
	t_atom			a;
	
	hub_outlet_return(x, ps_message_names_start, 0, NULL);
	
	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		t = *i;
		atom_setsym(&a, t->name);
		if(t->type == ps_subscribe_message)
			hub_outlet_return(x, ps_message_name, 1, &a);
	}
	critical_exit(0);
	hub_outlet_return(x, ps_message_names_end, 0, NULL);
}


void hub_returnnames_get(t_hub *x)
{
	subscriberList	*subscriber = x->subscriber;	// head of the linked list
	t_atom			a;
	
	hub_outlet_return(x, ps_return_names_start, 0, NULL);
	
	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		t = *i;
		atom_setsym(&a, t->name);
		if(t->type == ps_subscribe_return)
			hub_outlet_return(x, ps_message_return, 1, &a);
	}
	critical_exit(0);
	hub_outlet_return(x, ps_return_names_end, 0, NULL);
}


void hub_allnames_get(t_hub *x)
{
	hub_paramnames_get(x);
	hub_messagenames_get(x);
	hub_returnnames_get(x);
}


// SYMBOL INPUT
void hub_symbol(t_hub *x, t_symbol *msg, short argc, t_atom *argv)
{
	bool			found = false;
	subscriberList	*subscriber = x->subscriber;
	char			input[MAX_STRING_LEN];	// our input string
	char			*input2 = input;		// pointer to our input string
	char			*split;
	t_symbol		*osc = NULL;
	t_symbol		*name = msg;			// default to the name being the message

	strcpy(input, msg->s_name);
	if(*input2 == '/')				// leading slash means it's OSC...
		input2++;					// remove the the leading slash

	split = strchr(input2, ':');	// remove (and store) the param name
	if(split != NULL){
		*split = NULL;
		split++;					// now input2 = param name; split = a message for the parameter object		
		osc = gensym(split);
	}
	name = gensym(input2);

	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	if(name == ps_star){			// wildcard
		t_symbol* type;
		for(i = subscriber->begin(); i != subscriber->end(); ++i) {
			t = *i; type = t->type;
			if(type == ps_subscribe_parameter 
			  || type == ps_subscribe_message 
			  || type == ps_subscribe_return){
				if(osc == NULL){
					object_method_typed(t->object, ps_dispatched, argc, argv, NULL);
				}
				else{
					object_method_typed(t->object, osc, argc, argv, NULL);
				}
			}
		}
	}
	else{
		
		// search the linked list of params to find the right one
		for(i = subscriber->begin(); (i != subscriber->end()) && (found == false); ++i) {
			t = *i; 
			if(t->name == name) {
				found = true;
				break;
			}
		}

		// dispatch to the correct jcom.param object
		if(found == true){
			if(osc == NULL){
				object_method_typed(t->object, ps_dispatched, argc, argv, NULL);
			}
			else
				object_method_typed(t->object, osc, argc, argv, NULL);
		}
		else{
			// if we got here through the use a remote message to modules named by a wildcard
			// then we need don't post annoying errors to the Max window
			if(!x->using_wildcard)
				error("jcom.hub cannot find a parameter by that name (%s)", name->s_name);
		}
	}
	critical_exit(0);
}


void hub_module_view_alg(t_hub *x)
{
	if(x->in_object != NULL)
		object_method_typed(x->in_object, ps_open, 0, 0L, NULL);					// send "open" to jcom.in
	hub_outlet_return(x, ps_slash_module_view_internals, 0, 0L);					// return from jcom.hub left outlet
}


// FREEZE UI for all parameters
void hub_ui_freeze(t_hub *x, long val)
{
	subscriberList *subscriber = x->subscriber;	// head of the linked list
	t_atom a;

	atom_setlong(&a, val);	
	
	// Update stored parameter value for module/freeze
	hub_symbol(x, ps_ui_slash_freeze, 1, &a);
	
	// Change freeze status for all messages and parameters	
	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		t = *i;
		if(t->type == ps_subscribe_parameter)
			object_method_typed(t->object, ps_ui_slash_freeze, 1, &a, NULL);
	}
	critical_exit(0);
}


// REFRESH UI for all parameters
void hub_ui_refresh(t_hub *x)
{
	subscriberList *subscriber = x->subscriber;	// head of the linked list
	
	subscriberIterator i;
	t_subscriber* t;
	critical_enter(0);
	for(i = subscriber->begin(); i != subscriber->end(); ++i) {
		t = *i;
		if(t->type == ps_subscribe_parameter)
			object_method_typed(t->object, ps_ui_slash_refresh, 0, 0L, NULL);
	}
	critical_exit(0);
}


// receive messages from our internal jcom.receive external
void hub_receive_callback(void *z, t_symbol *msg, short argc, t_atom *argv)
{
	t_hub		*x = (t_hub *)z;
	char		mess[256];
	char		*in = &mess[0];
	char		*split;
	t_symbol	*osc;
	
	strcpy(mess, msg->s_name);
	if(*in == '/')					// remove leading slash...
		in++;
		
	split = strchr(in, '/');		// get the OSC message for the module
	if(split == NULL){
		error("jcom.hub (%s module) received message from jcom.send with problematic or missing OSC namespace (%s)", x->attr_name->s_name, mess);
		return;
	}

	*split = 0;						
	
	if(*in == '*'){										// wildcard
		// when parsing wildcards, we need to check and see if there is actually a valid subscriber
		// before blindly sending the message... 
		split++;
		osc = gensym(split);
		x->using_wildcard = true;
		object_method_typed(x, osc, argc, argv, NULL);		// call the method on this hub object
		x->using_wildcard = false;
	}
	else if(!strcmp(mess, x->osc_name->s_name)){		// check if we are the correct module...
		split++;
		osc = gensym(split);
		object_method_typed(x, osc, argc, argv, NULL);		// call the method on this hub object
	}
}




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

  jcom.hub.xcodeproj/
    project.pbxproj
  jcom.hub.autodoc.cpp
  jcom.hub.cpp
  jcom.hub.def
  jcom.hub.h
  jcom.hub.presets.cpp
  jcom.hub.sln
  jcom.hub.vcproj