// signal1~ - a flext tutorial external written by Frank Barknecht
// 
// This is a commented port of the pan~ example from the PD-Externals-Howto to
// illustrate the usage of flext. You can get the original code at
// http://iem.kug.ac.at/pd/externals-HOWTO/

#include <flext.h>
 
#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 401)
#error You need at least flext version 0.4.1
#endif


// A flext dsp external ("tilde object") inherits from the class flext_dsp 
class signal1: 
	public flext_dsp
{
	// Each external that is written in C++ needs to use #defines 
	// from flbase.h
	// 
	// The define
	// 
	// FLEXT_HEADER(NEW_CLASS, PARENT_CLASS)
	// 
	// should be somewhere in your dsp file.
	// A good place is here:
	
	FLEXT_HEADER(signal1, flext_dsp)

	public:
		signal1():
			f_pan(0) // initialize f_pan
		{
			// The constructor of your class is responsible for
			// setting up inlets and outlets and for registering
			// inlet-methods:
			// The descriptions of the inlets and outlets are output
			// via the Max/MSP assist method (when mousing over them in edit mode).
			// PD will hopefully provide such a feature as well soon

			AddInSignal("left audio in");       // left audio in
			AddInSignal("right audio in");      // right audio in
			AddInFloat("panning parameter");    // 1 float in
			AddOutSignal("audio out");          // 1 audio out 
			
			// Now we need to bind the handler function to our
			// panning inlet, which is inlet 2 (counting all inlets
			// from 0).  We want the function "setPan" to get
			// called on incoming float messages:

			FLEXT_ADDMETHOD(2,setPan);
			
			// We're done constructing:
			post("-- pan~ with flext ---");
			
		} // end of constructor
		
	
	protected:
		// here we declare the virtual DSP function
		virtual void m_signal(int n, t_sample *const *in, t_sample *const *out);
	private:	
		float f_pan;  // holds our panning factor
		
		// Before we can use "setPan" as a handler, we must register this
		// function as a callback to PD or Max. This is done using the
		// FLEXT_CALLBACK* macros. There are several of them.
		//
		// FLEXT_CALLBACK_F is a shortcut, that registers a function
		// expecting one float arg (thus ending in "_F"). There are
		// other shortcuts that register other types of functions. Look
		// into flext.h. No semicolon at the end of line!!!
		FLEXT_CALLBACK_F(setPan)

		// Now setPan can get declared and defined here.
		void setPan(float f) 
		{ 
			// set our private panning factor "f_pan" to the inlet
			// value float "f" in the intervall [0,1]
			f_pan = (f<0) ? 0.0f : (f>1) ? 1.0f : f ;	
			
			// if you want to debug if this worked, comment out the
			// following line: 
			//post("Set panning to %.2f, maybe clipped from %.2f", f_pan,f);
		} // end setPan
}; // end of class declaration for signal1


// Before we can run our signal1-class in PD, the object has to be registered as a
// PD object. Otherwise it would be a simple C++-class, and what good would
// that be for?  Registering is made easy with the FLEXT_NEW_* macros defined
// in flext.h. For tilde objects without arguments call:

FLEXT_NEW_DSP("signal1~ pan~", signal1)
// T.Grill: there are two names for the object: signal1~ as main name and pan~ as its alias

// Now we define our DSP function. It gets this arguments:
// 
// int n: length of signal vector. Loop over this for your signal processing.
// float *const *in, float *const *out: 
//          These are arrays of the signals in the objects signal inlets rsp.
//          oulets. We come to that later inside the function.

void signal1::m_signal(int n, t_sample *const *in, t_sample *const *out)
{
	
	const t_sample *ins1    =  in[0];
	const t_sample *ins2    =  in[1];
	// As said above "in" holds a list of the signal vectors in all inlets.
	// After these two lines, ins1 holds the signal vector ofthe first
	// inlet, index 0, and ins2 holds the signal vector of the second
	// inlet, with index 1.
	
	t_sample *outs          = out[0];
	// Now outs holds the signal vector at the one signal outlet we have.
	
	// We are now ready for the main signal loop
	while (n--)
	{
		
		// The "++" after the pointers outs, ins1 and ins2 walks us
		// through the signal vector with each n, of course. Before
		// each step we change the signal value in the outlet *outs
		// according to our panning factor "f_pan" and according to the
		// signals at the two signal inlets, *ins1 and *ins2 
		
		*outs++  = (*ins1++) * (1-f_pan) + (*ins2++) * f_pan;
	}
}  // end m_signal
