Code Search for Developers
 
 
  

jcom.in.cpp from Jamoma at Krugle


Show jcom.in.cpp syntax highlighted

/* 
 * jcom.in~
 * External for Jamoma: manage audio inputs for a module
 * By Tim Place, Copyright © 2006
 * 
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html 
 */


/*
	The user specifies @channel_config mono or @channel_config stereo 
	as arg to the module.  That makes the hub responsible for cleaning
	up any unused inlets and outlets for the configuration.  
	
	It may also signal to the module to handle the poly differently,
	i.e. if the algorithm should be true stereo instead of multi-mono
	
	This all means that we need this object to subscribe to the hub.
*/

#include "ext.h"					// Max Header
#include "z_dsp.h"					// MSP Header
#include "ext_strings.h"			// String Functions
#include "commonsyms.h"				// Common symbols used by the Max 4.5 API
#include "ext_obex.h"				// Max Object Extensions (attributes) Header
#include "jcom.core.h"
#include "jcom.io.h"
#include "jcom.in.h"

// Globals
t_class		*in_class;					// Required. Global pointing to this class
t_atom		ga_zero;


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

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

	// Define our class
#ifdef JCOM_IN_TILDE
	c = class_new("jcom.in~",(method)in_new, (method)in_free, (short)sizeof(t_in), (method)0L, A_GIMME, 0);
#else
	c = class_new("jcom.in",(method)in_new, (method)in_free, (short)sizeof(t_in), (method)0L, A_GIMME, 0);
#endif

	offset = calcoffset(t_in, common);
	class_obexoffset_set(c, offset + calcoffset(t_jcom_core_subscriber_common, obex));

	// Make methods accessible for our class: 
	class_addmethod(c, (method)in_dispatched,			"dispatched",			A_GIMME, 0L);
	class_addmethod(c, (method)in_algorithm_message,	"algorithm_message",	A_GIMME, 0L);
	class_addmethod(c, (method)in_view_internals,		"open",					A_GIMME, 0L);	// method used to view algorithm
	class_addmethod(c, (method)in_link,					"link_out",				A_CANT, 0L);	// maybe used to forward messages in jmod.in
	class_addmethod(c, (method)in_unlink,				"unlink_out",			0L);
#ifdef JCOM_IN_TILDE
	class_addmethod(c, (method)in_dsp,					"dsp", 					A_GIMME, 0L);
#else
	class_addmethod(c, (method)in_bang,					"bang", 				0L);
	class_addmethod(c, (method)in_int,					"int", 					A_LONG, 0L);
	class_addmethod(c, (method)in_float,				"float", 				A_FLOAT, 0L);
	class_addmethod(c, (method)in_anything,				"list", 				A_GIMME, 0L);
	class_addmethod(c, (method)in_anything,				"anything",				A_GIMME, 0L);	
#endif
	class_addmethod(c, (method)in_release,				"release",				A_CANT, 0L);	// notification of hub being freed
    class_addmethod(c, (method)in_assist,				"assist", 				A_CANT, 0L);

	jcom_core_subscriber_classinit_common(c, attr, offset);	
	
	// ATTRIBUTE: algorithm_type
	attr = attr_offset_new("algorithm_type", _sym_symbol, attrflags,
		(method)0, (method)0, calcoffset(t_in, attr_algorithm_type));
	class_addattr(c, attr);
	
	// ATTRIBUTE: num_inputs
	attr = attr_offset_new("num_inputs", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_in, num_inputs));
	class_addattr(c, attr);	

#ifdef JCOM_IN_TILDE
	// ATTRIBUTE: manage_channels
	attr = attr_offset_new("manage_channels", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_in, attr_manage_channels));
	class_addattr(c, attr);
	
	// Setup our class to work with MSP
	class_dspinit(c);
#endif

	// Finalize our class
	class_register(CLASS_BOX, c);
	in_class = c;

	jcom_core_init();
	atom_setlong(&ga_zero, 0);
	return 0;
}


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

