flext C++ layer for Pure Data & Max/MSP externals Thomas Grill gr@grrrr.org University for Music & Performing Arts, Vienna University of Applied Arts, Vienna Austrian Research Institute for Artificial Intelligence (OFAI)
Pure Data & Max/MSP • Modular real-time frameworks for audio (and video) - Pure Data for Linux, IRIX, MacOS X and Windows - Max/MSP for MacOS and Windows • Functionality extensible by loadable modules (“externals”) • Both systems originally conceived by Miller Puckette ➡ APIs have a lot in common
flext • Library with C++ interface to the Pd or Max API • External objects represented as classes • Wrappers for various other functions • Covers many features of the respective SDK • Cross-platform (Pd & Max, OS independence) • All major compilers supported
Download • http://puredata.info/Members/thomas/flext • https://svn.grrrr.org/ext/trunk/flext/ ➡ Covered by the GPL Support • Pure Data (and Max/MSP) mailing lists • flext mailing list, FAQ
Simple message object – PD #include <m_pd.h> typedef struct { t_object x_obj; t_float x_f1,x_f2; } t_plus; static t_class *plus_class; static void *plus_new(t_floatarg f) { t_plus *x = (t_plus *)pd_new(plus_class); outlet_new(&x->x_obj, &s_float); floatinlet_new(&x->x_obj, &x->x_f2); x->x_f1 = 0; x->x_f2 = f; return (x); } static void plus_bang(t_plus *x) { outlet_float(x->x_obj.ob_outlet, x->x_f1 + x->x_f2); } static void plus_float(t_plus *x, t_float f) { outlet_float(x->x_obj.ob_outlet, (x->x_f1 = f) + x->x_f2); } void plus_setup(void) { plus_class = class_new(gensym("plus"), (t_newmethod)plus_new, 0, sizeof(t_plus), 0, A_DEFFLOAT, 0); class_addbang(plus_class, plus_bang); class_addfloat(plus_class, (t_method)plus_float); } 4
Simple message object – flext #include <flext.h> class plus: public flext_base { FLEXT_HEADER(plus,flext_base) float f1,f2; plus(float f): f1(0),f2(f) // constructor { AddInAnything("Bang or Number"); AddInFloat("Argument"); AddOutFloat("Result"); FLEXT_ADDBANG(0,m_bang); // add methods FLEXT_ADDMETHOD(0,m_float); FLEXT_ADDMETHOD(1,m_arg); } inline void m_bang() { ToOutFloat(0,f1+f2); } inline void m_float(float f) { ToOutFloat(0,(f1 = f)+f2); } inline void m_arg(float f) { f2 = f; } FLEXT_CALLBACK(m_bang) // callback wrappers FLEXT_CALLBACK_F(m_float) FLEXT_CALLBACK_F(m_arg) }; FLEXT_NEW_1("plus",plus,float0) // set up class 5
Pros • Easy to write, easy to read • Hardly any system-dependent code necessary • Use advantages of C++ (polymorphism, templates) • Convenience functions • Extensions (attributes, multi-threading etc.)
Cons • Processing / memory overhead • File size of statically linked binaries • Building problems (additional dependency)
Building parts • Detection of platform and compiler • Two base classes: - flext_base for pure message objects - flext_dsp for DSP objects • Static flext class for general system functionality (atom lists, buffers, timers, threading, etc.)
DSP objects • Virtual methods for DSP processing class gain: public flext_dsp { FLEXT_HEADER(gain,flext_dsp) float factor; gain(): factor(0) { AddInSignal("In"); // add signal inlet AddInFloat("Gain"); AddOutSignal("Out"); // add signal outlet FLEXT_ADDMETHOD(1,m_gain); } virtual void m_signal(int n,t_sample *const *insigs,t_sample *const *outsigs) { const t_sample *in = insigs[0]; t_sample *out = outsigs[0]; while(n--) *(out++) = *(in++)*factor; // or: MulSamples(out,in,factor,n); } void m_gain(float db) { factor = pow(10.f,db*0.05f); } FLEXT_CALLBACK_F(m_gain); }; FLEXT_NEW_DSP("gain~",gain) // set up DSP class 9
Timers • Timer class using class methods or callback functions • Additional high-precision clock functions class bangs: public flext_base { FLEXT_HEADER(bangs,flext_base) Timer timer; bangs() { AddInAnything("In"); AddOutBang("Out"); FLEXT_ADDMETHOD(0,m_interval); FLEXT_ADDTIMER(timer,m_bang); } inline void m_interval(float intv) { timer.Periodic(intv*0.001); } inline void m_bang(void *) { ToOutBang(0); } FLEXT_CALLBACK_F(m_interval); FLEXT_CALLBACK_T(m_bang); // timer callback }; FLEXT_NEW("bangs",bangs) // set up class 11
Attributes • Consistent way to initialize, set and query state • Originally conceived by J.K.Clayton for Max/Jitter class plus: public flext_base { FLEXT_HEADER(plus,flext_base) float f1,f2; plus(float f): f1(0),f2(f) { AddInAnything("Bang or Number"); AddInFloat("Argument"); AddOutFloat("Result"); FLEXT_ADDBANG(0,m_bang); FLEXT_ADDMETHOD(0,m_float); FLEXT_ADDMETHOD(1,m_arg); FLEXT_ADDATTR_VAR1( "arg" ,f2); // add attribute } FLEXT_ATTRVAR_F(f2) // wrapper for attribute variable // … more methods and wrappers }; FLEXT_NEW_1("plus",plus,float0) // set up class 8
Threading • Transparent threading in real-time environment • Threads are running at lower priority • Several threading models supported (pthreads as default) class writer: public flext_base { FLEXT_HEADER(writer,flext_base) writer() { AddInAnything("Bang to start"); AddOutBang("Bang on finish"); FLEXT_ADDMETHOD_I(0,"start",m_start); // register method } void m_start(int loops) { // slowly write some megabytes to disk std::ofstream file("/temp/bigfile.txt"); for(int i = 0; i < loops; ++i) file << i << ' '; file << std::endl; ToOutBang(0); // indicate end of work } FLEXT_THREAD_I(m_start) // special wrapper }; FLEXT_NEW("writer",writer) 10
More features • Binding to symbols (named senders & receivers) • Libraries of externals • Interface classes to SndObj and STK frameworks • Integrated make system for externals
Status • Maintenance difficulties: - Many newer Max/MSP features not supported - Data structures for Pd not supported - Integration into Pd autobuild pending • C++ language update • Documentation update...
Published applications • soundspotter (Michael Casey et al.) • munger1~ (Ico Bukvic et al.) • fluid~ (Frank Barknecht) • msd (Nicolas Montgermont) • xsample, py/pyext, pool, dyn~, vasp, etc.
More recommend