// Create
void *in_new(t_symbol *s, short argc, t_atom *argv)
{
	long 		attrstart = attr_args_offset(argc, argv);		// support normal arguments
	t_in 		*x = (t_in *)object_alloc(in_class);
	short 		i;
		
	if(x){
		x->dumpout = outlet_new(x, NULL);
		x->algout = outlet_new(x, NULL);
		
		object_obex_store((void *)x, ps_dumpout, (object *)x->dumpout);		// setup the dumpout

		x->num_inputs = 0;
		x->attr_manage_channels = 0;
		x->attr_algorithm_type = _sym_nothing;
		x->attr_bypass = 0;
		x->attr_mute = 0;
		x->attr_freeze = 0;
		x->vector_size = 0;  // reset cached vector size

		if(attrstart > 0){
			int argument = atom_getlong(argv);
			x->num_inputs = tt_audio_base::clip(argument, 0, MAX_NUM_CHANNELS);
		} 
		else
			x->outlet[0] = x->algout;  // no arguments send any input out the first outlet

#ifdef JCOM_IN_TILDE
		if(x->num_inputs > 0)
			dsp_setup((t_pxobject *)x, x->num_inputs);		// Create Object and Inlets
		else
			dsp_setup((t_pxobject *)x, 1);					// Create Object and Inlet

		x->common.ob.z_misc = Z_NO_INPLACE | Z_PUT_FIRST;
		
		for(i=0; i < (x->num_inputs); i++)
			outlet_new((t_pxobject *)x, "signal");			// Create a signal outlet   		
		for(i=0; i < MAX_NUM_CHANNELS; i++)
			x->signal_in[i] = new tt_audio_signal;			// Storage for the signal (accessed by jcom.out~)
		in_alloc(x, sys_getblksize());						// allocates the vectors for the audio signals
#else
		for(i = x->num_inputs-1; i >= 1; i--)
			x->inlet[i] = proxy_new(x, i, 0L);
		for(i = x->num_inputs-1; i >= 0; i--)
			x->outlet[i] = outlet_new(x, 0L);

#endif
		jcom_core_subscriber_new_common(&x->common, ps__jcom_in__, ps_subscribe_in);
		jcom_core_subscriber_setcustomsubscribe_method(&x->common, &in_subscribe);
		attr_args_process(x, argc, argv);					// handle attribute args				
		defer_low(x, (method)jcom_core_subscriber_subscribe, 0, 0, 0);
	}
	return (x);												// Return the pointer
}


// deferred function for registering with the jcom.hub object
void in_subscribe(void *z)
{
	long		argc;
	t_atom		a;
	t_atom		*argv = &a;
	t_symbol	*result;
	t_symbol	*modtype;
	t_in		*x = (t_in *)z;
	
	//x->common.hub = jcom_core_subscribe(x, x->common.attr_name, x->common.container, ps_subscribe_in);
	if(x->common.hub != NULL){
		//object_attr_getvalueof(x->common.hub, ps_name, &argc, &argv);
		//x->common.module_name = atom_getsym(argv);
		
		// Find out what type of algorithm this is supposed to control
		object_attr_getvalueof(x->common.hub, ps_algorithm_type, &argc, &argv);
		result = atom_getsym(argv);
		if(result == ps_default){
			object_attr_getvalueof(x->common.hub, ps_module_type, &argc, &argv);
			modtype = atom_getsym(argv);
			
			if(modtype == ps_audio)
				x->attr_algorithm_type = ps_poly;
			else if(modtype == ps_video)
				x->attr_algorithm_type = ps_jitter;
			else
				x->attr_algorithm_type = ps_control;
		}
		else
			x->attr_algorithm_type = result;
	}
	if(x->attr_algorithm_type == ps_poly && x->attr_manage_channels)
		outlet_anything(x->algout, ps_target, 1, &ga_zero);
}


// Destroy
void in_free(t_in *x)
{
#ifdef JCOM_IN_TILDE
	short i;
	
	dsp_free((t_pxobject *)x);			// Always call dsp_free first in this routine
	for(i=0; i < MAX_NUM_CHANNELS; i++)
		delete x->signal_in[i];
#endif
	jcom_core_subscriber_common_free(&x->common);
}


// Notification that the hub no longer exists
void in_release(t_in *x)
{
	jcom_core_subscriber_hubrelease(&x->common);
	x->out_object = NULL;
}


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

// Method for Assistance Messages
void in_assist(t_in *x, void *b, long msg, long arg, char *dst)
{
	if(msg==1) 	// Inlets
		strcpy(dst, "(signal) input to the module");
	else if(msg==2){ // Outlets
		if(arg < x->num_inputs) 
			strcpy(dst, "(signal) connect to the algorithm");
		else if(arg == x->num_inputs) 
			strcpy(dst, "connect to algorithm");
		else 
			strcpy(dst, "dumpout");
	}
}


// messages received from jcom.hub for the algorithm
void in_algorithm_message(t_in *x, t_symbol *msg, short argc, t_atom *argv)
{
	char		namestring[256];
	t_symbol	*osc;

	if((argv->a_w.w_sym == ps_audio_mute) || (argv->a_w.w_sym == ps_slash_audio_mute)){
		x->attr_mute = atom_getlong(argv+1);
		outlet_anything(x->algout, ps_mute, argc-1, argv+1);
	}
	else if((argv->a_w.w_sym == ps_video_mute) || (argv->a_w.w_sym == ps_slash_video_mute))
		x->attr_mute = atom_getlong(argv+1);
	else if((argv->a_w.w_sym == ps_video_bypass) || (argv->a_w.w_sym == ps_slash_video_bypass))
		x->attr_bypass = atom_getlong(argv+1);
	else if((argv->a_w.w_sym == ps_video_freeze) || (argv->a_w.w_sym == ps_slash_video_freeze))
		x->attr_freeze = atom_getlong(argv+1);
	
	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()

	outlet_anything(x->algout, osc, argc-1, argv+1);
}


void in_view_internals(t_in *x, t_symbol *msg, short argc, t_atom *argv)
{
	outlet_anything(x->algout, ps_open, 0, 0L);
}


// messages received from jcom.hub for various reasons
void in_dispatched(t_in *x, t_symbol *msg, short argc, t_atom *argv)
{
	;
}


// set pointer to the out object so we can forward messages to it 
void in_link(t_in *x, void *y)
{
	x->out_object = y;
}


void in_unlink(t_in *x)
{
	x->out_object = NULL;
}


// NOTE: only called by the dsp() method at this point in time
void in_send_to_algorithm(t_in *x)
{
	short	i;
	t_atom 	a[MAX_NUM_CHANNELS];
	t_atom	aNumChans;
	t_atom	aMute[2];		// mute channel, mute state

	atom_setlong(&aNumChans, x->sigcount);
	outlet_anything(x->dumpout, ps_sigcount, 1, &aNumChans);

	for(i=0; i < x->num_inputs; i++)
		atom_setlong(&a[i], x->siglist[i]);

	outlet_anything(x->dumpout, ps_siglist, x->num_inputs, &a[0]);
	outlet_anything(x->dumpout, ps_config_changed, 0, NULL);

	// poly~ control
	if(x->attr_algorithm_type == ps_poly && x->attr_manage_channels){
		// set the number of voices in the poly~
		outlet_anything(x->algout, ps_voices, 1, &aNumChans);
		
		// control the muting of the voices
		for(i=0; i < x->num_inputs; i++){
			atom_setlong(&aMute[0], i+1);					// channel num
			atom_setlong(&aMute[1], (x->siglist[i] == 0));	// mute state
			outlet_anything(x->algout, ps_mute, 2, aMute);
		}
		// notify poly~ voices
		outlet_anything(x->algout, ps_target, 1, &ga_zero);
		outlet_anything(x->algout, ps_config_changed, 0, NULL);
	}
}


void in_bang(t_in *x)
{
	if(x->attr_mute)
		;
	else if(x->attr_freeze)
		object_method(x->out_object, ps_sendlastvalue);
	else if(x->attr_bypass)
		object_method(x->out_object, ps_sendbypassedvalue, proxy_getinlet((t_object *)x), _sym_bang, 0, NULL);
	else
		outlet_bang(x->outlet[proxy_getinlet((t_object *)x)]);
}


void in_int(t_in *x, long value)
{
	if(x->attr_mute)
		;
	else if(x->attr_freeze)
		object_method(x->out_object, ps_sendlastvalue);
	else if(x->attr_bypass){
		t_atom a;
		atom_setlong(&a, value);
		object_method(x->out_object, ps_sendbypassedvalue, proxy_getinlet((t_object *)x), _sym_int, 1, &a);
	}
	else
		outlet_int(x->outlet[proxy_getinlet((t_object *)x)], value);
}


void in_float(t_in *x, double value)
{
	if(x->attr_mute)
		;
	else if(x->attr_freeze)
		object_method(x->out_object, ps_sendlastvalue);
	else if(x->attr_bypass){
		t_atom a;
		atom_setfloat(&a, value);
		object_method(x->out_object, ps_sendbypassedvalue, proxy_getinlet((t_object *)x), _sym_float, 1, &a);
	}
	else
		outlet_float(x->outlet[proxy_getinlet((t_object *)x)], value);
}


void in_anything(t_in *x, t_symbol *msg, short argc, t_atom *argv)
{
	if(x->attr_mute)
		;
	else if(x->attr_freeze)
		object_method(x->out_object, ps_sendlastvalue);
	else if(x->attr_bypass)
		object_method(x->out_object, ps_sendbypassedvalue, proxy_getinlet((t_object *)x), msg, argc, argv);
	else
		outlet_anything(x->outlet[proxy_getinlet((t_object *)x)], msg, argc, argv);
}



// Perform Method - just pass the whole vector straight through
// (the work is all done in the dsp method)
t_int *in_perform(t_int *w)
{
  	t_in 	*x 		= (t_in *)(w[1]);		// Instance
	short	i		= (short)(w[2]);		// Channel Number
	t_float *in 	= (t_float *)(w[3]);	// Input
	t_float *out 	= (t_float *)(w[4]);	// Output
	long	n		= (long)(w[5]);			// vectorsize 
	short	j		= 0;

	while(n--){
		x->signal_in[i]->vector[j] = *in;
		*out++ = *in++;
		j++;
	}
	return(w+6);
}


t_int *in_perform_zero(t_int *w)
{
  	t_in 	*x 		= (t_in *)(w[1]);		// Instance
	short	i		= (short)(w[2]);		// Channel Number
  	t_float *out 	= (t_float *)(w[3]);	// Output
	long	n		= (long)(w[4]);			// vectorsize
	short	j		= 0;

	while(n--){
		x->signal_in[i]->vector[j] = 0;	
		*out++ = 0;
		j++;
	}
	return(w+5);
}


// DSP Method
/* Our strategy here is to figure out which signals have connections
 * Knowing which signals have connections, we then count them and
 * send the number of signals to dumpout (which can presumably then be
 * used to make the algorithm or patch do the right thing)
 * 
 * At some point we may want to look for other patterns of things to.
 * For example, what should really happen if it is only inputs 1 and 3 
 * that are connected?
 */
void in_dsp(t_in *x, t_signal **sp, short *count)
{
	short 	i;
	long	connection[MAX_NUM_CHANNELS];
	bool	connection_changed = false;
	int 	vs = sp[0]->s_n;			// Vector Size
//	int		sr = sp[0]->s_sr;			// Sample Rate	

	in_alloc(x, vs);	
	x->sigcount = 0;					// reset

	for(i=0; i < x->num_inputs; i++){	//take a look at each
		connection[i] = count[i];
		if(connection[i] != x->siglist[i])
			connection_changed = true;
		if(count[i]){
			x->sigcount++;
			dsp_add(in_perform, 5, x, i, sp[i]->s_vec, sp[x->num_inputs + i]->s_vec, sp[i]->s_n);
		}
		else
			dsp_add(in_perform_zero, 4, x, i, sp[x->num_inputs + i]->s_vec, sp[i]->s_n);
	}

	if(connection_changed){				// notify the module
		for(i=0; i < x->num_inputs; i++)
			x->siglist[i] = connection[i];
		in_send_to_algorithm(x);
	}	
}


void in_alloc(t_in *x, int vector_size)
{
	short i;
	
	if(vector_size != x->vector_size) {
		x->vector_size = vector_size;
		for(i=0; i < MAX_NUM_CHANNELS; i++) {
			x->signal_in[i]->alloc(vector_size);
		}
	}
}






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.in.xcodeproj/
    project.pbxproj
  jcom.in.cpp
  jcom.in.def
  jcom.in.h
  jcom.in.pch
  jcom.in.sln
  jcom.in.vcproj
  jcom.in~.def
  jcom.in~.pch
  jcom.in~.vcproj