diff options
author | Thomas Grill <xovo@users.sourceforge.net> | 2002-10-22 23:07:10 +0000 |
---|---|---|
committer | Thomas Grill <xovo@users.sourceforge.net> | 2002-10-22 23:07:10 +0000 |
commit | d62e56f4df9594f72ce501f5e19c974fd18e7295 (patch) | |
tree | 635d4af7a7c2425098e60ca277086ec436b617f7 /externals/grill/flext/source | |
parent | c6f373c281ecb5cd1f4aa7a070e15cc61ab8793c (diff) |
This commit was generated by cvs2svn to compensate for changes in r186,
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/; revision=187
Diffstat (limited to 'externals/grill/flext/source')
26 files changed, 5782 insertions, 0 deletions
diff --git a/externals/grill/flext/source/flatom.cpp b/externals/grill/flext/source/flatom.cpp new file mode 100644 index 00000000..705fc9e6 --- /dev/null +++ b/externals/grill/flext/source/flatom.cpp @@ -0,0 +1,139 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flatom.cpp + \brief Definitions for handling the t_atom type and lists thereof. +*/ + +#include "flext.h" + +//namespace flext { + +flext::AtomList::AtomList(int argc,const t_atom *argv): + lst(NULL),cnt(0) +{ + operator()(argc,argv); +} + +flext::AtomList::AtomList(const AtomList &a): + lst(NULL),cnt(0) +{ + operator =(a); +} + +flext::AtomList::~AtomList() { Clear(); } + +flext::AtomList &flext::AtomList::operator()(int argc,const t_atom *argv) +{ + if(lst && cnt != argc) { delete[] lst; lst = NULL; cnt = 0; } + + if(argc) { + cnt = argc; + lst = new t_atom[cnt]; + + if(argv) { + for(int i = 0; i < argc; ++i) SetAtom(lst[i],argv[i]); +/* + { + switch(lst[i].a_type = argv[i].a_type) { + case A_FLOAT: + lst[i].a_w.w_float = argv[i].a_w.w_float; + break; +#ifdef MAXMSP + case A_LONG: + lst[i].a_w.w_int = argv[i].a_w.w_int; + break; +#endif + case A_SYMBOL: + lst[i].a_w.w_symbol = argv[i].a_w.w_symbol; + break; +#ifdef PD + case A_POINTER: + lst[i].a_w.w_gpointer = argv[i].a_w.w_gpointer; + break; +#endif + default: + post("AtomList - atom type (%i) not supported",lst[i].a_type); + lst[i].a_type = A_NULL; + break; + } + } +*/ + } + } + return *this; +} + + +flext::AtomList &flext::AtomList::Append(const t_atom &a) +{ + t_atom *nlst = new t_atom[cnt+1]; + for(int i = 0; i < cnt; ++i) SetAtom(nlst[i],lst[i]); + SetAtom(nlst[cnt],a); + + if(lst) delete[] lst; + lst = nlst; + ++cnt; + + return *this; +} + +flext::AtomList &flext::AtomList::Append(int argc,const t_atom *argv) +{ + t_atom *nlst = new t_atom[cnt+argc]; + int i; + for(i = 0; i < cnt; ++i) SetAtom(nlst[i],lst[i]); + for(i = 0; i < argc; ++i) SetAtom(nlst[cnt+i],argv[i]); + + if(lst) delete[] lst; + lst = nlst; + cnt += argc; + + return *this; +} + +flext::AtomList &flext::AtomList::Prepend(const t_atom &a) +{ + t_atom *nlst = new t_atom[cnt+1]; + for(int i = 0; i < cnt; ++i) SetAtom(nlst[i+1],lst[i]); + SetAtom(nlst[0],a); + + if(lst) delete[] lst; + lst = nlst; + ++cnt; + + return *this; +} + +flext::AtomList &flext::AtomList::Prepend(int argc,const t_atom *argv) +{ + t_atom *nlst = new t_atom[cnt+argc]; + int i; + for(i = 0; i < argc; ++i) SetAtom(nlst[i],argv[i]); + for(i = 0; i < cnt; ++i) SetAtom(nlst[argc+i],lst[i]); + + if(lst) delete[] lst; + lst = nlst; + cnt += argc; + + return *this; +} + +flext::AtomList flext::AtomList::GetPart(int offs,int len) const +{ + if(offs+len > Count()) { + len = Count()-offs; + if(len < 0) len = 0; + } + + return AtomList(len,Atoms()+offs); +} + +//} // namespace flext diff --git a/externals/grill/flext/source/flattr.cpp b/externals/grill/flext/source/flattr.cpp new file mode 100644 index 00000000..20b06e41 --- /dev/null +++ b/externals/grill/flext/source/flattr.cpp @@ -0,0 +1,190 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flattr.cpp + \brief Attribute handling for the flext base class +*/ + +#include "flext.h" +#include <string.h> +#include <stdio.h> + +flext_base::attritem::attritem(const t_symbol *t,const t_symbol *gt,metharg tp,methfun gf,methfun sf): + tag(t),gtag(gt),argtp(tp),gfun(gf),sfun(sf),nxt(NULL) +{} + +flext_base::attritem::~attritem() +{ + if(nxt) delete nxt; +} + +void flext_base::AddAttrItem(attritem *m) +{ + if(attrhead) { + attritem *mi; + for(mi = attrhead; mi->nxt; mi = mi->nxt) {} + mi->nxt = m; + } + else + attrhead = m; + attrcnt++; +} + +void flext_base::AddAttrib(const char *attr,metharg tp,methfun gfun,methfun sfun) +{ + if(procattr) { + char tmp[1024]; + sprintf(tmp,"get%s",attr); + AddAttrItem(new attritem(MakeSymbol(attr),MakeSymbol(tmp),tp,gfun,sfun)); + + AddMethod(0,attr,(methfun)cb_SetAttrib,a_any,a_null); + AddMethod(0,tmp,(methfun)cb_GetAttrib,a_any,a_null); + } + else + error("%s - attribute procession is not enabled!",thisName()); +} + +int flext_base::CheckAttrib(int argc,const t_atom *argv) +{ + int offs = 0; + for(; offs < argc; ++offs) + if(IsString(argv[offs]) && *GetString(argv[offs]) == '@') break; + return offs; +} + +bool flext_base::InitAttrib(int argc,const t_atom *argv) +{ + int cur,nxt; + for(cur = 0; cur < argc; cur = nxt) { + // find next @symbol + for(nxt = cur+1; nxt < argc; ++nxt) + if(IsString(argv[nxt]) && *GetString(argv[nxt]) == '@') break; + + const t_symbol *tag = MakeSymbol(GetString(argv[cur])+1); + SetAttrib(tag,nxt-cur-1,argv+cur+1); + } + return true; +} + +bool flext_base::ListAttrib() +{ + if(outattr) { + AtomList la(attrcnt); + attritem *a = attrhead; + for(int i = 0; i < attrcnt; ++i,a = a->nxt) SetSymbol(la[i],a->tag); + + ToOutAnything(outattr,thisTag(),la.Count(),la.Atoms()); + return true; + } + else + return false; +} + +bool flext_base::SetAttrib(const t_symbol *tag,int argc,const t_atom *argv) +{ + attritem *a = attrhead; + for(; a && a->tag != tag; a = a->nxt) {} + + if(a) { + if(a->sfun) { + bool ok = true; + + AtomList la; + t_any any; + switch(a->argtp) { + case a_float: + if(argc == 1 && CanbeFloat(argv[0])) { + any.ft = GetAFloat(argv[0]); + ((methfun_1)a->sfun)(this,any); + } + else ok = false; + break; + case a_int: + if(argc == 1 && CanbeInt(argv[0])) { + any.it = GetAInt(argv[0]); + ((methfun_1)a->sfun)(this,any); + } + else ok = false; + break; + case a_symbol: + if(argc == 1 && IsSymbol(argv[0])) { + any.st = GetSymbol(argv[0]); + ((methfun_1)a->sfun)(this,any); + } + else ok = false; + break; + case a_LIST: + any.vt = &(la(argc,argv)); + ((methfun_1)a->sfun)(this,any); + break; + default: + ERRINTERNAL(); + } + + if(!ok) + post("%s - wrong arguments for attribute %s",thisName(),GetString(tag)); + } + else + post("%s - attribute %s has no get method",thisName(),GetString(tag)); + } + else + error("%s - %s: attribute not found",thisName(),tag); + return true; +} + +bool flext_base::GetAttrib(const t_symbol *tag,int argc,const t_atom *argv) +{ + if(argc) + post("%s - %s: arguments ignored",thisName(),GetString(tag)); + + attritem *a = attrhead; + for(; a && a->gtag != tag; a = a->nxt) {} + + if(a) { + if(a->gfun) { + AtomList la; + t_any any; + switch(a->argtp) { + case a_float: { + ((methfun_1)a->gfun)(this,any); + la(1); + SetFloat(la[0],any.ft); + break; + } + case a_int: { + ((methfun_1)a->gfun)(this,any); + la(1); + SetInt(la[0],any.it); + break; + } + case a_symbol: { + ((methfun_1)a->gfun)(this,any); + la(1); + SetSymbol(la[0],any.st); + break; + } + case a_LIST: { + any.vt = &la; + ((methfun_1)a->gfun)(this,any); + break; + } + default: + ERRINTERNAL(); + } + ToOutAnything(outattr,a->tag,la.Count(),la.Atoms()); + } + else + post("%s - attribute %s has no set method",thisName(),GetString(tag)); + } + else + error("%s - %s: attribute not found",thisName(),tag); + return true; +} + diff --git a/externals/grill/flext/source/flbase.cpp b/externals/grill/flext/source/flbase.cpp new file mode 100644 index 00000000..97fed291 --- /dev/null +++ b/externals/grill/flext/source/flbase.cpp @@ -0,0 +1,118 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flbase.cpp + \brief Implementation of the internal flext base classes. + + \remark This is all derived from GEM by Mark Danks +*/ + +#include "flbase.h" +#include "flinternal.h" +#include <string.h> + +///////////////////////////////////////////////////////// +// +// flext_obj +// +///////////////////////////////////////////////////////// + +flext_hdr *flext_obj::m_holder = NULL; +const t_symbol *flext_obj::m_holdname = NULL; +bool flext_obj::m_holdattr = false; +bool flext_obj::process_attributes = false; + +///////////////////////////////////////////////////////// +// Constructor +// +///////////////////////////////////////////////////////// +flext_obj :: flext_obj() + : x_obj(m_holder) + , m_name(m_holdname) + , procattr(m_holdattr) + , init_ok(true) +{ +#ifdef PD + m_canvas = canvas_getcurrent(); +#elif defined(MAXMSP) + m_canvas = (t_patcher *)gensym("#P")->s_thing; + x_obj->curinlet = 0; +#endif +} + +///////////////////////////////////////////////////////// +// Destructor +// +///////////////////////////////////////////////////////// +flext_obj :: ~flext_obj() {} + + +void flext_obj::DefineHelp(t_class *c,const char *ref,const char *dir,bool addtilde) +{ +#ifdef PD + char tmp[256]; + if(dir) { + strcpy(tmp,dir); + strcat(tmp,"/"); + strcat(tmp,ref); + if(addtilde) strcat(tmp,"~"); + } + else + strcpy(tmp,ref); + ::class_sethelpsymbol(c,gensym(const_cast<char *>(tmp))); +#else + // no solution for MaxMSP yet +#endif +} + + +///////////////////////////////////////////////////////// +// overloaded new/delete memory allocation methods +// +///////////////////////////////////////////////////////// + +void *flext_obj::operator new(size_t bytes) +{ + bytes += sizeof(size_t); + char *blk = (char *)getbytes(bytes); + *(size_t *)blk = bytes; + return blk+sizeof(size_t); +} + +void flext_obj::operator delete(void *blk) +{ + char *ori = (char *)blk-sizeof(size_t); + size_t bytes = *(size_t *)ori; + freebytes(ori,bytes); +} + +void *flext_obj::NewAligned(size_t bytes,int bitalign) +{ + const size_t ovh = sizeof(size_t)+sizeof(char *); + const unsigned long alignovh = bitalign/8-1; + bytes += ovh+alignovh; + char *blk = (char *)getbytes(bytes); + char *ablk = reinterpret_cast<char *>((reinterpret_cast<unsigned long>(blk)+ovh+alignovh) & ~alignovh); + *(char **)(ablk-sizeof(size_t)-sizeof(char *)) = blk; + *(size_t *)(ablk-sizeof(size_t)) = bytes; + return ablk; +} + +void flext_obj::FreeAligned(void *blk) +{ + char *ori = *(char **)((char *)blk-sizeof(size_t)-sizeof(char *)); + size_t bytes = *(size_t *)((char *)blk-sizeof(size_t)); + freebytes(ori,bytes); +} + + + + + diff --git a/externals/grill/flext/source/flbase.h b/externals/grill/flext/source/flbase.h new file mode 100644 index 00000000..f3f8b647 --- /dev/null +++ b/externals/grill/flext/source/flbase.h @@ -0,0 +1,426 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flbase.h + \brief Internal flext base classes + + \remark This is all derived from GEM by Mark Danks +*/ + +#ifndef __FLEXT_BASE_H +#define __FLEXT_BASE_H + +#include "flstdc.h" +#include "flsupport.h" + +#ifdef FLEXT_THREADS +#include <pthread.h> +#endif + +class flext_obj; + +// ---------------------------------------------------------------------------- +/*! \struct flext_hdr + \brief The obligatory PD or Max/MSP object header + \internal + + This is in a separate struct to assure that obj is the very first thing. + If it were the first thing in flext_obj, then there could be problems with + the virtual table of the C++ class. +*/ +// ---------------------------------------------------------------------------- + +struct FLEXT_EXT flext_hdr +{ + /*! \brief The obligatory object header + MUST reside at memory offset 0 (no virtual table possible) + */ + t_sigobj obj; + +#ifdef PD + //! PD only: float signal holder for pd + float defsig; +#endif + +#if defined(MAXMSP) + //! MaxMSP only: current inlet used by proxy objects + long curinlet; +#endif + + /*! \brief This points to flext object class + This points to the actual polymorphic C++ class + */ + flext_obj *data; +}; + + +// ---------------------------------------------------------------------------- +/*! \class flext_obj + \brief The mother of base classes for all flext externs + \internal + + Each extern which is written in C++ needs to use the #defines at the + end of this header file. + + The define + + FLEXT_HEADER(NEW_CLASS, PARENT_CLASS) + + should be somewhere in your header file. + One of the defines like + + FLEXT_NEW(NEW_CLASS) + FLEXT_NEW_2(NEW_CLASS, float, float) + + should be the first thing in your implementation file. + NEW_CLASS is the name of your class and PARENT_CLASS is the + parent of your class. +*/ +// ---------------------------------------------------------------------------- + +class FLEXT_EXT flext_obj: + public flext +{ + public: + + // --- overloading of new/delete memory allocation methods ---- + // MaxMSP allows only 16K in overdrive mode! + + void *operator new(size_t bytes); + void operator delete(void *blk); + + #ifndef __MRC__ // doesn't allow new[] overloading?! + void *operator new[](size_t bytes) { return operator new(bytes); } + void operator delete[](void *blk) { operator delete(blk); } + #endif + + // these are aligned + static void *NewAligned(size_t bytes,int bitalign = 128); + static void FreeAligned(void *blk); + + // --------------------- + + //! Constructor + flext_obj(); + + //! Destructor + virtual ~flext_obj() = 0; + + //! Get the object's canvas + t_canvas *thisCanvas() { return(m_canvas); } + + t_sigobj *thisHdr() { return &x_obj->obj; } + const t_sigobj *thisHdr() const { return &x_obj->obj; } + const char *thisName() const { return GetString(m_name); } + const t_symbol *thisNameSym() const { return m_name; } + +#ifdef PD + t_class *thisClass() { return (t_class *)((t_object *)(x_obj))->te_g.g_pd; } +#elif defined(MAXMSP) + t_class *thisClass() { return (t_class *)(((t_tinyobject *)x_obj)->t_messlist-1); } +#endif + + void InitProblem() { init_ok = false; } + + static void ProcessAttributes(bool attr) { process_attributes = attr; } + + // this also guarantees that there are no instances of flext_obj + virtual bool Init() = 0; + virtual void Exit() {} + +// --- help ------------------------------------------------------- + + /*! \defgroup FLEXT_C_HELP Flext help/assistance functionality + + @{ + */ + + static void DefineHelp(t_class *c,const char *ref,const char *dir = NULL,bool addtilde = false); + void DefineHelp(const char *ref,const char *dir = NULL,bool addtilde = false) { DefineHelp(thisClass(),ref,dir,addtilde); } + + //! @} + + + protected: + + //! The object header + flext_hdr *x_obj; + + //! Flag for attribute procession + bool procattr; + + static bool process_attributes; + + private: + + //! The canvas (patcher) that the object is in + t_canvas *m_canvas; + + //! Flag for successful object construction + bool init_ok; + + public: + + //! Creation callback + static void __setup__(t_class *) { flext::Setup(); } + + /*! \brief This is a temporary holder + \warning don't touch it! + */ + static flext_hdr *m_holder; + //! Hold object's name during construction + static const t_symbol *m_holdname; + + static bool m_holdattr; + + //! The object's name in the patcher + const t_symbol *m_name; + + //! Check whether construction was successful + bool InitOk() const { return init_ok; } + + //@{ + //! Definitions for library objects + + static void lib_init(const char *name,void setupfun(),bool attr); + static void obj_add(bool lib,bool dsp,bool attr,const char *idname,const char *names,void setupfun(t_class *),flext_obj *(*newfun)(int,t_atom *),void (*freefun)(flext_hdr *),int argtp1,...); + static flext_hdr *obj_new(const t_symbol *s,int argc,t_atom *argv); + static void obj_free(flext_hdr *o); + //@} +}; + + +// max. 4 creation args (see the following macros) +#define FLEXT_MAXNEWARGS 4 + +// max. 5 method args (see the following macros) +#define FLEXT_MAXMETHARGS 5 + +// prefixes for the macro generated handler functions +#define FLEXT_CALL_PRE(F) flext_c_##F +#define FLEXT_THR_PRE(F) flext_t_##F +#define FLEXT_GET_PRE(F) flext_g_##F +#define FLEXT_SET_PRE(F) flext_s_##F + + +#ifndef FLEXT_ATTRIBUTES +#define FLEXT_ATTRIBUTES 0 +#endif + +// ---------------------------------------- +// These should be used in the header +// ---------------------------------------- + + +#define FLEXT_REALHDR(NEW_CLASS, PARENT_CLASS) \ +public: \ +typedef NEW_CLASS thisType; \ +static flext_obj *__init__(int argc,t_atom *argv); \ +static void __free__(flext_hdr *hdr) \ +{ flext_obj *mydata = hdr->data; delete mydata; \ + hdr->flext_hdr::~flext_hdr(); } \ +static void __setup__(t_class *classPtr) { \ + PARENT_CLASS::__setup__(classPtr); } \ +protected: \ +static inline NEW_CLASS *thisObject(void *c) { return FLEXT_CAST<NEW_CLASS *>(((flext_hdr *)c)->data); } + + +#define FLEXT_REALHDR_S(NEW_CLASS, PARENT_CLASS,SETUPFUN) \ +public: \ +typedef NEW_CLASS thisType; \ +static flext_obj *__init__(int argc,t_atom *argv); \ +static void __free__(flext_hdr *hdr) \ +{ flext_obj *mydata = hdr->data; delete mydata; \ + hdr->flext_hdr::~flext_hdr(); } \ +static void __setup__(t_class *classPtr) \ +{ PARENT_CLASS::__setup__(classPtr); \ + NEW_CLASS::SETUPFUN(classPtr); } \ +protected: \ +static inline NEW_CLASS *thisObject(void *c) { return FLEXT_CAST<NEW_CLASS *>(((flext_hdr *)c)->data); } + + +// generate name of dsp/non-dsp setup function +#define FLEXT_STPF_0(NAME) NAME##_setup +#define FLEXT_STPF_1(NAME) NAME##_tilde_setup +#define FLEXT_STPF_(DSP) FLEXT_STPF_##DSP +#define FLEXT_STPF(NAME,DSP) FLEXT_STPF_(DSP)(NAME) + + + +// -------------------------------------------------------------------------------------- + + + +// these can be used in library setup functions +// to register the individual objects in the library + +#define FLEXT_SETUP(cl) \ +extern void cl##_setup(); \ +cl##_setup() + +#define FLEXT_DSP_SETUP(cl) \ +extern void cl##_tilde_setup(); \ +cl##_tilde_setup() + +// deprecated +#define FLEXT_TILDE_SETUP FLEXT_DSP_SETUP + + +// specify that to define the library itself + +#ifdef PD +#define FLEXT_LIB_SETUP(NAME,SETUPFUN) extern "C" FLEXT_EXT void NAME##_setup() { flext_obj::lib_init(#NAME,SETUPFUN,FLEXT_ATTRIBUTES); } +#else // MAXMSP +#define FLEXT_LIB_SETUP(NAME,SETUPFUN) extern "C" FLEXT_EXT int main() { flext_obj::lib_init(#NAME,SETUPFUN,FLEXT_ATTRIBUTES); return 0; } +#endif + + +// -------------------------------------------------- + + +#define FLEXT_EXP_0 extern "C" FLEXT_EXT +#define FLEXT_EXP_1 +#define FLEXT_EXP(LIB) FLEXT_EXP_##LIB + +#ifdef PD +#define FLEXT_OBJ_SETUP_0(NEW_CLASS,DSP) +#else // MAXMSP +#define FLEXT_OBJ_SETUP_0(NEW_CLASS,DSP) extern "C" FLEXT_EXT int main() { FLEXT_STPF(NEW_CLASS,DSP)(); return 0; } +#endif +#define FLEXT_OBJ_SETUP_1(NEW_CLASS,DSP) + +#define FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) FLEXT_OBJ_SETUP_##LIB(NEW_CLASS,DSP) + + + +// ---------------------------------------- +// These definitions are used below +// ---------------------------------------- + +// Shortcuts for PD/Max type arguments +#define FLEXTTYPE_void A_NULL +#define CALLBTYPE_void void +#define FLEXTTYPE_float A_FLOAT +#define CALLBTYPE_float float +#define FLEXTTYPE_t_float A_FLOAT +#define CALLBTYPE_t_float t_float + +//* #define FLEXTTYPE_t_flint A_FLINT + +#ifdef PD +#define FLEXTTYPE_int A_FLOAT +#define CALLBTYPE_int float +#else +#define FLEXTTYPE_int A_INT +#define CALLBTYPE_int int +#endif + +#define FLEXTTYPE_t_symptr A_SYMBOL +#define CALLBTYPE_t_symptr t_symptr +#define FLEXTTYPE_t_symtype A_SYMBOL +#define CALLBTYPE_t_symtype t_symptr +#define FLEXTTYPE_t_ptrtype A_POINTER +#define CALLBTYPE_t_ptrtype t_ptrtype + +#define FLEXTTP(TP) FLEXTTYPE_ ## TP +#define CALLBTP(TP) CALLBTYPE_ ## TP + + +#define ARGMEMBER_int(a) GetInt(a) +#define ARGMEMBER_float(a) GetFloat(a) +#define ARGMEMBER_t_symptr(a) GetSymbol(a) +#define ARGMEMBER_t_symtype(a) GetSymbol(a) +#define ARGCAST(arg,tp) ARGMEMBER_##tp(arg) + + +#define REAL_NEW(NAME,NEW_CLASS,DSP,LIB) \ +FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) \ +flext_obj *NEW_CLASS::__init__(int argc,t_atom *argv) \ +{ \ + return new NEW_CLASS; \ +} \ +FLEXT_EXP(LIB) void FLEXT_STPF(NEW_CLASS,DSP)() \ +{ \ + flext_obj::obj_add(LIB,DSP,FLEXT_ATTRIBUTES,#NEW_CLASS,NAME,NEW_CLASS::__setup__,NEW_CLASS::__init__,&NEW_CLASS::__free__,A_NULL); \ +} + +#define REAL_NEW_V(NAME,NEW_CLASS,DSP,LIB) \ +FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) \ +flext_obj *NEW_CLASS::__init__(int argc,t_atom *argv) \ +{ \ + return new NEW_CLASS(argc,argv); \ +} \ +FLEXT_EXP(LIB) void FLEXT_STPF(NEW_CLASS,DSP)() \ +{ \ + flext_obj::obj_add(LIB,DSP,FLEXT_ATTRIBUTES,#NEW_CLASS,NAME,NEW_CLASS::__setup__,NEW_CLASS::__init__,&NEW_CLASS::__free__,A_GIMME,A_NULL); \ +} + +#define REAL_NEW_1(NAME,NEW_CLASS,DSP,LIB, TYPE1) \ +FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) \ +flext_obj *NEW_CLASS::__init__(int argc,t_atom *argv) \ +{ \ + return new NEW_CLASS(ARGCAST(argv[0],TYPE1)); \ +} \ +FLEXT_EXP(LIB) void FLEXT_STPF(NEW_CLASS,DSP)() \ +{ \ + flext_obj::obj_add(LIB,DSP,FLEXT_ATTRIBUTES,#NEW_CLASS,NAME,NEW_CLASS::__setup__,NEW_CLASS::__init__,NEW_CLASS::__free__,FLEXTTP(TYPE1),A_NULL); \ +} + +#define REAL_NEW_2(NAME,NEW_CLASS,DSP,LIB, TYPE1,TYPE2) \ +FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) \ +flext_obj *NEW_CLASS::__init__(int argc,t_atom *argv) \ +{ \ + return new NEW_CLASS(ARGCAST(argv[0],TYPE1),ARGCAST(argv[1],TYPE2)); \ +} \ +FLEXT_EXP(LIB) void FLEXT_STPF(NEW_CLASS,DSP)() \ +{ \ + flext_obj::obj_add(LIB,DSP,FLEXT_ATTRIBUTES,#NEW_CLASS,NAME,NEW_CLASS::__setup__,NEW_CLASS::__init__,NEW_CLASS::__free__,FLEXTTP(TYPE1),FLEXTTP(TYPE2),A_NULL); \ +} + +#define REAL_NEW_3(NAME,NEW_CLASS,DSP,LIB, TYPE1, TYPE2, TYPE3) \ +FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) \ +flext_obj *NEW_CLASS::__init__(int argc,t_atom *argv) \ +{ \ + return new NEW_CLASS(ARGCAST(argv[0],TYPE1),ARGCAST(argv[1],TYPE2),ARGCAST(argv[2],TYPE3)); \ +} \ +FLEXT_EXP(LIB) void FLEXT_STPF(NEW_CLASS,DSP)() \ +{ \ + flext_obj::obj_add(LIB,DSP,FLEXT_ATTRIBUTES,#NEW_CLASS,NAME,NEW_CLASS::__setup__,NEW_CLASS::__init__,NEW_CLASS::__free__,FLEXTTP(TYPE1),FLEXTTP(TYPE2),FLEXTTP(TYPE3),A_NULL); \ +} + +#define REAL_NEW_4(NAME,NEW_CLASS,DSP,LIB, TYPE1,TYPE2, TYPE3, TYPE4) \ +FLEXT_OBJ_SETUP(NEW_CLASS,DSP,LIB) \ +flext_obj *NEW_CLASS::__init__(int argc,t_atom *argv) \ +{ \ + return new NEW_CLASS(ARGCAST(argv[0],TYPE1),ARGCAST(argv[1],TYPE2),ARGCAST(argv[2],TYPE3),ARGCAST(argv[3],TYPE4)); \ +} \ +FLEXT_EXP(LIB) void FLEXT_STPF(NEW_CLASS,DSP)() \ +{ \ + flext_obj::obj_add(LIB,DSP,FLEXT_ATTRIBUTES,#NEW_CLASS,NAME,NEW_CLASS::__setup__,NEW_CLASS::__init__,NEW_CLASS::__free__,FLEXTTP(TYPE1),FLEXTTP(TYPE2),FLEXTTP(TYPE3),FLEXTTP(TYPE4),A_NULL); \ +} + + +// Shortcuts for method arguments: +#define FLEXTARG_float a_float +#define FLEXTARG_int a_int +#define FLEXTARG_bool a_int +#define FLEXTARG_t_float a_float +#define FLEXTARG_t_symtype a_symbol +#define FLEXTARG_t_symptr a_symbol +#define FLEXTARG_t_ptrtype a_pointer + +#define FLEXTARG(TP) FLEXTARG_ ## TP + + +#endif + + + + diff --git a/externals/grill/flext/source/flbuf.cpp b/externals/grill/flext/source/flbuf.cpp new file mode 100644 index 00000000..dc5704c0 --- /dev/null +++ b/externals/grill/flext/source/flbuf.cpp @@ -0,0 +1,255 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flbuf.cpp + \brief Implementation of the buffer abstraction class. +*/ + +#include "flext.h" + +#ifdef MAXMSP +#include "flmspbuffer.h" // include inofficial buffer.h +#endif + +#ifdef PD +#define DIRTY_INTERVAL 0 // buffer dirty check in msec +#endif + + + +flext::buffer::buffer(const t_symbol *bn,bool delayed): + sym(NULL),data(NULL), + chns(0),frames(0) +{ +#ifdef PD + arr = NULL; + interval = DIRTY_INTERVAL; + isdirty = false; + ticking = false; + tick = clock_new(this,(t_method)cb_tick); +#endif + + if(bn) Set(bn,delayed); +} + +flext::buffer::~buffer() +{ +#ifdef PD + clock_free(tick); +#endif +} + +int flext::buffer::Set(const t_symbol *s,bool nameonly) +{ + int ret = 0; + bool valid = data != NULL; // valid now? (before change) + + if(s && sym != s) { + ret = -1; + data = NULL; + frames = 0; + chns = 0; + } + + if(s && *s->s_name) sym = s; + + if(!sym) { + if(valid) ret = -1; + } + else if(!nameonly) { +#ifdef PD + int frames1; + t_sample *data1; + + arr = (t_garray *)pd_findbyclass(const_cast<t_symbol *>(sym), garray_class); + if(!arr) + { + if (*sym->s_name) error("buffer: no such array '%s'",sym->s_name); + sym = NULL; + if(valid) ret = -1; + } + else if(!garray_getfloatarray(arr, &frames1, &data1)) + { + error("buffer: bad template '%s'", sym->s_name); + data = NULL; + frames = 0; + if(valid) ret = -1; + } + else { + garray_usedindsp(arr); + if(frames != frames1) { frames = frames1; if(!ret) ret = 1; } + if(data != data1) { data = data1; if(!ret) ret = 1; } + chns = 1; + } +#elif defined(MAXMSP) + if(sym->s_thing) { + const _buffer *p = (const _buffer *)sym->s_thing; + + if(NOGOOD(p)) { + post("buffer: buffer object '%s' no good",sym->s_name); + if(valid) ret = -1; + } + else { +#ifdef DEBUG + post("%s: buffer object '%s' - valid:%i samples:%i channels:%i frames:%i",thisName(),bufname->s_name,p->b_valid,p->b_frames,p->b_nchans,p->b_frames); +#endif + if(data != p->b_samples) { data = p->b_samples; if(!ret) ret = 1; } + if(chns != p->b_nchans) { chns = p->b_nchans; if(!ret) ret = 1; } + if(frames != p->b_frames) { frames = p->b_frames; if(!ret) ret = 1; } + } + } + else { + error("buffer: symbol '%s' not defined", sym->s_name); + if(valid) ret = -1; + } +#endif + } + + return ret; +} + +bool flext::buffer::Update() +{ + if(!Ok()) return false; + +#ifdef PD + int frames1; + t_sample *data1; + if(!garray_getfloatarray(arr, &frames1, &data1)) { + frames = 0; + data = NULL; + chns = 0; + return true; + } + else if(data != data1 || frames != frames1) { + frames = frames1; + data = data1; + return true; + } + else + return false; +#else // MAXMSP + if(!sym->s_thing) + return false; + else { + const _buffer *p = (const _buffer *)sym->s_thing; + if(data != p->b_samples || chns != p->b_nchans || frames != p->b_frames) { + data = p->b_samples; + chns = p->b_nchans; + frames = p->b_frames; + return true; + } + else + return false; + } +#endif +} + +void flext::buffer::Frames(int fr,bool keep) +{ +#ifdef PD + ::garray_resize(arr,(float)fr); + Update(); +#else + t_sample *tmp = NULL; + int sz = frames; + if(fr < sz) sz = fr; + + if(keep) { + // copy buffer data to tmp storage + tmp = new t_sample[sz]; + if(tmp) + BlockMoveData(data,tmp,sizeof(t_sample)*sz); + else + error("flext::buffer - not enough memory for keeping buffer~ contents"); + } + + t_atom msg; + _buffer *buf = (_buffer *)sym->s_thing; + // b_msr reflects buffer sample rate... is this what we want? + // Max bug: adding small value 0.001 to get right sample count + float ms = fr/buf->b_msr+0.001; + + SetFloat(msg,ms); + ::typedmess((object *)buf,gensym("size"),1,&msg); + + Update(); + + if(tmp) { + // copy data back + BlockMoveData(tmp,data,sizeof(t_sample)*sz); + delete[] tmp; + } +#endif +} + + +#ifdef PD +void flext::buffer::SetRefrIntv(float intv) +{ + interval = intv; + if(interval == 0 && ticking) { + clock_unset(tick); + ticking = false; + } +} +#else +void flext::buffer::SetRefrIntv(float) {} +#endif + + +void flext::buffer::Dirty(bool force) +{ + if(sym) { +#ifdef PD + if((!ticking) && (interval || force)) { + ticking = true; + cb_tick(this); // immediately redraw + } + else { + if(force) clock_delay(tick,0); + isdirty = true; + } +#elif defined(MAXMSP) + if(sym->s_thing) { + _buffer *p = (_buffer *)sym->s_thing; + + if(NOGOOD(p)) { + post("buffer: buffer object '%s' no good",sym->s_name); + } + else { + p->b_modtime = gettime(); + } + } + else { + error("buffer: symbol '%s' not defined",sym->s_name); + } +#endif + } +} + +#ifdef PD +void flext::buffer::cb_tick(buffer *b) +{ + if(b->arr) garray_redraw(b->arr); +#ifdef _DEBUG + else error("buffer: array is NULL"); +#endif + + if(b->isdirty && b->interval) { + b->isdirty = false; + b->ticking = true; + clock_delay(b->tick,b->interval); + } + else + b->ticking = false; +} +#endif + diff --git a/externals/grill/flext/source/flclass.h b/externals/grill/flext/source/flclass.h new file mode 100644 index 00000000..5c67dde9 --- /dev/null +++ b/externals/grill/flext/source/flclass.h @@ -0,0 +1,599 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flclass.h + \brief User accessible flext base classes + +*/ + +#ifndef __FLCLASS_H +#define __FLCLASS_H + +// include the header file declaring the base classes +#include "flbase.h" +#include "flsupport.h" + +#ifdef FLEXT_THREADS +#include <pthread.h> +#include <sched.h> +#endif + +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif + +#ifdef __BORLANDC__ +#pragma warn -8008 // Condition is always false +#pragma warn -8057 // Parameter is never used +#pragma warn -8066 // Unreachable code +#endif + + +// === flext_base ================================================== + +//class qmsg; +//class thr_entry; + +/*! \brief Flext message only base object +*/ + + +class flext_base: + public flext_obj +{ + FLEXT_HEADER_S(flext_base,flext_obj,Setup) + + friend class flext_obj; + +public: + + /*! \defgroup FLEXT_C_BASE Flext basic class functionality + + @{ + */ + +// --- compatibility mode ---------------------------------------- + + /*! \brief Cross-platform compatibility flag. + If set flext allows only operations valid for all platforms. + Set to true by default! + */ + static bool compatibility; + +// --- inheritable virtual methods -------------------------------- + + /*! \defgroup FLEXT_C_VIRTUAL Flext virtual base class functions + + @{ + */ + + //! called on "help" message: should post some text + virtual void m_help(); + + //! called on patcher load (not on mere object creation!) + virtual void m_loadbang() {} + + //! quickhelp for inlets/outlets (gets calles in MaxMSP only) + virtual void m_assist(long /*msg*/,long /*arg*/,char * /*s*/) {} + + /*! \brief Called for every incoming message. + All method handling is done in there + \return True if a handler was found and called + */ + virtual bool m_methodmain(int inlet,const t_symbol *s,int argc,t_atom *argv); + + //! called for every unhandled message (by m_methodmain) + virtual bool m_method_(int inlet,const t_symbol *s,int argc,t_atom *argv); + +//! @} + + +// --- inlet/outlet stuff ----------------------------------------- + + /*! \defgroup FLEXT_C_INOUT Flext in-/outlet functions + \note These must be called in the class' constructor + \note All (also default) inlets must be defined + + @{ + */ + + // argument m specifies multiple inlet/outlet count + +// void AddInDef() { AddInlet(xlet::tp_def,1); } + + /*! \brief Add inlet(s) for anythings + That's the one to choose for the left-most (first) inlet unless it's a signal inlet. + */ + void AddInAnything(int m = 1) { AddInlet(xlet::tp_any,m); } // leftmost or via proxy + void AddInAnything(const char *desc,int m = 1) { AddInlet(xlet::tp_any,m,desc); } // leftmost or via proxy + //! Add inlet(s) for floats + void AddInFloat(int m = 1) { AddInlet(xlet::tp_float,m); } + void AddInFloat(const char *desc,int m = 1) { AddInlet(xlet::tp_float,m,desc); } + //! Add inlet(s) for ints + void AddInInt(int m = 1) { AddInlet(xlet::tp_int,m); } + void AddInInt(const char *desc,int m = 1) { AddInlet(xlet::tp_int,m,desc); } + //! Add inlet(s) for symbols + void AddInSymbol(int m = 1) { AddInlet(xlet::tp_sym,m); } + void AddInSymbol(const char *desc,int m = 1) { AddInlet(xlet::tp_sym,m,desc); } + //! Add inlet(s) for bang + void AddInBang(int m = 1) { AddInlet(xlet::tp_sym,m); } + void AddInBang(const char *desc,int m = 1) { AddInlet(xlet::tp_sym,m,desc); } + //! Add inlet(s) for lists + void AddInList(int m = 1) { AddInlet(xlet::tp_list,m); } // via proxy + void AddInList(const char *desc,int m = 1) { AddInlet(xlet::tp_list,m,desc); } // via proxy + + //! Add outlet(s) for anythings + void AddOutAnything(int m = 1) { AddOutlet(xlet::tp_any,m); } + void AddOutAnything(const char *desc,int m = 1) { AddOutlet(xlet::tp_any,m,desc); } + //! Add outlet(s) for floats + void AddOutFloat(int m = 1) { AddOutlet(xlet::tp_float,m); } + void AddOutFloat(const char *desc,int m = 1) { AddOutlet(xlet::tp_float,m,desc); } + //! Add outlet(s) for ints + void AddOutInt(int m = 1) { AddOutlet(xlet::tp_int,m); } + void AddOutInt(const char *desc,int m = 1) { AddOutlet(xlet::tp_int,m,desc); } + //! Add outlet(s) for symbols + void AddOutSymbol(int m = 1) { AddOutlet(xlet::tp_sym,m); } + void AddOutSymbol(const char *desc,int m = 1) { AddOutlet(xlet::tp_sym,m,desc); } + //! Add outlet(s) for bangs + void AddOutBang(int m = 1) { AddOutlet(xlet::tp_sym,m); } + void AddOutBang(const char *desc,int m = 1) { AddOutlet(xlet::tp_sym,m,desc); } + //! Add outlet(s) for lists + void AddOutList(int m = 1) { AddOutlet(xlet::tp_list,m); } + void AddOutList(const char *desc,int m = 1) { AddOutlet(xlet::tp_list,m,desc); } + + /*! \brief Set up inlets and outlets + \note this is deprecated... inlets and outlets are now set up automatically + */ + bool SetupInOut() { return true; } + + //! Get number of inlets + int CntIn() const { return incnt; } + //! Get number of outlets + int CntOut() const { return outcnt; } + //! Get number of signal inlets + int CntInSig() const { return insigs; } + //! Get number of signal outlets + int CntOutSig() const { return outsigs; } + + + class outlet; +// class AtomList; +// class AtomAnything; + + //! Retrieve currently processed message tag (NULL if no message processing) + const t_symbol *thisTag() const { return curtag; } + + //! Get pointer to outlet (_after_ calling setup_inout()!) + outlet *GetOut(int ix) { return (outlets && ix < outcnt)?outlets[ix]:NULL; } + + // output messages + + void ToOutBang(outlet *o); + //! Output bang (index n starts with 0) + void ToOutBang(int n) { outlet *o = GetOut(n); if(o) ToOutBang(o); } + + void ToOutFloat(outlet *o,float f); + //! Output float (index n starts with 0) + void ToOutFloat(int n,float f) { outlet *o = GetOut(n); if(o) ToOutFloat(o,f); } + + void ToOutInt(outlet *o,int f); + //! Output int (index n starts with 0) + void ToOutInt(int n,int f) { outlet *o = GetOut(n); if(o) ToOutInt(o,f); } + + void ToOutSymbol(outlet *o,const t_symbol *s); + //! Output symbol (index n starts with 0) + void ToOutSymbol(int n,const t_symbol *s) { outlet *o = GetOut(n); if(o) ToOutSymbol(o,s); } + + void ToOutString(outlet *o,const char *s) { ToOutSymbol(o,MakeSymbol(s)); } + //! Output string (index n starts with 0) + void ToOutString(int n,const char *s) { outlet *o = GetOut(n); if(o) ToOutString(o,s); } + + void ToOutList(outlet *o,int argc,const t_atom *argv); + //! Output list (index n starts with 0) + void ToOutList(int n,int argc,const t_atom *argv) { outlet *o = GetOut(n); if(o) ToOutList(o,argc,argv); } + //! Output list (index n starts with 0) + void ToOutList(int n,const AtomList &list) { ToOutList(n,list.Count(),list.Atoms()); } + + void ToOutAnything(outlet *o,const t_symbol *s,int argc,const t_atom *argv); + //! Output anything (index n starts with 0) + void ToOutAnything(int n,const t_symbol *s,int argc,const t_atom *argv) { outlet *o = GetOut(n); if(o) ToOutAnything(o,const_cast<t_symbol *>(s),argc,argv); } + //! Output anything (index n starts with 0) + void ToOutAnything(int n,const AtomAnything &any) { ToOutAnything(n,any.Header(),any.Count(),any.Atoms()); } + + void ToQueueBang(outlet *o); + void ToQueueBang(int n) { outlet *o = GetOut(n); if(o) ToQueueBang(o); } + void ToQueueFloat(outlet *o,float f); + void ToQueueFloat(int n,float f) { outlet *o = GetOut(n); if(o) ToQueueFloat(o,f); } + void ToQueueInt(outlet *o,int f); + void ToQueueInt(int n,int f) { outlet *o = GetOut(n); if(o) ToQueueInt(o,f); } + void ToQueueSymbol(outlet *o,const t_symbol *s); + void ToQueueSymbol(int n,const t_symbol *s) { outlet *o = GetOut(n); if(o) ToQueueSymbol(o,s); } + void ToQueueString(int n,const char *s) { ToQueueSymbol(n,MakeSymbol(s)); } + void ToQueueList(outlet *o,int argc,const t_atom *argv); + void ToQueueList(int n,int argc,const t_atom *argv) { outlet *o = GetOut(n); if(o) ToQueueList(o,argc,argv); } + void ToQueueList(int n,const AtomList &list) { ToQueueList(n,list.Count(),list.Atoms()); } + void ToQueueAnything(outlet *o,const t_symbol *s,int argc,const t_atom *argv); + void ToQueueAnything(int n,const t_symbol *s,int argc,const t_atom *argv) { outlet *o = GetOut(n); if(o) ToQueueAnything(o,s,argc,argv); } + void ToQueueAnything(int n,const AtomAnything &any) { ToQueueAnything(n,any.Header(),any.Count(),any.Atoms()); } + +//! @} + + +// --- message handling ------------------------------------------- + + enum metharg { + a_null = 0, + a_float,a_int, + a_symbol,a_pointer, + a_list,a_any, + a_LIST,a_ANY + }; + + typedef bool (*methfun)(flext_base *c); + + /*! \defgroup FLEXT_C_ADDMETHOD Flext method handling + \internal + + @{ + */ + + void AddMethodDef(int inlet,const char *tag = NULL); // call virtual function for tag && inlet + void AddMethod(int inlet,const char *tag,methfun fun,metharg tp,...); + + void AddMethod(int inlet,bool (*m)(flext_base *,int,t_atom *)) { AddMethod(inlet,"list",(methfun)m,a_list,a_null); } + void AddMethod(int inlet,const char *tag,bool (*m)(flext_base *)) { AddMethod(inlet,tag,(methfun)m,a_null); } // pure method + void AddMethod(int inlet,bool (*m)(flext_base *,const t_symbol *,int,t_atom *)) { AddMethod(inlet,"anything",(methfun)m,a_any,a_null); } // anything + void AddMethod(int inlet,bool (*m)(flext_base *,t_symbol *&)) { AddMethod(inlet,"symbol",(methfun)m,a_symbol,a_null); } // single symbol + void AddMethod(int inlet,bool (*m)(flext_base *,float &)) { AddMethod(inlet,"float",(methfun)m,a_float,a_null); } // single float + void AddMethod(int inlet,bool (*m)(flext_base *,float &,float &)) { AddMethod(inlet,"list",(methfun)m,a_float,a_float,a_null); } // list of 2 floats + void AddMethod(int inlet,bool (*m)(flext_base *,float &,float &,float &)) { AddMethod(inlet,"list",(methfun)m,a_float,a_float,a_float,a_null); } // list of 3 floats +#ifdef PD + void AddMethod(int inlet,bool (*m)(flext_base *,int &)) { AddMethod(inlet,"float",(methfun)m,a_int,a_null); } // single float +#else + void AddMethod(int inlet,bool (*m)(flext_base *,int &)) { AddMethod(inlet,"int",(methfun)m,a_int,a_null); } // single float +#endif + void AddMethod(int inlet,bool (*m)(flext_base *,int &,int &)) { AddMethod(inlet,"list",(methfun)m,a_int,a_int,a_null); } // list of 2 floats + void AddMethod(int inlet,bool (*m)(flext_base *,int &,int &,int &)) { AddMethod(inlet,"list",(methfun)m,a_int,a_int,a_int,a_null); } // list of 3 floats + void AddMethod(int inlet,const char *tag,bool (*m)(flext_base *,int,t_atom *)) { AddMethod(inlet,tag,(methfun)m,a_list,a_null); } // method+gimme + void AddMethod(int inlet,const char *tag,bool (*m)(flext_base *,const t_symbol *,int,t_atom *)) { AddMethod(inlet,tag,(methfun)m,a_any,a_null); } // method+gimme + void AddMethod(int inlet,const char *tag,bool (*m)(flext_base *,t_symbol *&)) { AddMethod(inlet,tag,(methfun)m,a_symbol,a_null); } // method+symbol + void AddMethod(int inlet,const char *tag,bool (*m)(flext_base *,float &)) { AddMethod(inlet,tag,(methfun)m,a_float,a_null); } // method+float + void AddMethod(int inlet,const char *tag,bool (*m)(flext_base *,int &)) { AddMethod(inlet,tag,(methfun)m,a_int,a_null); } // method+int + + //! Set MaxMSP style of distributing list elements over (message) inlets + void SetDist(bool d = true) { distmsgs = d; } + +//! @} + +// --- bind/unbind --------------------------------------- + +#ifdef PD + //! Bind object to a symbol + bool Bind(const t_symbol *s) { pd_bind(&thisHdr()->ob_pd,const_cast<t_symbol *>(s)); return true; } + //! Unbind object from a symbol + bool Unbind(const t_symbol *s) { pd_unbind(&thisHdr()->ob_pd,const_cast<t_symbol *>(s)); return true; } +#else + //! Bind object to a symbol + bool Bind(const t_symbol *s) { if(s->s_thing) return false; else { const_cast<t_symbol *>(s)->s_thing = (t_object *)thisHdr(); return true; } } + //! Unbind object from a symbol + bool Unbind(const t_symbol *s) { if(s->s_thing != (t_object *)thisHdr()) return false; else { const_cast<t_symbol *>(s)->s_thing = NULL; return true; } } +#endif + //! Bind object to a symbol (as string) + bool Bind(const char *c) { return Bind(MakeSymbol(c)); } + //! Unbind object from a symbol (as string) + bool Unbind(const char *c) { return Unbind(MakeSymbol(c)); } + +/* + // Low level + + //! Bind object to a symbol + static void DoUnbind(t_symbol *s,flext_obj *o); + //! Unbind object from a symbol + static void DoBind(const t_symbol *s,flext_obj *o); + //! Get bound object of a symbol + static t_class **GetBound(const t_symbol *s) { return (t_class **)s->s_thing; } +*/ + +// --- thread stuff ----------------------------------------------- + +#ifdef FLEXT_THREADS + /*! \defgroup FLEXT_C_THREAD Flext thread handling + + @{ + */ + + /*! \brief Check if current thread should terminate + \todo Check for currently running thread + */ + bool ShouldExit() const { return shouldexit; } + + //! Check if current thread is the realtime system's thread + bool IsSystemThread() const { pthread_t cur = pthread_self(); return pthread_equal(cur,thrid) != 0; } + + /*! \brief Yield to other threads + \remark A call to this is only needed for systems with cooperative multitasking like MacOS<=9 + */ + static void ThrYield() { sched_yield(); } + + typedef pthread_t thrid_t; + + /*! \brief Increase/Decrease priority of a thread + */ + static bool ChangePriority(int dp,thrid_t thr = GetThreadId()); + + /*! \brief Get priority of a thread + */ + static int GetPriority(thrid_t thr = GetThreadId()); + + /*! \brief Set priority of a thread + */ + static bool SetPriority(int p,thrid_t thr = GetThreadId()); + + /*! \brief Get current thread id + */ + static thrid_t GetThreadId(); + + +#endif // FLEXT_THREADS + +//! @} + +// xxx internal stuff xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +protected: + +// --- thread stuff ----------------------------------------------- + +#ifdef FLEXT_THREADS + class thr_params + { + public: + thr_params(flext_base *c,int n = 1); + ~thr_params(); + + void set_any(const t_symbol *s,int argc,const t_atom *argv); + void set_list(int argc,const t_atom *argv); + + flext_base *cl; + union _data { + bool _bool; + float _float; + int _int; + t_symptr _t_symptr; + struct { AtomAnything *args; } _any; + struct { AtomList *args; } _list; + struct { void *data; } _ext; + } *var; + }; + + class thr_entry + { + public: + thr_entry(pthread_t id = pthread_self()): thrid(id),nxt(NULL) {} + + bool Is(pthread_t id = pthread_self()) const { return pthread_equal(thrid,id) != 0; } + + pthread_t thrid; + thr_entry *nxt; + }; + + static bool StartThread(void *(*)(thr_params *p),thr_params *p,char *methname); + bool PushThread(); + void PopThread(); +#endif + +protected: + + flext_base(); + virtual ~flext_base(); + +// inlets and outlets + + /*! \brief Set up inlets and outlets + \return True on successful creation of all inlets and outlets + */ + virtual bool Init(); + + struct xlet { + enum type { + tp_none = 0, + tp_float,tp_int,tp_sym,tp_list,tp_any, + tp_LIST,tp_ANY, // use AtomList and AtomAnything + tp_sig + }; + + xlet(type t,const char *desc = NULL); + ~xlet(); + + char *desc; + type tp; + xlet *nxt; + }; + + /*! \addtogroup FLEXT_C_ATTR + + @{ + */ + + void AddAttrib(const char *attr,bool (*get)(flext_base *,float &),bool (*set)(flext_base *,float &)) { AddAttrib(attr,a_float,(methfun)get,(methfun)set); } + void AddAttrib(const char *attr,bool (*get)(flext_base *,int &),bool (*set)(flext_base *,int &)) { AddAttrib(attr,a_int,(methfun)get,(methfun)set); } + void AddAttrib(const char *attr,bool (*get)(flext_base *,t_symbol *&),bool (*set)(flext_base *,t_symbol *&)) { AddAttrib(attr,a_symbol,(methfun)get,(methfun)set); } + void AddAttrib(const char *attr,bool (*get)(flext_base *,AtomList *&),bool (*set)(flext_base *,AtomList *&)) { AddAttrib(attr,a_LIST,(methfun)get,(methfun)set); } + +//! @} + + /*! \addtogroup FLEXT_C_INOUT + + @{ + */ + + unsigned long XletCode(xlet::type tp = xlet::tp_none,...); // end list with 0 (= tp_none) !! + + void AddInlets(unsigned long code); // use XletCode to get code value + void AddInlet(xlet::type tp,int mult = 1,const char *desc = NULL) { AddXlet(tp,mult,desc,inlist); } + void AddOutlets(unsigned long code); // use XletCode to get code value + void AddOutlet(xlet::type tp,int mult = 1,const char *desc = NULL) { AddXlet(tp,mult,desc,outlist); } + + void DescInlet(int ix,const char *desc) { DescXlet(ix,desc,inlist); } + void DescOutlet(int ix,const char *desc) { DescXlet(ix,desc,outlist); } + +//! @} + +// method handling + + class methitem { + public: + methitem(int inlet,const t_symbol *t); + ~methitem(); + + void SetArgs(methfun fun,int argc,metharg *args); + + const t_symbol *tag; + int inlet; + int argc; + metharg *args; + methfun fun; + + methitem *nxt; + }; + +// const methitem *FindMethItem(int inlet,const t_symbol *tag,const methitem *st); + + class attritem { + public: + attritem(const t_symbol *tag,const t_symbol *gtag,metharg tp,methfun gfun,methfun sfun); + ~attritem(); + + const t_symbol *tag,*gtag; + metharg argtp; + methfun gfun,sfun; + + attritem *nxt; + }; + +private: + + static void Setup(t_class *c); + + xlet *inlist,*outlist; + const t_symbol *curtag; + int incnt,outcnt,insigs,outsigs; + outlet **outlets,*outattr; + bool distmsgs; + + void AddXlet(xlet::type tp,int mult,const char *desc,xlet *&root); + void DescXlet(int ix,const char *desc,xlet *&root); + + union t_any { + float ft; + int it; + t_symbol *st; + #ifdef PD + t_gpointer *pt; + #endif + void *vt; + }; + + typedef bool (*methfun_V)(flext_base *c,int argc,t_atom *argv); + typedef bool (*methfun_A)(flext_base *c,const t_symbol *s,int argc,t_atom *argv); + typedef bool (*methfun_0)(flext_base *c); + typedef bool (*methfun_1)(flext_base *c,t_any &); + typedef bool (*methfun_2)(flext_base *c,t_any &,t_any &); + typedef bool (*methfun_3)(flext_base *c,t_any &,t_any &,t_any &); + typedef bool (*methfun_4)(flext_base *c,t_any &,t_any &,t_any &,t_any &); + typedef bool (*methfun_5)(flext_base *c,t_any &,t_any &,t_any &,t_any &,t_any &); + + methitem *methhead; + void AddMethItem(methitem *m); + + attritem *attrhead; + int attrcnt; + void AddAttrItem(attritem *m); + + void AddAttrib(const char *attr,metharg tp,methfun gfun,methfun sfun); + + static int CheckAttrib(int argc,const t_atom *argv); + bool InitAttrib(int argc,const t_atom *argv); + + bool ListAttrib(); + bool GetAttrib(const t_symbol *s,int argc,const t_atom *argv); + bool SetAttrib(const t_symbol *s,int argc,const t_atom *argv); + + static bool cb_ListAttrib(flext_base *c) { return c->ListAttrib(); } + static bool cb_GetAttrib(flext_base *c,const t_symbol *s,int argc,const t_atom *argv) { return c->GetAttrib(s,argc,argv); } + static bool cb_SetAttrib(flext_base *c,const t_symbol *s,int argc,const t_atom *argv) { return c->SetAttrib(s,argc,argv); } + +#ifdef FLEXT_THREADS + bool shouldexit; + int thrcount; + + pthread_t thrid; // the thread that created the object (the system thread) + ThrMutex qmutex; + + thr_entry *thrhead,*thrtail; + ThrMutex tlmutex; +#endif + + class qmsg; + qmsg *qhead,*qtail; + t_qelem *qclk; +#ifdef MAXMSP + t_clock *yclk; + static void YTick(flext_base *th); +#endif + + static void QTick(flext_base *th); + void Queue(qmsg *m); + +#ifdef PD + // proxy object (for additional inlets) stuff + struct px_object; + friend struct px_object; +#elif defined(MAXMSP) + typedef object px_object; + static void cb_px_float(t_class *c,float f); + static void cb_px_int(t_class *c,int v); + static void cb_px_bang(t_class *c); + + static void cb_px_in1(t_class *c,int v); + static void cb_px_in2(t_class *c,int v); + static void cb_px_in3(t_class *c,int v); + static void cb_px_in4(t_class *c,int v); + static void cb_px_in5(t_class *c,int v); + static void cb_px_in6(t_class *c,int v); + static void cb_px_in7(t_class *c,int v); + static void cb_px_in8(t_class *c,int v); + static void cb_px_in9(t_class *c,int v); +#endif + static void cb_px_anything(t_class *c,const t_symbol *s,int argc,t_atom *argv); + + static void cb_px_ft1(t_class *c,float f); + static void cb_px_ft2(t_class *c,float f); + static void cb_px_ft3(t_class *c,float f); + static void cb_px_ft4(t_class *c,float f); + static void cb_px_ft5(t_class *c,float f); + static void cb_px_ft6(t_class *c,float f); + static void cb_px_ft7(t_class *c,float f); + static void cb_px_ft8(t_class *c,float f); + static void cb_px_ft9(t_class *c,float f); + + px_object **inlets; + + // callback functions + + static void cb_help(t_class *c); + + static void cb_loadbang(t_class *c); +#ifdef MAXMSP + static void cb_assist(t_class *c,void *b,long msg,long arg,char *s); +#endif +}; + +#endif diff --git a/externals/grill/flext/source/flcwmax-thr.h b/externals/grill/flext/source/flcwmax-thr.h new file mode 100755 index 00000000..1a9ecffb --- /dev/null +++ b/externals/grill/flext/source/flcwmax-thr.h @@ -0,0 +1,20 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +// This is the prefix file for CodeWarrior projects - threaded version + +#ifndef _FLEXT_CW_MAX_THR_H +#define _FLEXT_CW_MAX_THR_H + +#define FLEXT_THREADS + +#include "flcwmax.h" + +#endif diff --git a/externals/grill/flext/source/flcwmax.h b/externals/grill/flext/source/flcwmax.h new file mode 100644 index 00000000..5ef0b298 --- /dev/null +++ b/externals/grill/flext/source/flcwmax.h @@ -0,0 +1,26 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/* This is the prefix file for CodeWarrior projects */ + +#ifndef _FLEXT_CW_MAX_H +#define _FLEXT_CW_MAX_H + +#include <MacHeaders.h> + +#define MAXMSP + +#if !defined(__OPTIMIZE__) || __OPTIMIZE__ == 0 +#define _DEBUG +#endif + +/* #define _LOG */ + +#endif diff --git a/externals/grill/flext/source/fldefs.h b/externals/grill/flext/source/fldefs.h new file mode 100644 index 00000000..f92232f9 --- /dev/null +++ b/externals/grill/flext/source/fldefs.h @@ -0,0 +1,912 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file fldefs.h + \brief This file contains all #defines for actual usage + +*/ + +#ifndef __FLEXT_DEFS_H +#define __FLEXT_DEFS_H + +#ifdef FLEXT_GUI +#define FLEXT_CAST dynamic_cast +#else +#define FLEXT_CAST static_cast +#endif + +/*! \defgroup FLEXT_HEADER Flext class header + One (and only one!) of these definitions is compulsory for the class declaration. + It has to be placed somewhere in the class definition (not necessarily in a public section). + + @{ +*/ + +/*! \brief Plain flext class header + \param NEW_CLASS name of the current C++ class + \param PARENT_CLASS name of the base C++ class (e.g. flext_base or flext_dsp) +*/ +#define FLEXT_HEADER(NEW_CLASS,PARENT_CLASS) \ +\ +FLEXT_REALHDR(NEW_CLASS, PARENT_CLASS) + +/*! \brief Flext class header with setup function + \param NEW_CLASS name of the current C++ class + \param PARENT_CLASS name of the base C++ class (e.g. flext_base or flext_dsp) + \param SETUPFUN setup function, of type "void (*setupfn)(t_class *)" + + The setup function is called after class creation. It corresponds to the + original "object_setup" function, apart from the + fact that all necessary class initializations have already been taken care by flext. + The setup function can e.g. be used for a message to the console upon first creation of an object. + The object's t_class* data can be accessed by the static function thisClass() +*/ +#define FLEXT_HEADER_S(NEW_CLASS, PARENT_CLASS, SETUPFUN)\ +\ +FLEXT_REALHDR_S(NEW_CLASS, PARENT_CLASS, SETUPFUN) + + +//! @} + + + +// ==================================================================================== + +/*! \defgroup FLEXT_NEW Flext class instantiation + Makes an actual instance of a class. +*/ + +/*! \defgroup FLEXT_NEW_DSP Flext dsp class instantiation + Makes an actual instance of a dsp (aka "tilde") class (with signal processing). +*/ + +/*! \defgroup FLEXT_LIB Flext library class instantiation + Makes an actual instance of a class which is part of an object library (and not stand-alone). +*/ + +/*! \defgroup FLEXT_LIB_DSP Flext dsp library class instantiation + Makes an actual instance of a dsp (aka "tilde") class with signal processing + which is part of an object library (and not stand-alone). +*/ + +// NO ARGUMENTS +// ---------------------------------------- + +/*! Implementation of a flext class with no arguments + \ingroup FLEXT_NEW + \param NAME the object's actual name(s) as a string (like "*", "trigger", "noise~", etc.) + \param NEW_CLASS the object's C++ class name +*/ +#define FLEXT_NEW(NAME,NEW_CLASS) \ +\ +REAL_NEW(NAME,NEW_CLASS,0,0) + +/*! Implementation of a flext dsp class with no arguments + \ingroup FLEXT_NEW_DSP +*/ +#define FLEXT_NEW_DSP(NAME,NEW_CLASS) \ +\ +REAL_NEW(NAME,NEW_CLASS,1,0) + +/*! Implementation of a flext class (part of a library) with no arguments + \ingroup FLEXT_LIB +*/ +#define FLEXT_LIB(NAME,NEW_CLASS) \ +\ +REAL_NEW(NAME,NEW_CLASS,0,1) + +/*! Implementation of a flext dsp class (part of a library) with no arguments + \ingroup FLEXT_LIB_DSP +*/ +#define FLEXT_LIB_DSP(NAME,NEW_CLASS) \ +\ +REAL_NEW(NAME,NEW_CLASS,1,1) + + +// VARIABLE ARGUMENT LIST +// ---------------------------------------- + +/*! Implementation of a flext class with a variable argument list + \ingroup FLEXT_NEW +*/ +#define FLEXT_NEW_V(NAME,NEW_CLASS) \ +\ +REAL_NEW_V(NAME,NEW_CLASS,0,0) \ + +/*! Implementation of a flext tilde class with a variable argument list + \ingroup FLEXT_NEW_DSP +*/ +#define FLEXT_NEW_DSP_V(NAME,NEW_CLASS) \ +\ +REAL_NEW_V(NAME,NEW_CLASS,1,0) \ + +/*! Implementation of a flext class (part of a library) with a variable argument list + \ingroup FLEXT_LIB +*/ +#define FLEXT_LIB_V(NAME,NEW_CLASS) \ +\ +REAL_NEW_V(NAME,NEW_CLASS, 0,1) + +/*! Implementation of a flext tilde class (part of a library) with a variable argument list + \ingroup FLEXT_LIB_DSP +*/ +#define FLEXT_LIB_DSP_V(NAME,NEW_CLASS) \ +\ +REAL_NEW_V(NAME,NEW_CLASS, 1,1) + + +// OBJECT NAME + VARIABLE ARGUMENT LIST +// ---------------------------------------- + +/*! Implementation of a flext class with its name and a variable argument list + \ingroup FLEXT_NEW +*/ +#define FLEXT_NEW_NV(NAME,NEW_CLASS) \ +\ +REAL_NEW_NV(NAME,NEW_CLASS,0,0) \ + +/*! Implementation of a flext tilde class with its name and a variable argument list + \ingroup FLEXT_NEW_DSP +*/ +#define FLEXT_NEW_DSP_NV(NAME,NEW_CLASS) \ +\ +REAL_NEW_NV(NAME,NEW_CLASS,1,0) \ + +/*! Implementation of a flext class (part of a library) with its name and a variable argument list + \ingroup FLEXT_LIB +*/ +#define FLEXT_LIB_NV(NAME,NEW_CLASS) \ +\ +REAL_NEW_NV(NAME,NEW_CLASS, 0,1) + +/*! Implementation of a flext tilde class (part of a library) with its name and a variable argument list + \ingroup FLEXT_LIB_DSP +*/ +#define FLEXT_LIB_DSP_NV(NAME,NEW_CLASS) \ +\ +REAL_NEW_NV(NAME,NEW_CLASS, 1,1) + + +// ONE ARGUMENT +// ---------------------------------------- + +/*! Implementation of a flext class with one argument + \ingroup FLEXT_NEW +*/ +#define FLEXT_NEW_1(NAME,NEW_CLASS, TYPE) \ +\ +REAL_NEW_1(NAME,NEW_CLASS, 0, 0,TYPE) \ + +/*! Implementation of a flext tilde class with one argument + \ingroup FLEXT_NEW_DSP +*/ +#define FLEXT_NEW_DSP_1(NAME,NEW_CLASS, TYPE) \ +\ +REAL_NEW_1(NAME,NEW_CLASS, 1, 0,TYPE) \ + +/*! Implementation of a flext class (part of a library) with one argument + \ingroup FLEXT_LIB +*/ +#define FLEXT_LIB_1(NAME,NEW_CLASS, TYPE) \ +\ +REAL_NEW_1(NAME,NEW_CLASS, 0,1,TYPE) + +/*! Implementation of a flext tilde class (part of a library) with one argument + \ingroup FLEXT_LIB_DSP +*/ +#define FLEXT_LIB_DSP_1(NAME,NEW_CLASS, TYPE) \ +\ +REAL_NEW_1(NAME,NEW_CLASS, 1,1, TYPE) + + +// TWO ARGUMENTS +// ---------------------------------------- + +/*! Implementation of a flext class with 2 arguments + \ingroup FLEXT_NEW +*/ +#define FLEXT_NEW_2(NAME,NEW_CLASS, TYPE1, TYPE2) \ +\ +REAL_NEW_2(NAME,NEW_CLASS, 0,0, TYPE1, TYPE2) \ + +/*! Implementation of a flext tilde class with 2 arguments + \ingroup FLEXT_NEW_DSP +*/ +#define FLEXT_NEW_DSP_2(NAME,NEW_CLASS, TYPE1, TYPE2) \ +\ +REAL_NEW_2(NAME,NEW_CLASS, 1,0, TYPE1, TYPE2) \ + +/*! Implementation of a flext class (part of a library) with 2 arguments + \ingroup FLEXT_LIB +*/ +#define FLEXT_LIB_2(NAME,NEW_CLASS, TYPE1, TYPE2) \ +\ +REAL_NEW_2(NAME,NEW_CLASS, 0,1, TYPE1, TYPE2) + +/*! Implementation of a flext tilde class (part of a library) with 2 arguments + \ingroup FLEXT_LIB_DSP +*/ +#define FLEXT_LIB_DSP_2(NAME,NEW_CLASS, TYPE1, TYPE2) \ +\ +REAL_NEW_2(NAME,NEW_CLASS, 1,1, TYPE1, TYPE2) + + +// THREE ARGUMENTS +// ---------------------------------------- + +/*! Implementation of a flext class with 3 arguments + \ingroup FLEXT_NEW +*/ +#define FLEXT_NEW_3(NAME,NEW_CLASS, TYPE1, TYPE2, TYPE3) \ +\ +REAL_NEW_3(NAME,NEW_CLASS, 0,0, TYPE1, TYPE2, TYPE3) \ + +/*! Implementation of a flext tilde class with 3 arguments + \ingroup FLEXT_NEW_DSP +*/ +#define FLEXT_NEW_DSP_3(NAME,NEW_CLASS, TYPE1, TYPE2, TYPE3) \ +\ +REAL_NEW_3(NAME,NEW_CLASS, 1,0, TYPE1, TYPE2, TYPE3) \ + +/*! Implementation of a flext class (part of a library) with 3 arguments + \ingroup FLEXT_LIB +*/ +#define FLEXT_LIB_3(NAME,NEW_CLASS, TYPE1, TYPE2, TYPE3) \ +\ +REAL_NEW_3(NAME,NEW_CLASS, 0,1,TYPE1, TYPE2, TYPE3) + +/*! Implementation of a flext tilde class (part of a library) with 3 arguments + \ingroup FLEXT_LIB_DSP +*/ +#define FLEXT_LIB_DSP_3(NAME,NEW_CLASS, TYPE1, TYPE2, TYPE3) \ +\ +REAL_NEW_3(NAME,NEW_CLASS, 1,1, TYPE1, TYPE2, TYPE3) + + +// deprecated stuff + +#define FLEXT_NEW_G FLEXT_NEW_V + +#define FLEXT_NEW_TILDE FLEXT_NEW_DSP +#define FLEXT_NEW_TILDE_G FLEXT_NEW_DSP_V +#define FLEXT_NEW_TILDE_1 FLEXT_NEW_DSP_1 +#define FLEXT_NEW_TILDE_2 FLEXT_NEW_DSP_2 +#define FLEXT_NEW_TILDE_3 FLEXT_NEW_DSP_3 + +#define FLEXT_LIB_G FLEXT_LIB_V + +#define FLEXT_LIB_TILDE FLEXT_LIB_DSP +#define FLEXT_LIB_TILDE_G FLEXT_LIB_DSP_V +#define FLEXT_LIB_TILDE_1 FLEXT_LIB_DSP_1 +#define FLEXT_LIB_TILDE_2 FLEXT_LIB_DSP_2 +#define FLEXT_LIB_TILDE_3 FLEXT_LIB_DSP_3 + + + + +// ==================================================================================== + + +/*! \defgroup FLEXT_CALLBACK Flext callbacks + + @{ +*/ + +//! Set up a method callback with no arguments +#define FLEXT_CALLBACK(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(); return true; } + +//! Set up a method callback for an anything argument +#define FLEXT_CALLBACK_A(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,const t_symbol *s,int argc,t_atom *argv) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(s,argc,argv); return true; } + +//! Set up a method callback for a variable argument list +#define FLEXT_CALLBACK_V(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int argc,t_atom *argv) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(argc,argv); return true; } + +//! Set up a method callback for a data package (void *) argument +#define FLEXT_CALLBACK_X(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,void *data) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(data); return true; } + +//! Set up a method callback for a boolean argument +#define FLEXT_CALLBACK_B(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int &arg1) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(arg1 != 0); return true; } + +//! Set up a method callback for 1 argument +#define FLEXT_CALLBACK_1(M_FUN,TP1) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(arg1); return true; } + +//! Set up a method callback for 2 arguments +#define FLEXT_CALLBACK_2(M_FUN,TP1,TP2) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(arg1,arg2); return true; } + +//! Set up a method callback for 3 arguments +#define FLEXT_CALLBACK_3(M_FUN,TP1,TP2,TP3) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(arg1,arg2,arg3); return true; } + +//! Set up a method callback for 4 arguments +#define FLEXT_CALLBACK_4(M_FUN,TP1,TP2,TP3,TP4) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP4 &arg4) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(arg1,arg2,arg3,arg4); return true; } + +//! Set up a method callback for 5 arguments +#define FLEXT_CALLBACK_5(M_FUN,TP1,TP2,TP3,TP4,TP5) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP4 &arg4,TP5 &arg5) \ +{ FLEXT_CAST<thisType *>(c)->M_FUN(arg1,arg2,arg3,arg4,arg5); return true; } + + +// Shortcuts + +//! Set up a method callback for 1 float argument +#define FLEXT_CALLBACK_F(M_FUN) \ +\ +FLEXT_CALLBACK_1(M_FUN,float) + +//! Set up a method callback for 2 float arguments +#define FLEXT_CALLBACK_FF(M_FUN) \ +\ +FLEXT_CALLBACK_2(M_FUN,float,float) + +//! Set up a method callback for 3 float arguments +#define FLEXT_CALLBACK_FFF(M_FUN) \ +\ +FLEXT_CALLBACK_3(M_FUN,float,float,float) + +//! Set up a method callback for 1 integer argument +#define FLEXT_CALLBACK_I(M_FUN) \ +\ +FLEXT_CALLBACK_1(M_FUN,int) + +//! Set up a method callback for 2 integer arguments +#define FLEXT_CALLBACK_II(M_FUN) \ +\ +FLEXT_CALLBACK_2(M_FUN,int,int) + +//! Set up a method callback for 3 integer arguments +#define FLEXT_CALLBACK_III(M_FUN) \ +\ +FLEXT_CALLBACK_3(M_FUN,int,int,int) + +//! Set up a method callback for 1 symbol argument +#define FLEXT_CALLBACK_S(M_FUN) \ +\ +FLEXT_CALLBACK_1(M_FUN,t_symptr) + + +// deprecated +#define FLEXT_CALLBACK_G FLEXT_CALLBACK_V + +//! @} + + + +/*! \defgroup FLEXT_THREAD Flext threads + + @{ +*/ + +#ifdef FLEXT_THREADS + +//! Set up a threaded method callback with no arguments +#define FLEXT_THREAD(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c) { \ + thr_params *p = new thr_params(c); \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + delete p; \ + if(ok) { \ + th->M_FUN(); \ + th->PopThread(); \ + } \ + return NULL; \ +} + +//! Set up a threaded method callback for an anything argument +#define FLEXT_THREAD_A(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,const t_symbol *s,int argc,t_atom *argv) { \ + thr_params *p = new thr_params(c); p->set_any(s,argc,argv); \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + AtomAnything *args = p->var[0]._any.args; \ + delete p; \ + if(ok) { \ + th->M_FUN(args->Header(),args->Count(),args->Atoms()); \ + th->PopThread(); \ + } \ + delete args; \ + return NULL; \ +} + +//! Set up a threaded method callback for a variable argument list +#define FLEXT_THREAD_V(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int argc,t_atom *argv) { \ + thr_params *p = new thr_params(c); p->set_list(argc,argv); \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + AtomList *args = p->var[0]._list.args; \ + delete p; \ + if(ok) { \ + th->M_FUN(args->Count(),args->Atoms()); \ + th->PopThread(); \ + } \ + delete args; \ + return NULL; \ +} + +/*! \brief Set up a threaded method callback for an arbitrary data struct + \note Data is pure... no destructor is called upon delete +*/ +#define FLEXT_THREAD_X(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,void *data) { \ + thr_params *p = new thr_params(c); p->var[0]._ext.data = data; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + void *data = p->var[0]._ext.data; \ + delete p; \ + if(ok) { \ + th->M_FUN(data); \ + th->PopThread(); \ + } \ + delete data; \ + return NULL; \ +} + +//! Set up a threaded method callback for a boolean argument +#define FLEXT_THREAD_B(M_FUN) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int &arg1) { \ + thr_params *p = new thr_params(c); p->var[0]._bool = arg1 != 0; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + bool b = p->var[0]._bool; \ + delete p; \ + if(ok) { \ + th->M_FUN(b); \ + th->PopThread(); \ + } \ + return NULL; \ +} + +//! Set up a threaded method callback for 1 argument +#define FLEXT_THREAD_1(M_FUN,TP1) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1) { \ + thr_params *p = new thr_params(c,1); \ + p->var[0]._ ## TP1 = arg1; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + const TP1 v1 = p->var[0]._ ## TP1; \ + delete p; \ + if(ok) { \ + th->M_FUN(v1); \ + th->PopThread(); \ + } \ + return NULL; \ +} + +//! Set up a threaded method callback for 2 arguments +#define FLEXT_THREAD_2(M_FUN,TP1,TP2) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2) { \ + thr_params *p = new thr_params(c,2); \ + p->var[0]._ ## TP1 = arg1; \ + p->var[1]._ ## TP2 = arg2; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + const TP1 v1 = p->var[0]._ ## TP1; \ + const TP1 v2 = p->var[1]._ ## TP2; \ + delete p; \ + if(ok) { \ + th->M_FUN(v1,v2); \ + th->PopThread(); \ + } \ + return NULL; \ +} + +//! Set up a threaded method callback for 3 arguments +#define FLEXT_THREAD_3(M_FUN,TP1,TP2,TP3) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3) { \ + thr_params *p = new thr_params(c,3); \ + p->var[0]._ ## TP1 = arg1; \ + p->var[1]._ ## TP2 = arg2; \ + p->var[2]._ ## TP3 = arg3; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + const TP1 v1 = p->var[0]._ ## TP1; \ + const TP2 v2 = p->var[1]._ ## TP2; \ + const TP3 v3 = p->var[2]._ ## TP3; \ + delete p; \ + if(ok) { \ + th->M_FUN(v1,v2,v3); \ + th->PopThread(); \ + } \ + return NULL; \ +} + +//! Set up a threaded method callback for 4 arguments +#define FLEXT_THREAD_4(M_FUN,TP1,TP2,TP3,TP4) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP4 &arg4) { \ + thr_params *p = new thr_params(c,4); \ + p->var[0]._ ## TP1 = arg1; \ + p->var[1]._ ## TP2 = arg2; \ + p->var[2]._ ## TP3 = arg3; \ + p->var[3]._ ## TP4 = arg4; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + const TP1 v1 = p->var[0]._ ## TP1; \ + const TP2 v2 = p->var[1]._ ## TP2; \ + const TP3 v3 = p->var[2]._ ## TP3; \ + const TP4 v4 = p->var[3]._ ## TP4; \ + delete p; \ + if(ok) { \ + th->M_FUN(v1,v2,v3,v4); \ + th->PopThread(); \ + } \ + return NULL; \ +} + +//! Set up a threaded method callback for 5 arguments +#define FLEXT_THREAD_5(M_FUN,TP1,TP2,TP3,TP4,TP5) \ +static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP4 &arg4,TP5 &arg5) { \ + thr_params *p = new thr_params(c,5); \ + p->var[0]._ ## TP1 = arg1; \ + p->var[1]._ ## TP2 = arg2; \ + p->var[2]._ ## TP3 = arg3; \ + p->var[3]._ ## TP4 = arg4; \ + p->var[4]._ ## TP5 = arg5; \ + return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ +} \ +static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ + thisType *th = FLEXT_CAST<thisType *>(p->cl); \ + bool ok = th->PushThread(); \ + const TP1 v1 = p->var[0]._ ## TP1; \ + const TP2 v2 = p->var[1]._ ## TP2; \ + const TP3 v3 = p->var[2]._ ## TP3; \ + const TP4 v4 = p->var[3]._ ## TP4; \ + const TP5 v5 = p->var[4]._ ## TP5; \ + delete p; \ + if(ok) { \ + th->M_FUN(v1,v2,v3,v4,v5); \ + th->PopThread(); \ + } \ + return NULL; \ +} + + +//! Shortcuts + +//! Set up a threaded method callback for 1 float argument +#define FLEXT_THREAD_F(M_FUN) \ +\ +FLEXT_THREAD_1(M_FUN,float) + +//! Set up a threaded method callback for 2 float arguments +#define FLEXT_THREAD_FF(M_FUN) \ +\ +FLEXT_THREAD_2(M_FUN,float,float) + +//! Set up a threaded method callback for 3 float arguments +#define FLEXT_THREAD_FFF(M_FUN) \ +\ +FLEXT_THREAD_3(M_FUN,float,float,float) + +//! Set up a threaded method callback for 1 integer argument +#define FLEXT_THREAD_I(M_FUN) \ +\ +FLEXT_THREAD_1(M_FUN,int) + +//! Set up a threaded method callback for 2 integer arguments +#define FLEXT_THREAD_II(M_FUN) \ +\ +FLEXT_THREAD_2(M_FUN,int,int) + +//! Set up a threaded method callback for 3 integer arguments +#define FLEXT_THREAD_III(M_FUN) \ +\ +FLEXT_THREAD_3(M_FUN,int,int,int) + +//! Set up a threaded method callback for 1 symbol argument +#define FLEXT_THREAD_S(M_FUN) \ +\ +FLEXT_THREAD_1(M_FUN,t_symptr) + +// deprecated +#define FLEXT_THREAD_G FLEXT_THREAD_V + +#endif // FLEXT_THREAD + +//! @} + + + +// ==================================================================================== + + + +/*! \defgroup FLEXT_ADDMETHOD Add flext methods + These should be the used in the class' constructor + + @{ +*/ + +//! Enable list element distribution over inlets (if no better handler found) +#define FLEXT_ADDDIST() \ +\ +SetDist(true) + +//! Add a method handler for bang +#define FLEXT_ADDBANG(IX,M_FUN) \ +\ +AddMethod(IX,"bang",FLEXT_CALL_PRE(M_FUN)) + +//! Add a handler for a method with no arguments +#define FLEXT_ADDMETHOD(IX,M_FUN) \ +AddMethod(IX,FLEXT_CALL_PRE(M_FUN)) + +//! Add a handler for a method with a (variable argument) list +#define FLEXT_ADDMETHOD_V(IX,M_FUN) \ +\ +AddMethod(IX,FLEXT_CALL_PRE(M_FUN)) + +//! Add a handler for a method with an anything argument +#define FLEXT_ADDMETHOD_A(IX,M_FUN) \ +\ +AddMethod(IX,FLEXT_CALL_PRE(M_FUN)) + +//! Add a a handler for a method with implicit arguments +#define FLEXT_ADDMETHOD_(IX,M_TAG,M_FUN) \ +\ +AddMethod(IX,M_TAG,FLEXT_CALL_PRE(M_FUN)) + +//! Add a handler for a method with 1 enum type argument +#define FLEXT_ADDMETHOD_E(IX,M_TAG,M_FUN) \ +\ +AddMethod(IX,M_TAG,(methfun)(FLEXT_CALL_PRE(M_FUN)),a_int,a_null) + +//! Add a handler for a method with 1 argument +#define FLEXT_ADDMETHOD_1(IX,M_TAG,M_FUN,TP1) \ +\ +AddMethod(IX,M_TAG,(methfun)(FLEXT_CALL_PRE(M_FUN)),FLEXTARG(TP1),a_null) + +//! Add a handler for a method with 2 arguments +#define FLEXT_ADDMETHOD_2(IX,M_TAG,M_FUN,TP1,TP2) \ +\ +AddMethod(IX,M_TAG,(methfun)(FLEXT_CALL_PRE(M_FUN)),FLEXTARG(TP1),FLEXTARG(TP2),a_null) + +//! Add a handler for a method with 3 arguments +#define FLEXT_ADDMETHOD_3(IX,M_TAG,M_FUN,TP1,TP2,TP3) \ +\ +AddMethod(IX,M_TAG,(methfun)(FLEXT_CALL_PRE(M_FUN)),FLEXTARG(TP1),FLEXTARG(TP2),FLEXTARG(TP3),a_null) + +//! Add a handler for a method with 4 arguments +#define FLEXT_ADDMETHOD_4(IX,M_TAG,M_FUN,TP1,TP2,TP3,TP4) \ +\ +AddMethod(IX,M_TAG,(methfun)(FLEXT_CALL_PRE(M_FUN)),FLEXTARG(TP1),FLEXTARG(TP2),FLEXTARG(TP3),FLEXTARG(TP4),a_null) + +//! Add a handler for a method with 5 arguments +#define FLEXT_ADDMETHOD_5(IX,M_TAG,M_FUN,TP1,TP2,TP3,TP4,TP5) \ +\ +AddMethod(IX,M_TAG,(methfun)(FLEXT_CALL_PRE(M_FUN)),FLEXTARG(TP1),FLEXTARG(TP2),FLEXTARG(TP3),FLEXTARG(TP4),FLEXTARG(TP5),a_null) + + +// Shortcuts + +//! Add a handler for a method with a boolean argument +#define FLEXT_ADDMETHOD_B(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_1(IX,M_TAG,M_FUN,bool) + +//! Add a handler for a method with 1 float argument +#define FLEXT_ADDMETHOD_F(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_1(IX,M_TAG,M_FUN,float) + +//! Add a handler for a method with 2 float arguments +#define FLEXT_ADDMETHOD_FF(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_2(IX,M_TAG,M_FUN,float,float) + +//! Add a handler for a method with 3 float arguments +#define FLEXT_ADDMETHOD_FFF(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_3(IX,M_TAG,M_FUN,float,float,float) + +//! Add a handler for a method with 1 integer argument +#define FLEXT_ADDMETHOD_I(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_1(IX,M_TAG,M_FUN,int) + +//! Add a handler for a method with 2 integer arguments +#define FLEXT_ADDMETHOD_II(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_2(IX,M_TAG,M_FUN,int,int) + +//! Add a handler for a method with 3 integer arguments +#define FLEXT_ADDMETHOD_III(IX,M_TAG,M_FUN) \ +\ +FLEXT_ADDMETHOD_3(IX,M_TAG,M_FUN,int,int,int) + +//! @} + + + +/*! \defgroup FLEXT_CALLMETHOD Call flext methods manually + These can only be used in class member functions! + + @{ +*/ + +//! Call a (already defined) method with no arguments +#define FLEXT_CALLMETHOD(M_FUN) \ +\ +FLEXT_CALL_PRE(M_FUN)(this) + +//! Call a (already defined) method with variable list arguments +#define FLEXT_CALLMETHOD_V(M_FUN,ARGC,ARGV) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARGC,ARGV) + +//! Call a (already defined) method with anything arguments +#define FLEXT_CALLMETHOD_A(M_FUN,HDR,ARGC,ARGV) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,HDR,ARGC,ARGV) + +//! Call a (already defined) method with a data package (void *) +#define FLEXT_CALLMETHOD_X(M_FUN,DATA) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,DATA) + +//! Call a (already defined) method with 1 enum type argument +#define FLEXT_CALLMETHOD_E(M_FUN,ARG) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARG) + +//! Call a (already defined) method with 1 argument +#define FLEXT_CALLMETHOD_1(M_FUN,ARG) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARG) + +//! Call a (already defined) method with 2 arguments +#define FLEXT_CALLMETHOD_2(M_FUN,ARG1,ARG2) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARG1,ARG2) + +//! Call a (already defined) method with 3 arguments +#define FLEXT_CALLMETHOD_3(M_FUN,ARG1,ARG2,ARG3) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARG1,ARG2,ARG3) + +//! Call a (already defined) method with 4 arguments +#define FLEXT_CALLMETHOD_4(M_FUN,ARG1,ARG2,ARG3,ARG4) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARG1,ARG2,ARG3,ARG4) + +//! Call a (already defined) method with 5 arguments +#define FLEXT_CALLMETHOD_5(M_FUN,ARG1,ARG2,ARG3,ARG4,ARG5) \ +\ +FLEXT_CALL_PRE(M_FUN)(this,ARG1,ARG2,ARG3,ARG4,ARG5) + +//! @} + + + +/*! \defgroup FLEXT_DEFATTR flext functions for attribute definition + + @{ +*/ + +#define FLEXT_CALLSET_(FUN,TP) \ +static bool FLEXT_SET_PRE(FUN)(flext_base *c,TP &arg) \ +{ FLEXT_CAST<thisType *>(c)->FUN(arg); return true; } + +#define FLEXT_CALLGET_(FUN,TP) \ +static bool FLEXT_GET_PRE(FUN)(flext_base *c,TP &arg) \ +{ FLEXT_CAST<thisType *>(c)->FUN(arg); return true; } + +#define FLEXT_ATTRSET_(VAR,TP) \ +static bool FLEXT_SET_PRE(VAR)(flext_base *c,TP &arg) \ +{ FLEXT_CAST<thisType *>(c)->VAR = arg; return true; } + +#define FLEXT_ATTRGET_(VAR,TP) \ +static bool FLEXT_GET_PRE(VAR)(flext_base *c,TP &arg) \ +{ arg = FLEXT_CAST<thisType *>(c)->VAR; return true; } + +#define FLEXT_CALLSET_F(SFUN) FLEXT_CALLSET_(SFUN,float) +#define FLEXT_CALLSET_I(SFUN) FLEXT_CALLSET_(SFUN,int) +#define FLEXT_CALLSET_S(SFUN) FLEXT_CALLSET_(SFUN,t_symptr) + +#define FLEXT_CALLSET_V(FUN) \ +static bool FLEXT_SET_PRE(FUN)(flext_base *c,AtomList *&arg) \ +{ FLEXT_CAST<thisType *>(c)->FUN(*arg); return true; } + +#define FLEXT_CALLGET_F(GFUN) FLEXT_CALLGET_(GFUN,float) +#define FLEXT_CALLGET_I(GFUN) FLEXT_CALLGET_(GFUN,int) +#define FLEXT_CALLGET_S(GFUN) FLEXT_CALLGET_(GFUN,t_symptr) + +#define FLEXT_CALLGET_V(FUN) \ +static bool FLEXT_GET_PRE(FUN)(flext_base *c,AtomList *&arg) \ +{ FLEXT_CAST<thisType *>(c)->FUN(*arg); return true; } + +#define FLEXT_CALLXFER_F(GFUN,SFUN) FLEXT_CALLGET_F(GFUN) FLEXT_CALLSET_F(SFUN) +#define FLEXT_CALLXFER_I(GFUN,SFUN) FLEXT_CALLGET_I(GFUN) FLEXT_CALLSET_I(SFUN) +#define FLEXT_CALLXFER_S(GFUN,SFUN) FLEXT_CALLGET_S(GFUN) FLEXT_CALLSET_S(SFUN) +#define FLEXT_CALLXFER_V(GFUN,SFUN) FLEXT_CALLGET_V(GFUN) FLEXT_CALLSET_V(SFUN) + +#define FLEXT_ATTRSET_F(VAR) FLEXT_ATTRSET_(VAR,float) +#define FLEXT_ATTRSET_I(VAR) FLEXT_ATTRSET_(VAR,int) +#define FLEXT_ATTRSET_S(VAR) FLEXT_ATTRSET_(VAR,t_symptr) + +#define FLEXT_ATTRSET_V(VAR) \ +static bool FLEXT_SET_PRE(VAR)(flext_base *c,AtomList *&arg) \ +{ FLEXT_CAST<thisType *>(c)->VAR = *arg; return true; } + +#define FLEXT_ATTRGET_F(VAR) FLEXT_ATTRGET_(VAR,float) +#define FLEXT_ATTRGET_I(VAR) FLEXT_ATTRGET_(VAR,int) +#define FLEXT_ATTRGET_S(VAR) FLEXT_ATTRGET_(VAR,t_symptr) + +#define FLEXT_ATTRGET_V(VAR) \ +static bool FLEXT_GET_PRE(VAR)(flext_base *c,AtomList *&arg) \ +{ *arg = FLEXT_CAST<thisType *>(c)->VAR; return true; } + +#define FLEXT_ATTRXFER_F(VAR) FLEXT_ATTRGET_F(VAR) FLEXT_ATTRSET_F(VAR) +#define FLEXT_ATTRXFER_I(VAR) FLEXT_ATTRGET_I(VAR) FLEXT_ATTRSET_I(VAR) +#define FLEXT_ATTRXFER_S(VAR) FLEXT_ATTRGET_S(VAR) FLEXT_ATTRSET_S(VAR) +#define FLEXT_ATTRXFER_V(VAR) FLEXT_ATTRGET_V(VAR) FLEXT_ATTRSET_V(VAR) + +//! @} + +/*! \defgroup FLEXT_ADDATTR flext methods for defining attributes + These can only be used in class member functions! + + @{ +*/ + +#define FLEXT_ADDATTR_GET(NAME,GFUN) AddAttrib(NAME,(FLEXT_GET_PRE(GFUN)),NULL) +#define FLEXT_ADDATTR_SET(NAME,SFUN) AddAttrib(NAME,NULL,(FLEXT_SET_PRE(SFUN))) +#define FLEXT_ADDATTRIB(NAME,FUN) AddAttrib(NAME,(FLEXT_GET_PRE(FUN)),(FLEXT_SET_PRE(FUN))) + +//! @} + + + + +#endif // __FLEXT_DEFS_H diff --git a/externals/grill/flext/source/fldoxygen.h b/externals/grill/flext/source/fldoxygen.h new file mode 100644 index 00000000..bae97b44 --- /dev/null +++ b/externals/grill/flext/source/fldoxygen.h @@ -0,0 +1,22 @@ +#ifndef __FLEXT_DOXYGEN_H +#define __FLEXT_DOXYGEN_H + +/*! \file fldoxygen.h + \brief Doxygen definitions + \remark There is no code in here, just documentation stuff. +*/ + +/*! \mainpage flext - C++ layer for cross-platform development of PD and Max/MSP objects + + \section intro Introduction + + This is the introduction + + \section install Installation + + \subsection step1 Step 1: Opening the box + + etc... +*/ + +#endif diff --git a/externals/grill/flext/source/fldsp.cpp b/externals/grill/flext/source/fldsp.cpp new file mode 100644 index 00000000..fc5db717 --- /dev/null +++ b/externals/grill/flext/source/fldsp.cpp @@ -0,0 +1,119 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file fldsp.cpp + \brief Implementation of the flext dsp base class. +*/ + +#include "flext.h" +#include "flinternal.h" +#include <string.h> + + + +// === flext_dsp ============================================== + +void flext_dsp::Setup(t_class *c) +{ +#ifdef PD +// CLASS_MAINSIGNALIN(c,flext_hdr,defsig); +#elif defined(MAXMSP) +// dsp_initclass(); + dsp_initboxclass(); +#endif + + add_dsp(c,cb_dsp); +#ifndef MAXMSP + add_method1(c,cb_enable,"enable",A_FLINT); +#endif +} + +flext_dsp::flext_dsp(): +#ifndef MAXMSP + dspon(true), +#endif + srate(sys_getsr()), // should we set it? + blksz(sys_getblksize()), +#ifdef PD + chnsin(sys_get_inchannels()), + chnsout(sys_get_outchannels()), +#else // MAXMSP + chnsin(sys_getch()), + chnsout(sys_getch()), +#endif + invecs(NULL),outvecs(NULL) +{} + + +flext_dsp::~flext_dsp() +{ + if(invecs) delete[] invecs; + if(outvecs) delete[] outvecs; +} + + +t_int *flext_dsp::dspmeth(t_int *w) +{ + flext_dsp *obj = (flext_dsp *)w[1]; +#ifdef MAXMSP + if(!obj->thisHdr()->z_disabled) +#else + if(obj->dspon) +#endif + obj->m_signal((int)w[2],obj->invecs,obj->outvecs); + return w+3; +} + +void flext_dsp::m_dsp(int /*n*/,t_sample *const * /*insigs*/,t_sample *const * /*outsigs*/) {} + +void flext_dsp::m_signal(int n,t_sample *const * /*insigs*/,t_sample *const *outsigs) +{ + for(int i = 0; i < CntOutSig(); ++i) + memset(outsigs[i],0,n*sizeof(*outsigs[i])); +} + +void flext_dsp::cb_dsp(t_class *c,t_signal **sp) +{ + flext_dsp *obj = thisObject(c); + + // store current dsp parameters + obj->srate = sp[0]->s_sr; + obj->blksz = sp[0]->s_n; // is this guaranteed to be the same as sys_getblksize() ? + +#ifdef PD + obj->chnsin = sys_get_inchannels(); + obj->chnsout = sys_get_outchannels(); +#else // MAXMSP + obj->chnsin = obj->chnsout = sys_getch(); +#endif + + // store in and out signal vectors + int i,in = obj->CntInSig(),out = obj->CntOutSig(); + if(obj->invecs) delete[] obj->invecs; + obj->invecs = new t_sample *[in]; + for(i = 0; i < in; ++i) obj->invecs[i] = sp[i]->s_vec; + + if(obj->outvecs) delete[] obj->outvecs; + obj->outvecs = new t_sample *[out]; + for(i = 0; i < out; ++i) obj->outvecs[i] = sp[in+i]->s_vec; + + // with the following call derived classes can do their eventual DSP setup + obj->m_dsp(sp[0]->s_n,obj->invecs,obj->outvecs); + + // set the DSP function + dsp_add((t_dspmethod)dspmeth,2,obj,sp[0]->s_n); +} + +#ifndef MAXMSP +void flext_dsp::cb_enable(t_class *c,t_flint on) { thisObject(c)->m_enable(on != 0); } +void flext_dsp::m_enable(bool en) { dspon = en; } +#endif + + diff --git a/externals/grill/flext/source/fldsp.h b/externals/grill/flext/source/fldsp.h new file mode 100644 index 00000000..70c88745 --- /dev/null +++ b/externals/grill/flext/source/fldsp.h @@ -0,0 +1,140 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file fldsp.h + \brief Declares the flext dsp class + +*/ + +#ifndef __FLDSP_H +#define __FLDSP_H + +// include the header file declaring the base classes +#include "flext.h" + + +// === flext_dsp ================================================== + +/*! \brief Flext dsp enabled base object +*/ +class flext_dsp: + public flext_base +{ + FLEXT_HEADER_S(flext_dsp,flext_base,Setup) + +public: + +/*! \defgroup FLEXT_C_DSP Flext basic dsp functionality + + @{ +*/ + + //! returns current sample rate + float Samplerate() const { return srate; } + + //! returns current block (aka vector) size + int Blocksize() const { return blksz; } + + /*! \brief returns number of audio system input channels + \bug Doesn't work in Max/MSP - is always 0 + */ + int ChannelsIn() const { return chnsin; } + + /*! \brief returns number of audio system output channels + \bug Doesn't work in Max/MSP - is always 0 + */ + int ChannelsOut() const { return chnsout; } + +//! @} + + +// --- inheritable virtual methods -------------------------------- + +/*! \defgroup FLEXT_C_VIRTUAL_DSP Flext virtual dsp functions + + @{ +*/ + /*! \brief Called on every dsp init. + \note Don't expect any valid data in the signal vectors! + + \param n: frames (aka samples) in one signal vector + \param insigs: array of input vectors (get number with function CntInSig()) + \param outsigs: array of output vectors (get number with function CntOutSig()) + */ + virtual void m_dsp(int n,t_sample *const *insigs,t_sample *const *outsigs); + + /*! \brief Called with every signal vector - here you do the dsp calculation + + \param n: frames (aka samples) in one signal vector + \param insigs: array of input vectors (get number with function CntInSig()) + \param outsigs: array of output vectors (get number with function CntOutSig()) + */ + virtual void m_signal(int n,t_sample *const *insigs,t_sample *const *outsigs); + +#ifndef MAXMSP + /*! \brief called with "enable" message: pauses/resumes dsp + \note PD only - implicitely defined in MaxMSP + */ + virtual void m_enable(bool on); +#endif + +//! @} + + +/*! \defgroup FLEXT_C_INOUT_DSP Flext dsp in-/outlet functions + \note These must be called in the class' constructor + + @{ +*/ +// --- inlet/outlet stuff ----------------------------------------- + + /*! \brief Add signal inlet(s) + \param m Number of inlets to add + */ + void AddInSignal(int m = 1) { AddInlet(xlet::tp_sig,m); } + + /*! \brief Add signal outlet(s) + \param m Number of inlets to add + */ + void AddOutSignal(int m = 1) { AddOutlet(xlet::tp_sig,m); } + +//! @} + + +protected: + + flext_dsp(); + virtual ~flext_dsp(); + +private: + + // not static, could be different in different patchers.. + float srate; + int blksz; + int chnsin,chnsout; + + // setup function + static void Setup(t_class *c); + + // callback functions + + static void cb_dsp(t_class *c,t_signal **s); +#ifndef MAXMSP + static void cb_enable(t_class *c,t_flint on); + bool dspon; +#endif + + // dsp stuff + + static t_int *dspmeth(t_int *w); + t_sample **invecs,**outvecs; +}; + +#endif diff --git a/externals/grill/flext/source/flext.cpp b/externals/grill/flext/source/flext.cpp new file mode 100644 index 00000000..5ed852c3 --- /dev/null +++ b/externals/grill/flext/source/flext.cpp @@ -0,0 +1,748 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flext.cpp + \brief Implementation of the flext base class. +*/ + +#include "flext.h" +#include "flinternal.h" +#include <string.h> +#include <stdarg.h> + + +// === proxy class for flext_base ============================ + +#ifdef PD + +static t_class *px_class; + +struct flext_base::px_object // no virtual table! +{ + t_object obj; // MUST reside at memory offset 0 + flext_base *base; + int index; + + void init(flext_base *b,int ix) { base = b; index = ix; } + static void px_method(px_object *c,const t_symbol *s,int argc,t_atom *argv); +}; + + +void flext_base::px_object::px_method(px_object *obj,const t_symbol *s,int argc,t_atom *argv) +{ + obj->base->m_methodmain(obj->index,s,argc,argv); +} + +void flext_base::cb_px_anything(t_class *c,const t_symbol *s,int argc,t_atom *argv) +{ + thisObject(c)->m_methodmain(0,s,argc,argv); +} + +#define DEF_IN_FT(IX) \ +void flext_base::cb_px_ft ## IX(t_class *c,float v) { \ + t_atom atom; SETFLOAT(&atom,v); \ + thisObject(c)->m_methodmain(IX,&s_float,1,&atom); \ +} + +#define ADD_IN_FT(IX) \ +add_method1(c,cb_px_ft ## IX,"ft" #IX,A_FLOAT) + +#elif defined(MAXMSP) + +void flext_base::cb_px_anything(t_class *c,const t_symbol *s,int argc,t_atom *argv) +{ + // check if inlet allows anything (or list) + + flext_base *o = thisObject(c); + int ci = ((flext_hdr *)o->x_obj)->curinlet; + + o->m_methodmain(ci,s,argc,argv); +} + +void flext_base::cb_px_int(t_class *c,int v) +{ + // check if inlet allows int type + t_atom atom; + SETINT(&atom,v); + cb_px_anything(c,sym_int,1,&atom); +} + +void flext_base::cb_px_float(t_class *c,float v) +{ + // check if inlet allows float type + t_atom atom; + SETFLOAT(&atom,v); + cb_px_anything(c,sym_float,1,&atom); +} + +void flext_base::cb_px_bang(t_class *c) +{ + // check if inlet allows bang + cb_px_anything(c,sym_bang,0,NULL); +} + + +#define DEF_IN_FT(IX) \ +void flext_base::cb_px_in ## IX(t_class *c,int v) { long &ci = ((flext_hdr *)thisObject(c)->x_obj)->curinlet; ci = IX; cb_px_int(c,v); ci = 0; } \ +void flext_base::cb_px_ft ## IX(t_class *c,float v) { long &ci = ((flext_hdr *)thisObject(c)->x_obj)->curinlet; ci = IX; cb_px_float(c,v); ci = 0; } + +#define ADD_IN_FT(IX) \ +add_method1(c,cb_px_in ## IX,"in" #IX,A_INT); \ +add_method1(c,cb_px_ft ## IX,"ft" #IX,A_FLOAT) + +#endif // MAXMSP + + +DEF_IN_FT(1) +DEF_IN_FT(2) +DEF_IN_FT(3) +DEF_IN_FT(4) +DEF_IN_FT(5) +DEF_IN_FT(6) +DEF_IN_FT(7) +DEF_IN_FT(8) +DEF_IN_FT(9) + + + +// === flext_base ============================================ + +bool flext_base::compatibility = true; + +flext_base::flext_base(): + inlist(NULL),outlist(NULL), + incnt(0),outcnt(0), + insigs(0),outsigs(0), + curtag(NULL), + outlets(NULL),inlets(NULL),outattr(NULL), + methhead(NULL),attrhead(NULL),attrcnt(0), + distmsgs(false) +{ + LOG1("%s - flext logging is on",thisName()); + +#ifdef FLEXT_THREADS + thrid = pthread_self(); + + shouldexit = false; + thrhead = thrtail = NULL; +#endif + qhead = qtail = NULL; + qclk = (t_qelem *)(qelem_new(this,(t_method)QTick)); +#ifdef MAXMSP + yclk = (t_clock *)(clock_new(this,(t_method)YTick)); +#endif + + AddMethod(0,"getattributes",(methfun)cb_ListAttrib); +} + +flext_base::~flext_base() +{ +#ifdef FLEXT_THREADS + // wait for thread termination + shouldexit = true; + for(int wi = 0; thrhead && wi < 100; ++wi) Sleep(0.01f); + +#ifdef PD + qmutex.Lock(); // Lock message queue + tlmutex.Lock(); + // timeout -> hard termination + while(thrhead) { + thr_entry *t = thrhead; + if(pthread_cancel(t->thrid)) post("%s - Thread could not be terminated!",thisName()); + thrhead = t->nxt; + t->nxt = NULL; delete t; + } + tlmutex.Unlock(); + qmutex.Unlock(); +#else +#pragma message ("No tread cancelling") +#endif + +#endif + + // send remaining pending messages + while(qhead) QTick(this); + qelem_free((t_qelem *)qclk); +#ifdef MAXMSP + clock_free((object *)yclk); +#endif + + if(inlist) delete inlist; + if(outlist) delete outlist; + if(outlets) delete[] outlets; + + if(inlets) { + for(int ix = 0; ix < incnt; ++ix) + if(inlets[ix]) { +#ifdef PD + pd_free(&inlets[ix]->obj.ob_pd); +#elif defined(MAXMSP) + freeobject((object *)inlets[ix]); +#endif + } + delete[] inlets; + } + +#ifdef MAXMSP +// if(insigs) dsp_free(thisHdr()); + if(insigs) dsp_freebox(thisHdr()); +#endif + + if(methhead) delete methhead; + if(attrhead) delete attrhead; +} + + +bool flext_base::Init() +{ +// if(!flext_obj::Init()) return false; + + bool ok = true; + + incnt = insigs = 0; + + if(inlets) { + for(int ix = 0; ix < incnt; ++ix) + if(inlets[ix]) { +#ifdef PD + pd_free(&inlets[ix]->obj.ob_pd); +#elif defined(MAXMSP) + freeobject(inlets[ix]); +#endif + } + delete[] inlets; + inlets = NULL; + } + + if(inlist) { + xlet *xi; + incnt = 0; + for(xi = inlist; xi; xi = xi->nxt) ++incnt; + xlet::type *list = new xlet::type[incnt]; + int i; + for(xi = inlist,i = 0; xi; xi = xi->nxt,++i) list[i] = xi->tp; + delete inlist; inlist = NULL; + + inlets = new px_object *[incnt]; + for(i = 0; i < incnt; ++i) inlets[i] = NULL; + + // type info is now in list array +#ifdef PD + { + int cnt = 0; + + if(incnt >= 1) { + switch(list[0]) { + case xlet::tp_sig: + CLASS_MAINSIGNALIN(thisClass(),flext_hdr,defsig); + ++insigs; + break; + default: + // leftmost inlet is already there... + break; + } + ++cnt; + } + + for(int ix = 1; ix < incnt; ++ix,++cnt) { + switch(list[ix]) { + case xlet::tp_float: + case xlet::tp_int: { + char sym[] = "ft??"; + if(ix >= 10) { + if(compatibility) { + // Max allows max. 9 inlets + post("%s: Only 9 float/int inlets allowed in compatibility mode",thisName()); + ok = false; + } + else { + if(ix > 99) + post("%s: Inlet index > 99 not allowed for float/int inlets",thisName()); + sym[2] = '0'+ix/10,sym[3] = '0'+ix%10; + } + } + else + sym[2] = '0'+ix,sym[3] = 0; + if(ok) inlet_new(&x_obj->obj, &x_obj->obj.ob_pd, &s_float, gensym(sym)); + break; + } + case xlet::tp_sym: + (inlets[ix] = (px_object *)pd_new(px_class))->init(this,ix); // proxy for 2nd inlet messages + inlet_new(&x_obj->obj,&inlets[ix]->obj.ob_pd, &s_symbol, &s_symbol); + break; + case xlet::tp_list: + (inlets[ix] = (px_object *)pd_new(px_class))->init(this,ix); // proxy for 2nd inlet messages + inlet_new(&x_obj->obj,&inlets[ix]->obj.ob_pd, &s_list, &s_list); + break; + case xlet::tp_any: + (inlets[ix] = (px_object *)pd_new(px_class))->init(this,ix); // proxy for 2nd inlet messages + inlet_new(&x_obj->obj,&inlets[ix]->obj.ob_pd, 0, 0); + break; + case xlet::tp_sig: + if(compatibility && list[ix-1] != xlet::tp_sig) { + post("%s: All signal inlets must be left-aligned in compatibility mode",thisName()); + ok = false; + } + else { + // pd doesn't seem to be able to handle signals and messages into the same inlet... + + inlet_new(&x_obj->obj, &x_obj->obj.ob_pd, &s_signal, &s_signal); + ++insigs; + } + break; + default: + error("%s: Wrong type for inlet #%i: %i",thisName(),ix,(int)list[ix]); + ok = false; + } + } + + incnt = cnt; + } +#elif defined(MAXMSP) + { + int ix,cnt; + // count leftmost signal inlets + while(insigs < incnt && list[insigs] == xlet::tp_sig) ++insigs; + + for(cnt = 0,ix = incnt-1; ix >= insigs; --ix,++cnt) { + if(ix == 0) { + if(list[ix] != xlet::tp_any) { + error("%s: Leftmost inlet must be of type signal or default",thisName()); + ok = false; + } + } + else { + switch(list[ix]) { + case xlet::tp_sig: + error("%s: All signal inlets must be at the left side",thisName()); + ok = false; + break; + case xlet::tp_float: + if(ix >= 10) { + post("%s: Only 9 float inlets possible",thisName()); + ok = false; + } + else + floatin(x_obj,ix); + break; + case xlet::tp_int: + if(ix >= 10) { + post("%s: Only 9 int inlets possible",thisName()); + ok = false; + } + else + intin(x_obj,ix); + break; + case xlet::tp_any: // non-leftmost + case xlet::tp_sym: + case xlet::tp_list: + inlets[ix] = (px_object *)proxy_new(x_obj,ix,&((flext_hdr *)x_obj)->curinlet); + break; + default: + error("%s: Wrong type for inlet #%i: %i",thisName(),ix,(int)list[ix]); + ok = false; + } + } + } + + incnt = cnt; + + if(insigs) +// dsp_setup(thisHdr(),insigs); // signal inlets + dsp_setupbox(thisHdr(),insigs); // signal inlets + } +#endif + + delete[] list; + } + + if(outlets) { delete[] outlets; outlets = NULL; } + outcnt = outsigs = 0; + + if(outlist) { + xlet *xi; + + // count outlets + outcnt = 0; + for(xi = outlist; xi; xi = xi->nxt) ++outcnt; + + xlet::type *list = new xlet::type[outcnt]; + int i; + for(xi = outlist,i = 0; xi; xi = xi->nxt,++i) list[i] = xi->tp; + delete outlist; outlist = NULL; + + outlets = new outlet *[outcnt]; + + // type info is now in list array +#ifdef PD + for(int ix = 0; ix < outcnt; ++ix) +#elif defined(MAXMSP) + for(int ix = outcnt-1; ix >= 0; --ix) +#endif + { + switch(list[ix]) { + case xlet::tp_float: + outlets[ix] = (outlet *)newout_float(&x_obj->obj); + break; + case xlet::tp_int: + outlets[ix] = (outlet *)newout_flint(&x_obj->obj); + break; + case xlet::tp_sig: + outlets[ix] = (outlet *)newout_signal(&x_obj->obj); + ++outsigs; + break; + case xlet::tp_sym: + outlets[ix] = (outlet *)newout_symbol(&x_obj->obj); + break; + case xlet::tp_list: + outlets[ix] = (outlet *)newout_list(&x_obj->obj); + break; + case xlet::tp_any: + outlets[ix] = (outlet *)newout_anything(&x_obj->obj); + break; +#ifdef _DEBUG + default: + ERRINTERNAL(); + ok = false; +#endif + } + } + + delete[] list; + } + + if(procattr) + // attribute dump outlet is the last one + outattr = (outlet *)newout_anything(&x_obj->obj); + + return ok; +} + +void flext_base::Setup(t_class *c) +{ + add_method(c,cb_help,"help"); + add_loadbang(c,cb_loadbang); +#ifdef MAXMSP + add_assist(c,cb_assist); +#endif + + // proxy for extra inlets +#ifdef PD + add_anything(c,cb_px_anything); // for leftmost inlet + px_class = class_new(gensym("flext_base proxy"),NULL,NULL,sizeof(px_object),CLASS_PD|CLASS_NOINLET, A_NULL); + add_anything(px_class,px_object::px_method); // for other inlets +#elif defined(MAXMSP) + add_bang(c,cb_px_bang); + add_method1(c,cb_px_int,"int",A_INT); + add_method1(c,cb_px_float,"float",A_FLOAT); + add_methodG(c,cb_px_anything,"list"); + add_anything(c,cb_px_anything); +#endif + + // setup non-leftmost ints and floats + ADD_IN_FT(1); + ADD_IN_FT(2); + ADD_IN_FT(3); + ADD_IN_FT(4); + ADD_IN_FT(5); + ADD_IN_FT(6); + ADD_IN_FT(7); + ADD_IN_FT(8); + ADD_IN_FT(9); +} + +void flext_base::cb_help(t_class *c) { thisObject(c)->m_help(); } + +void flext_base::cb_loadbang(t_class *c) { thisObject(c)->m_loadbang(); } +#ifdef MAXMSP +void flext_base::cb_assist(t_class *c,void * /*b*/,long msg,long arg,char *s) { thisObject(c)->m_assist(msg,arg,s); } +#endif + +void flext_base::m_help() +{ + // This should better be overloaded + post("%s (using flext " FLEXT_VERSTR ") - compiled on %s %s",thisName(),__DATE__,__TIME__); +} + + +bool flext_base::m_methodmain(int inlet,const t_symbol *s,int argc,t_atom *argv) +{ + static bool trap = false; + bool ret = false; + + curtag = s; + + LOG3("methodmain inlet:%i args:%i symbol:%s",inlet,argc,s?s->s_name:""); + + for(const methitem *m = methhead; m && !ret; m = m->nxt) { + if(m->tag == s && (inlet == m->inlet || m->inlet < 0 )) { + // tag fits + LOG4("found method tag %s: inlet=%i, symbol=%s, argc=%i",m->tag->s_name,inlet,s->s_name,argc); + + if(m->argc == 1 && m->args[0] == a_list) { + ret = ((methfun_V)m->fun)(this,argc,argv); + } + else if(m->argc == 1 && m->args[0] == a_any) { + ret = ((methfun_A)m->fun)(this,s,argc,argv); + } + else if(argc == m->argc) { + int ix; + t_any aargs[FLEXT_MAXMETHARGS]; + bool ok = true; + for(ix = 0; ix < argc && ok; ++ix) { + switch(m->args[ix]) { + case a_float: { + if(IsFloat(argv[ix])) aargs[ix].ft = GetFloat(argv[ix]); + else if(IsInt(argv[ix])) aargs[ix].ft = (float)GetInt(argv[ix]); + else ok = false; + + if(ok) LOG2("int arg %i = %f",ix,aargs[ix].ft); + break; + } + case a_int: { + if(IsFloat(argv[ix])) aargs[ix].it = (int)GetFloat(argv[ix]); + else if(IsInt(argv[ix])) aargs[ix].it = GetInt(argv[ix]); + else ok = false; + + if(ok) LOG2("float arg %i = %i",ix,aargs[ix].it); + break; + } + case a_symbol: { + if(IsSymbol(argv[ix])) aargs[ix].st = GetSymbol(argv[ix]); + else ok = false; + + if(ok) LOG2("symbol arg %i = %s",ix,GetString(aargs[ix].st)); + break; + } +#ifdef PD + case a_pointer: { + if(IsPointer(argv[ix])) aargs[ix].pt = GetPointer(argv[ix]); + else ok = false; + break; + } +#endif + default: + error("Argument type illegal"); + ok = false; + } + } + + if(ok && ix == argc) { + switch(argc) { + case 0: ret = ((methfun_0)m->fun)(this); break; + case 1: ret = ((methfun_1)m->fun)(this,aargs[0]); break; + case 2: ret = ((methfun_2)m->fun)(this,aargs[0],aargs[1]); break; + case 3: ret = ((methfun_3)m->fun)(this,aargs[0],aargs[1],aargs[2]); break; + case 4: ret = ((methfun_4)m->fun)(this,aargs[0],aargs[1],aargs[2],aargs[3]); break; + case 5: ret = ((methfun_5)m->fun)(this,aargs[0],aargs[1],aargs[2],aargs[3],aargs[4]); break; + } + } + } + } + else if(m->tag == sym_symbol && !argc && (inlet == m->inlet || m->inlet < 0 )) { + // symbol + LOG3("found symbol method for %s: inlet=%i, symbol=%s",m->tag->s_name,inlet,s->s_name); + + t_any sym; sym.st = const_cast<t_symbol *>(s); + ret = ((methfun_1)m->fun)(this,sym); + } + else if(m->tag == sym_anything && (inlet == m->inlet || m->inlet < 0) && m->argc == 1 && m->args[0] == a_any) { + // any + LOG4("found any method for %s: inlet=%i, symbol=%s, argc=%i",m->tag->s_name,inlet,s->s_name,argc); + + ret = ((methfun_A)m->fun)(this,s,argc,argv); + } + } + +#ifdef MAXMSP + // If float message is not explicitly handled: try int handler instead + if(!ret && argc == 1 && s == sym_float && !trap) { + t_atom fl; + SetInt(fl,GetAInt(argv[0])); + trap = true; + ret = m_methodmain(inlet,sym_int,1,&fl); + trap = false; + } + + // If int message is not explicitly handled: try float handler instead + if(!ret && argc == 1 && s == sym_int && !trap) { + t_atom fl; + SetFloat(fl,GetAFloat(argv[0])); + trap = true; + ret = m_methodmain(inlet,sym_float,1,&fl); + trap = false; + } +#endif + + // If float or int message is not explicitly handled: try list handler instead + if(!ret && !trap && argc == 1 && (s == sym_float +#ifdef MAXMSP + || s == sym_int +#endif + )) { + t_atom list; + if(s == sym_float) + SetFloat(list,GetFloat(argv[0])); +#ifdef MAXMSP + else if(s == sym_int) + SetInt(list,GetInt(argv[0])); +#endif + + trap = true; + ret = m_methodmain(inlet,sym_list,1,&list); + trap = false; + } + + // If symbol message (pure anything without args) is not explicitly handled: try list handler instead + if(!ret && !trap && argc == 0) { + t_atom list; + SetSymbol(list,s); + trap = true; + ret = m_methodmain(inlet,sym_list,1,&list); + trap = false; + } + + // if distmsgs is switched on then distribute list elements over inlets (Max/MSP behavior) + if(!ret && distmsgs && !trap && inlet == 0 && s == sym_list && insigs <= 1) { + int i = incnt; + if(i > argc) i = argc; + for(--i; i >= 0; --i) { // right to left distribution + const t_symbol *sym = NULL; + if(IsFloat(argv[i])) sym = sym_float; + else if(IsInt(argv[i])) sym = sym_int; + else if(IsSymbol(argv[i])) sym = sym_symbol; +#ifdef PD + else if(IsPointer(argv[i])) sym = sym_pointer; // can pointer atoms occur here? +#endif + if(sym) { + trap = true; + m_methodmain(i,sym,1,argv+i); + trap = false; + } + } + + ret = true; + } + + if(!ret && !trap) ret = m_method_(inlet,s,argc,argv); + + curtag = NULL; + + return ret; // true if appropriate handler was found and called +} + +bool flext_base::m_method_(int inlet,const t_symbol *s,int argc,t_atom *argv) +{ +//#ifdef _DEBUG + post("%s: message unhandled - inlet:%i args:%i symbol:%s",thisName(),inlet,argc,s?s->s_name:""); +//#endif + return false; +} + + +flext_base::methitem::methitem(int in,const t_symbol *t): + inlet(in),tag(t), + fun(NULL), + argc(0),args(NULL), + nxt(NULL) +{} + +flext_base::methitem::~methitem() +{ + if(nxt) delete nxt; + if(args) delete[] args; +} + +void flext_base::methitem::SetArgs(methfun _fun,int _argc,metharg *_args) +{ + fun = _fun; + if(args) delete[] args; + argc = _argc,args = _args; +} + + + +void flext_base::AddMethItem(methitem *m) +{ + if(methhead) { + methitem *mi; + for(mi = methhead; mi->nxt; mi = mi->nxt) {} + mi->nxt = m; + } + else + methhead = m; +} +/* +const flext_base::methitem *flext_base::FindMethItem(int inlet,const t_symbol *tag,const methitem *st) +{ + const methitem *mi = st?st:mlst; + if(inlet < 0) { + for(; mi; mi = mi->nxt) + if(mi->tag == tag) break; + } + else { + for(; mi; mi = mi->nxt) + if(mi->inlet == inlet && mi->tag == tag) break; + } + return mi; +} +*/ + +void flext_base::AddMethodDef(int inlet,const char *tag) +{ + AddMethItem(new methitem(inlet,tag?MakeSymbol(tag):NULL)); +} + +void flext_base::AddMethod(int inlet,const char *tag,methfun fun,metharg tp,...) +{ + methitem *mi = new methitem(inlet,MakeSymbol(tag)); + + va_list marker; + + // at first just count the arg type list (in argc) + int argc = 0; + va_start(marker,tp); + metharg *args = NULL,arg = tp; + for(; arg != a_null; ++argc) arg = (metharg)va_arg(marker,int); //metharg); + va_end(marker); + + if(argc > 0) { + if(argc > FLEXT_MAXMETHARGS) { + error("%s - method %s: only %i arguments are type-checkable: use variable argument list for more",thisName(),tag?tag:"?",FLEXT_MAXMETHARGS); + argc = FLEXT_MAXMETHARGS; + } + + args = new metharg[argc]; + + va_start(marker,tp); + metharg a = tp; + for(int ix = 0; ix < argc; ++ix) { +#ifdef _DEBUG + if(a == a_list && ix > 0) { + ERRINTERNAL(); + } +#endif +#ifdef PD + if(a == a_pointer && flext_base::compatibility) { + post("Pointer arguments are not allowed in compatibility mode"); + } +#endif + args[ix] = a; + a = (metharg)va_arg(marker,int); //metharg); + } + va_end(marker); + } + + mi->SetArgs(fun,argc,args); + + AddMethItem(mi); +} + + diff --git a/externals/grill/flext/source/flext.h b/externals/grill/flext/source/flext.h new file mode 100644 index 00000000..fd99f253 --- /dev/null +++ b/externals/grill/flext/source/flext.h @@ -0,0 +1,45 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flext.h + \brief This is the main flext include file. + + The basic definitions are set here and the necessary header files are included +*/ + +#ifndef __FLEXT_H +#define __FLEXT_H + + +/*! \defgroup FLEXT_GLOBAL Flext global definitions + @{ +*/ + +//! \brief flext version number +#define FLEXT_VERSION 400 + +//! \brief flext version string +#define FLEXT_VERSTR "0.4.0pre" + +//! @} + + +// include all the flext interface definitions +#include "fldefs.h" + +// include the basic flext object classes +#include "flclass.h" + +// include the flext dsp class +#include "fldsp.h" + +#endif // FLEXT_H + + diff --git a/externals/grill/flext/source/flinternal.h b/externals/grill/flext/source/flinternal.h new file mode 100644 index 00000000..20989b1b --- /dev/null +++ b/externals/grill/flext/source/flinternal.h @@ -0,0 +1,111 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flinternal.h + \brief Definitions for internal flext usage + \internal + + Here, a few shortcuts for common MaxMSP or PD library calls and type definitions + are declared +*/ + +#ifndef __FLEXT_INTERNALS_H +#define __FLEXT_INTERNALS_H + +#include "flstdc.h" + + +#ifdef PD + +#define object_new(clss) pd_new(clss) +#define object_free(obj) pd_free(&(obj).ob_pd) + + + +#define add_dsp(clss,meth) class_addmethod(clss, (t_method)meth,gensym("dsp"),A_NULL) +#define add_bang(clss,meth) class_addbang(clss, (t_method)meth) +#define add_float(clss,meth) class_addfloat(clss, (t_method)meth) +#define add_floatn(clss,meth,n) class_addmethod(clss, (t_method)meth,gensym("ft" #n),A_FLOAT,A_NULL) +#define add_flint(clss,meth) class_addfloat(clss, (t_method)meth) +#define add_flintn(clss,meth,n) class_addmethod(clss, (t_method)meth,gensym("ft" #n),A_FLOAT,A_NULL) +#define add_method(clss,meth,text) class_addmethod(clss, (t_method)meth, gensym(text), A_NULL) +#define add_methodG(clss,meth,text) class_addmethod(clss, (t_method)meth, gensym(text), A_GIMME,A_NULL) +#define add_method1(clss,meth,text,a1) class_addmethod(clss, (t_method)meth, gensym(text), a1,A_NULL) +#define add_method2(clss,meth,text,a1,a2) class_addmethod(clss, (t_method)meth, gensym(text), a1,a2,A_NULL) +#define add_method3(clss,meth,text,a1,a2,a3) class_addmethod(clss, (t_method)meth, gensym(text), a1,a2,a3,A_NULL) +#define add_method4(clss,meth,text,a1,a2,a3,a4) class_addmethod(clss, (t_method)meth, gensym(text), a1,a2,a3,a4,A_NULL) +#define add_method5(clss,meth,text,a1,a2,a3,a5) class_addmethod(clss, (t_method)meth, gensym(text), a1,a2,a3,a4,a5,A_NULL) +#define add_loadbang(clss,meth) class_addmethod(clss,(t_method)meth, gensym("loadbang"), A_CANT, A_NULL) +#define add_anything(clss,meth) class_addanything(clss,meth) + + +#define newout_signal(clss) outlet_new(clss,&s_signal) +#define newout_float(clss) outlet_new(clss,&s_float) +#define newout_flint(clss) outlet_new(clss,&s_float) +#define newout_list(clss) outlet_new(clss,&s_list) +#define newout_symbol(clss) outlet_new(clss,&s_symbol) +#define newout_anything(clss) outlet_new(clss,&s_anything) + +#define outlet_flint(o,v) outlet_float(o,(float)(v)) + +typedef t_perfroutine t_dspmethod; + +#define qelem_new clock_new +#define qelem_free clock_free +#define qelem_set clock_set +#define qelem_unset clock_unset + +#elif defined(MAXMSP) + +/* +typedef void _inlet; +typedef _inlet t_inlet; +*/ + +typedef void t_outlet; +//typedef _outlet t_outlet; + +#define object_new(clss) pd_new(clss) +#define object_free(obj) freeobject((object *)obj) + +#define add_dsp(clss,meth) addmess((method)meth,"dsp",A_CANT,A_NOTHING) +#define add_bang(clss,meth) addbang((method)meth) +#define add_float(clss,meth) addfloat((method)meth) +#define add_floatn(clss,meth,n) addftx((method)meth,n) +#define add_flint(clss,meth) addint((method)meth) +#define add_flintn(clss,meth,n) addinx((method)meth,n) +#define add_method(clss,meth,text) addmess((method)meth, text, A_NOTHING) +#define add_methodG(clss,meth,text) addmess((method)meth, text, A_GIMME,A_NOTHING) +#define add_method1(clss,meth,text,a1) addmess((method)meth, text, a1,A_NOTHING) +#define add_method2(clss,meth,text,a1,a2) addmess((method)meth, text, a1,a2,A_NOTHING) +#define add_method3(clss,meth,text,a1,a2,a3) addmess((method)meth, text, a1,a2,a3,A_NOTHING) +#define add_method4(clss,meth,text,a1,a2,a3,a4) addmess((method)meth, text, a1,a2,a3,a4,A_NOTHING) +#define add_method5(clss,meth,text,a1,a2,a3,a5) addmess((method)meth, text, a1,a2,a3,a4,a5,A_NOTHING) +#define add_anything(clss,meth) addmess((method)meth, "anything", A_GIMME,A_NOTHING) + +#define add_assist(clss,meth) addmess((method)meth, "assist", A_CANT, A_NULL) +#define add_loadbang(clss,meth) addmess((method)meth, "loadbang", A_CANT, A_NULL) + +#define newout_signal(clss) outlet_new(clss,"signal") +#define newout_float(clss) outlet_new(clss,"float") +#define newout_flint(clss) outlet_new(clss,"int") +#define newout_list(clss) outlet_new(clss,"list") +#define newout_symbol(clss) outlet_new(clss,"symbol") +#define newout_anything(clss) outlet_new(clss,"anything") + +#define outlet_flint(o,v) outlet_int(o,(int)(v)) +#define outlet_symbol(o,s) outlet_anything(o,s,0,NULL) + +typedef t_perfroutine t_dspmethod; + +#endif + + +#endif diff --git a/externals/grill/flext/source/fllib.cpp b/externals/grill/flext/source/fllib.cpp new file mode 100755 index 00000000..eee94ce5 --- /dev/null +++ b/externals/grill/flext/source/fllib.cpp @@ -0,0 +1,386 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +// Code for handling of object creation functions + +#include "flext.h" + +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +#define ALIASDEL ',' + +#define ALIASSLASHES ":/\\" +#ifdef MAXMSP + #define ALIASSLASH ':' +#elif defined(NT) + #define ALIASSLASH '/' +#else + #define ALIASSLASH '/' +#endif + +//! Extract space-delimited words from a string +static const char *extract(const char *name,int ix = 0) +{ + static char tmp[1024]; + const char *n = name; + + const char *del = strchr(name,ALIASDEL); + + if(del) { + if(ix < 0) { + char *t = tmp; + while(n < del && (isspace(*n) || strchr(ALIASSLASHES,*n))) ++n; + while(n < del && !isspace(*n)) { + char c = *(n++); + *(t++) = strchr(ALIASSLASHES,c)?ALIASSLASH:c; + } + while(*t == ALIASSLASH && t > tmp) --t; + *t = 0; + + return tmp; + } + + n = del+1; + } + + while(*n && isspace(*n)) ++n; + + for(int i = 0; n && *n; ++i) { + if(i == ix) { + char *t = tmp; + + for(; *n && !isspace(*n); ++t,++n) *t = *n; + *t = 0; + return *tmp?tmp:NULL; + } + else { + while(*n && !isspace(*n)) ++n; + while(*n && isspace(*n)) ++n; + } + } + + return NULL; +} + + +//! Check if object's name ends with a tilde +static bool chktilde(const char *objname) +{ +// int stplen = strlen(setupfun); + bool tilde = true; //!strncmp(setupfun,"_tilde",6); + + if((objname[strlen(objname)-1] == '~'?1:0)^(tilde?1:0)) { + if(tilde) + error("flext: %s (no trailing ~) is defined as a tilde object",objname); + else + error("flext::check_tilde: %s is no tilde object",objname); + return true; + } + else + return false; +} + + + +// this class stands for one registered object +// it holds the class, type flags, constructor and destructor of the object and the creation arg types +// it will never be destroyed +class libobject { +public: + libobject(t_class *&cl,flext_obj *(*newf)(int,t_atom *),void (*freef)(flext_hdr *)); + + flext_obj *(*newfun)(int,t_atom *); + void (*freefun)(flext_hdr *c); + + t_class *const &clss; + bool lib,dsp,attr; + int argc; + int *argv; +}; + +libobject::libobject(t_class *&cl,flext_obj *(*newf)(int,t_atom *),void (*freef)(flext_hdr *)): + clss(cl),newfun(newf),freefun(freef),argc(0),argv(NULL) +{} + +// this class stands for one registered object name +// it holds a pointer to the respective object +// it will never be destroyed +class libname { +public: + libname(const t_symbol *n,libobject *o): name(n),obj(o),nxt(NULL) {} + + const t_symbol *name; + libobject *obj; + + static void add(libname *n); + static libname *find(const t_symbol *s); + +protected: + libname *nxt; + void addrec(libname *n); + static libname *root; +}; + +void libname::addrec(libname *n) { if(nxt) nxt->addrec(n); else nxt = n; } + +libname *libname::root = NULL; + +void libname::add(libname *l) { + if(root) root->addrec(l); + else root = l; +} + +libname *libname::find(const t_symbol *s) { + libname *l; + for(l = root; l; l = l->nxt) + if(s == l->name) break; + return l; +} + +// for MAXMSP, the library is represented by a special object (class) registered at startup +// all objects in the library are clones of that library object - they share the same class +#ifdef MAXMSP +static t_class *lib_class = NULL; +static const t_symbol *lib_name = NULL; +#endif + +void flext_obj::lib_init(const char *name,void setupfun(),bool attr) +{ +#ifdef MAXMSP + lib_name = MakeSymbol(name); + ::setup( + (t_messlist **)&lib_class, + (t_newmethod)obj_new,(t_method)obj_free, + sizeof(flext_hdr),NULL,A_GIMME,A_NULL); +#endif + process_attributes = attr; + setupfun(); +} + +void flext_obj::obj_add(bool lib,bool dsp,bool attr,const char *idname,const char *names,void setupfun(t_class *),flext_obj *(*newfun)(int,t_atom *),void (*freefun)(flext_hdr *),int argtp1,...) +{ + // get first possible object name + const t_symbol *nsym = MakeSymbol(extract(names)); + +#ifdef _DEBUG + if(dsp) chktilde(GetString(nsym)); +#endif + + if(!lib) process_attributes = attr; + + // set dynamic class pointer + t_class **cl = +#ifdef MAXMSP + lib?&lib_class: +#endif + new t_class *; + + // register object class +#ifdef PD + *cl = ::class_new( + (t_symbol *)nsym, + (t_newmethod)obj_new,(t_method)obj_free, + sizeof(flext_hdr),0,A_GIMME,A_NULL); +#elif defined(MAXMSP) + if(!lib) { + ::setup( + (t_messlist **)cl, + (t_newmethod)obj_new,(t_method)obj_free, + sizeof(flext_hdr),NULL,A_GIMME,A_NULL); + } +#endif + + // make new dynamic object + libobject *lo = new libobject(*cl,newfun,freefun); + lo->lib = lib; + lo->dsp = dsp; + lo->attr = process_attributes; + + // parse the argument type list and store it with the object + if(argtp1 == A_GIMME) + lo->argc = -1; + else { + int argtp,i; + va_list marker; + + // parse a first time and count only + va_start(marker,argtp1); + for(argtp = argtp1; argtp != A_NULL; ++lo->argc) argtp = (int)va_arg(marker,int); + va_end(marker); + + lo->argv = new int[lo->argc]; + + // now parse and store + va_start(marker,argtp1); + for(argtp = argtp1,i = 0; i < lo->argc; ++i) { + lo->argv[i] = argtp; + argtp = (int)va_arg(marker,int); + } + va_end(marker); + } + + // make help reference + flext_obj::DefineHelp(lo->clss,idname,extract(names,-1),dsp); + + for(int ix = 0; ; ++ix) { + // in this loop register all the possible aliases of the object + + const char *c = ix?extract(names,ix):GetString(nsym); + if(!c || !*c) break; + + // add to name list + libname *l = new libname(MakeSymbol(c),lo); + libname::add(l); + +#ifdef PD + if(ix > 0) + // in PD the first name is already registered with class creation + ::class_addcreator((t_newmethod)obj_new,(t_symbol *)l->name,A_GIMME,A_NULL); +#elif defined(MAXMSP) + if(ix > 0 || lib) + // in MaxMSP the first alias gets its name from the name of the object file, + // unless it is a library (then the name can be different) + ::alias(const_cast<char *>(c)); +#endif + } + + // call class setup function + setupfun(lo->clss); +} + + +typedef flext_obj *(*libfun)(int,t_atom *); + +flext_hdr *flext_obj::obj_new(const t_symbol *s,int _argc_,t_atom *argv) +{ + flext_hdr *obj = NULL; + libname *l = libname::find(s); + if(l) { + bool ok = true; + t_atom args[FLEXT_MAXNEWARGS]; + libobject *lo = l->obj; + + int argc = _argc_; + if(lo->attr) { + argc = flext_base::CheckAttrib(argc,argv); + } + + if(lo->argc >= 0) { +#ifdef _DEBUG + if(lo->argc > FLEXT_MAXNEWARGS) { ERRINTERNAL(); ok = false; } +#endif + + if(argc == lo->argc) { + for(int i = 0; /*ok &&*/ i < lo->argc; ++i) { + switch(lo->argv[i]) { +#ifdef MAXMSP + case A_INT: + if(flext::IsInt(argv[i])) args[i] = argv[i]; + else if(flext::IsFloat(argv[i])) flext::SetInt(args[i],(int)flext::GetFloat(argv[i])); + else ok = false; + break; +#endif + case A_FLOAT: + if(flext::IsInt(argv[i])) flext::SetFloat(args[i],(float)flext::GetInt(argv[i])); + else if(flext::IsFloat(argv[i])) args[i] = argv[i]; + else ok = false; + break; + case A_SYMBOL: + if(flext::IsSymbol(argv[i])) args[i] = argv[i]; + else ok = false; + break; + } + } + + if(!ok) + post("%s: Creation arguments do not match",s->s_name); + } + else { + error("%s: %s creation arguments",s->s_name,argc < lo->argc?"Not enough":"Too many"); + ok = false; + } + } + + if(ok) { +#ifdef PD + obj = (flext_hdr *)::pd_new(lo->clss); +#elif defined(MAXMSP) + obj = (flext_hdr *)::newobject(lo->clss); +#endif + flext_obj::m_holder = obj; + flext_obj::m_holdname = l->name; + flext_obj::m_holdattr = lo->attr; + + // get actual flext object (newfun calls "new flext_obj()") + if(lo->argc >= 0) + // for interpreted arguments + obj->data = lo->newfun(lo->argc,args); + else + obj->data = lo->newfun(argc,argv); + + flext_obj::m_holder = NULL; + flext_obj::m_holdname = NULL; + flext_obj::m_holdattr = false; + + bool ok = obj->data || + // check constructor exit flag + obj->data->InitOk(); + + if(ok && lo->attr && argc < _argc_) + // set cmdline attributes (this is a flext_base function!) + ok = ((flext_base *)obj->data)->InitAttrib(_argc_-argc,argv+argc); + + if(ok) // call virtual init function + ok = obj->data->Init(); + + if(!ok) { + // there was some init error, free object + lo->freefun(obj); + obj = NULL; + } + } + } +#ifdef _DEBUG + else +#ifdef MAXMSP + // in MaxMSP an object with the name of the library exists, even if not explicitely declared! + if(s != lib_name) +#endif + error("Class %s not found in library!",s->s_name); +#endif + + return obj; +} + +void flext_obj::obj_free(flext_hdr *hdr) +{ + const t_symbol *name = hdr->data->thisNameSym(); + libname *l = libname::find(name); + + if(l) { + // call virtual exit function + hdr->data->Exit(); + + // now call object destructor and deallocate + l->obj->freefun(hdr); + } +#ifdef _DEBUG + else +#ifdef MAXMSP + // in MaxMSP an object with the name of the library exists, even if not explicitely declared! + if(name != lib_name) +#endif + error("Class %s not found in library!",name); +#endif +} + + diff --git a/externals/grill/flext/source/flmspbuffer.h b/externals/grill/flext/source/flmspbuffer.h new file mode 100755 index 00000000..4a8ffe69 --- /dev/null +++ b/externals/grill/flext/source/flmspbuffer.h @@ -0,0 +1,83 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flmspbuffer.h + \brief Definition of the Max/MSP buffer structure + \internal + + This file comes from David Zicarellis inofficial package index.sit + The latter is not easily found so i included the original file buffer.h with flext +*/ + +#if defined(MAXMSP) && !defined(__FLEXT_MSPBUFFER_H) +#define __FLEXT_MSPBUFFER_H + +enum { + MAXCHAN = 4 +}; + +enum { + bi_basefreq = 0, + bi_detune, + bi_lowfreq, + bi_hifreq, + bi_lowvel, + bi_hivel, + bi_gain, + bi_numparams +}; + +typedef struct _buffer +{ + t_object b_obj; // doesn't have any signals so it doesn't need to be pxobject + long b_valid; // flag is off during read replacement or editing operation + float *b_samples; // stored with interleaved channels if multi-channel + long b_frames; // number of sample frames (each one is sizeof(float) * b_nchans bytes) + long b_nchans; // number of channels + long b_size; // size of buffer in floats + float b_sr; // sampling rate of the buffer + float b_1oversr; // 1 / sr + float b_msr; // sr * .001 + // Mac-specific stuff + float *b_memory; // pointer to where memory starts (initial padding for interp) + t_symbol *b_name; + short b_vol; + short b_space; + // looping info (from AIFF file) + long b_susloopstart; // in samples + long b_susloopend; // in samples + long b_relloopstart; // in samples + long b_relloopend; // in samples + // instrument info (from AIFF file) + short b_inst[bi_numparams]; + // window stuff + void *b_wind; + double b_pixperfr; + double b_frperpix; + long b_imagesize; + Point b_scroll; + long b_scrollscale; + long b_selbegin[MAXCHAN]; + long b_selend[MAXCHAN]; + long b_zoom; + long b_zim[11]; + void *b_mouseout; + long b_format; // 'AIFF' or 'Sd2f' + t_symbol *b_filename; // last file read (not written) for readagain message + long b_oldnchans; // used for resizing window in case of # of channels change + void *b_doneout; + long b_outputbytes; // number of bytes used for output sample (1-4) + long b_modtime; // last modified time ("dirty" method) +} t_buffer; + +#define BUFWIND(x) ((t_wind *)(x->b_wind)) + + +#endif diff --git a/externals/grill/flext/source/flout.cpp b/externals/grill/flext/source/flout.cpp new file mode 100644 index 00000000..3b7c6bd9 --- /dev/null +++ b/externals/grill/flext/source/flout.cpp @@ -0,0 +1,201 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flout.cpp + \brief Implementation of the flext outlet functionality. +*/ + +#include "flext.h" +#include "flinternal.h" + + +#ifdef MAXMSP +#define CRITON() short state = lockout_set(1) +#define CRITOFF() lockout_set(state) +#else +#define CRITON() +#define CRITOFF() +#endif + +#ifndef FLEXT_THREADS +void flext_base::ToOutBang(outlet *o) { CRITON(); outlet_bang((t_outlet *)o); CRITOFF(); } +void flext_base::ToOutFloat(outlet *o,float f) { CRITON(); outlet_float((t_outlet *)o,f); CRITOFF(); } +void flext_base::ToOutInt(outlet *o,int f) { CRITON(); outlet_flint((t_outlet *)o,f); CRITOFF(); } +void flext_base::ToOutSymbol(outlet *o,const t_symbol *s) { CRITON(); outlet_symbol((t_outlet *)o,const_cast<t_symbol *>(s)); CRITOFF(); } +void flext_base::ToOutList(outlet *o,int argc,const t_atom *argv) { CRITON(); outlet_list((t_outlet *)o,gensym("list"),argc,(t_atom *)argv); CRITOFF(); } +void flext_base::ToOutAnything(outlet *o,const t_symbol *s,int argc,const t_atom *argv) { CRITON(); outlet_anything((t_outlet *)o,const_cast<t_symbol *>(s),argc,(t_atom *)argv); CRITOFF(); } +#else +void flext_base::ToOutBang(outlet *o) { if(IsSystemThread()) { CRITON(); outlet_bang((t_outlet *)o); CRITOFF(); } else ToQueueBang(o); } +void flext_base::ToOutFloat(outlet *o,float f) { if(IsSystemThread()) { CRITON(); outlet_float((t_outlet *)o,f); CRITOFF(); } else ToQueueFloat(o,f); } +void flext_base::ToOutInt(outlet *o,int f) { if(IsSystemThread()) { CRITON(); outlet_flint((t_outlet *)o,f); CRITOFF(); } else ToQueueInt(o,f); } +void flext_base::ToOutSymbol(outlet *o,const t_symbol *s) { if(IsSystemThread()) { CRITON(); outlet_symbol((t_outlet *)o,const_cast<t_symbol *>(s)); CRITOFF(); } else ToQueueSymbol(o,s); } +void flext_base::ToOutList(outlet *o,int argc,const t_atom *argv) { if(IsSystemThread()) { CRITON(); outlet_list((t_outlet *)o,gensym("list"),argc,(t_atom *)argv); CRITOFF(); } else ToQueueList(o,argc,(t_atom *)argv); } +void flext_base::ToOutAnything(outlet *o,const t_symbol *s,int argc,const t_atom *argv) { if(IsSystemThread()) { CRITON(); outlet_anything((t_outlet *)o,const_cast<t_symbol *>(s),argc,(t_atom *)argv); CRITOFF(); } else ToQueueAnything(o,s,argc,(t_atom *)argv); } +#endif + + +class flext_base::qmsg +{ +public: + qmsg(): nxt(NULL),tp(tp_none) {} + ~qmsg(); + + qmsg *nxt; + + void Clear(); + + void SetBang(outlet *o) { Clear(); out = o; tp = tp_bang; } + void SetFloat(outlet *o,float f) { Clear(); out = o; tp = tp_float; _float = f; } + void SetInt(outlet *o,int i) { Clear(); out = o; tp = tp_int; _int = i; } + void SetSymbol(outlet *o,const t_symbol *s) { Clear(); out = o; tp = tp_sym; _sym = s; } + void SetList(outlet *o,int argc,const t_atom *argv) { Clear(); out = o; tp = tp_list; _list.argc = argc,_list.argv = CopyList(argc,argv); } + void SetAny(outlet *o,const t_symbol *s,int argc,const t_atom *argv) { Clear(); out = o; tp = tp_any; _any.s = s,_any.argc = argc,_any.argv = CopyList(argc,argv); } + + outlet *out; + enum { tp_none,tp_bang,tp_float,tp_int,tp_sym,tp_list,tp_any } tp; + union { + float _float; + int _int; + const t_symbol *_sym; + struct { int argc; t_atom *argv; } _list; + struct { const t_symbol *s; int argc; t_atom *argv; } _any; + }; + +// void Add(qmsg *o); +}; + +flext_base::qmsg::~qmsg() +{ + Clear(); + if(nxt) delete nxt; +} + +void flext_base::qmsg::Clear() +{ + if(tp == tp_list) { if(_list.argv) delete[] _list.argv; } + else if(tp == tp_any) { if(_any.argv) delete[] _any.argv; } + tp = tp_none; +} + +/* +void flext_base::qmsg::Add(qmsg *o) +{ + if(nxt) nxt->Add(o); + else nxt = o; +} +*/ + +void flext_base::QTick(flext_base *th) +{ +#ifdef DEBUG + if(!th->IsSystemThread()) { + error("flext - Queue tick called by wrong thread!"); + return; + } +#endif + +#ifdef FLEXT_THREADS + th->qmutex.Lock(); +#endif + while(th->qhead) { + qmsg *m = th->qhead; + +#ifdef MAXMSP + short state = lockout_set(1); +#endif + + switch(m->tp) { + case qmsg::tp_bang: th->ToOutBang(m->out); break; + case qmsg::tp_float: th->ToOutFloat(m->out,m->_float); break; + case qmsg::tp_int: th->ToOutInt(m->out,m->_int); break; + case qmsg::tp_sym: th->ToOutSymbol(m->out,m->_sym); break; + case qmsg::tp_list: th->ToOutList(m->out,m->_list.argc,m->_list.argv); break; + case qmsg::tp_any: th->ToOutAnything(m->out,m->_any.s,m->_any.argc,m->_any.argv); break; +#ifdef DEBUG + default: ERRINTERNAL(); +#endif + } + +#ifdef MAXMSP + lockout_set(state); +#endif + + th->qhead = m->nxt; + if(!th->qhead) th->qtail = NULL; + m->nxt = NULL; + delete m; + } +#ifdef FLEXT_THREADS + th->qmutex.Unlock(); +#endif +} + +void flext_base::Queue(qmsg *m) +{ +#ifdef FLEXT_THREADS + qmutex.Lock(); +#endif + if(qtail) qtail->nxt = m; + else qhead = m; + qtail = m; +#ifdef FLEXT_THREADS + qmutex.Unlock(); +#endif +#ifdef PD + clock_delay(qclk,0); +#elif defined(MAXMSP) + clock_delay(yclk,0); +#else + #error "To implement!" +#endif +} + +void flext_base::ToQueueBang(outlet *o) +{ + qmsg *m = new qmsg(); + m->SetBang(o); + Queue(m); +} + +void flext_base::ToQueueFloat(outlet *o,float f) +{ + qmsg *m = new qmsg; + m->SetFloat(o,f); + Queue(m); +} + +void flext_base::ToQueueInt(outlet *o,int f) +{ + qmsg *m = new qmsg; + m->SetInt(o,f); + Queue(m); +} + +void flext_base::ToQueueSymbol(outlet *o,const t_symbol *s) +{ + qmsg *m = new qmsg; + m->SetSymbol(o,s); + Queue(m); +} + +void flext_base::ToQueueList(outlet *o,int argc,const t_atom *argv) +{ + qmsg *m = new qmsg; + m->SetList(o,argc,argv); + Queue(m); +} + +void flext_base::ToQueueAnything(outlet *o,const t_symbol *s,int argc,const t_atom *argv) +{ + qmsg *m = new qmsg; + m->SetAny(o,s,argc,argv); + Queue(m); +} + diff --git a/externals/grill/flext/source/flsndobj.cpp b/externals/grill/flext/source/flsndobj.cpp new file mode 100644 index 00000000..1965b86b --- /dev/null +++ b/externals/grill/flext/source/flsndobj.cpp @@ -0,0 +1,107 @@ +#include "flsndobj.h" + +//namespace flext { + +flext_sndobj::flext_sndobj(): + inobjs(0),outobjs(0), + inobj(NULL),tmpobj(NULL),outobj(NULL), + smprt(0),blsz(0) +{} + +flext_sndobj::~flext_sndobj() +{ + ClearObjs(); +} + +void flext_sndobj::ClearObjs() +{ + FreeObjs(); + + if(inobj) { + for(int i = 0; i < inobjs; ++i) { delete inobj[i]; delete tmpobj[i]; } + delete[] inobj; inobj = NULL; + delete[] tmpobj; tmpobj = NULL; + inobjs = 0; + } + if(outobj) { + for(int i = 0; i < outobjs; ++i) delete outobj[i]; + delete[] outobj; outobj = NULL; outobjs = 0; + } +} + +void flext_sndobj::m_dsp(int n,t_sample *const *in,t_sample *const *out) +{ + // called on every rebuild of the dsp chain + + int i; + if(Blocksize() != blsz || Samplerate() != smprt) { + // block size or sample rate has changed... rebuild all objects + + ClearObjs(); + + blsz = Blocksize(); + smprt = Samplerate(); + + // set up sndobjs for inlets and outlets + inobj = new Inlet *[inobjs = CntInSig()]; + tmpobj = new SndObj *[inobjs]; + for(i = 0; i < inobjs; ++i) { + inobj[i] = new Inlet(in[i],blsz,smprt); + tmpobj[i] = new SndObj(NULL,blsz,smprt); + } + outobj = new Outlet *[outobjs = CntInSig()]; + for(i = 0; i < outobjs; ++i) outobj[i] = new Outlet(out[i],blsz,smprt); + + NewObjs(); + } + else { + // assign changed input/output vectors + + for(i = 0; i < inobjs; ++i) inobj[i]->SetBuf(in[i]); + for(i = 0; i < outobjs; ++i) outobj[i]->SetBuf(out[i]); + } +} + +void flext_sndobj::m_signal(int n,t_sample *const *in,t_sample *const *out) +{ + for(int i = 0; i < inobjs; ++i) *tmpobj[i] << *inobj[i]; + ProcessObjs(); +} + + +flext_sndobj::Inlet::Inlet(const t_sample *b,int vecsz,float sr): + SndIO(1,sizeof(t_sample)*8,NULL,vecsz,sr),buf(b) +{} + +short flext_sndobj::Inlet::Read() +{ + if(!m_error) { + for(m_vecpos = 0; m_vecpos < m_samples; m_vecpos++) + m_output[m_vecpos] = buf[m_vecpos]; + return 1; + } + else return 0; +} + +short flext_sndobj::Inlet::Write() { return 0; } + + +flext_sndobj::Outlet::Outlet(t_sample *b,int vecsz,float sr): + SndIO(1,sizeof(t_sample)*8,NULL,vecsz,sr),buf(b) +{} + +short flext_sndobj::Outlet::Read() { return 0; } + +short flext_sndobj::Outlet::Write() +{ + if(!m_error) { + if(m_IOobjs[0]) + for(m_vecpos = 0; m_vecpos < m_samples; m_vecpos++) + buf[m_vecpos] = m_IOobjs[0]->Output(m_vecpos); + return 1; + } + else return 0; +} + +//} // namespace flext + diff --git a/externals/grill/flext/source/flsndobj.h b/externals/grill/flext/source/flsndobj.h new file mode 100644 index 00000000..f68054ed --- /dev/null +++ b/externals/grill/flext/source/flsndobj.h @@ -0,0 +1,83 @@ +/* + +Copyright (c) 2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +#ifndef FLEXT_SNDOBJ +#define FLEXT_SNDOBJ + +#include "flext.h" +#include <SndObj/AudioDefs.h> + +//namespace flext { + +class flext_sndobj: + public flext_dsp +{ + FLEXT_HEADER(flext_sndobj,flext_dsp) + +public: + flext_sndobj(); + virtual ~flext_sndobj(); + + // these have to be overridden in child classes + virtual void NewObjs() {} + virtual void FreeObjs() {} + virtual void ProcessObjs() {} + + // inputs and outputs + SndObj &InObj(int i) { return *tmpobj[i]; } + SndIO &OutObj(int i) { return *outobj[i]; } + +protected: + virtual void m_dsp(int n,t_sample *const *in,t_sample *const *out); + virtual void m_signal(int n,t_sample *const *in,t_sample *const *out); + +private: + //! SndObj for reading from inlet buffer + class Inlet: + public SndIO + { + public: + Inlet(const t_sample *b,int vecsz,float sr); + virtual short Read(); + virtual short Write(); + + void SetBuf(const t_sample *b) { buf = b; } + + private: + const t_sample *buf; + }; + + //! SndObj for writing to outlet buffer + class Outlet: + public SndIO + { + public: + Outlet(t_sample *b,int vecsz,float sr); + virtual short Read(); + virtual short Write(); + + void SetBuf(t_sample *b) { buf = b; } + + private: + t_sample *buf; + }; + + void ClearObjs(); + + int inobjs,outobjs; + SndObj **tmpobj; + Inlet **inobj; + Outlet **outobj; + + float smprt; + int blsz; +}; + +//} // namespace flext + +#endif diff --git a/externals/grill/flext/source/flstdc.h b/externals/grill/flext/source/flstdc.h new file mode 100644 index 00000000..73ce613c --- /dev/null +++ b/externals/grill/flext/source/flstdc.h @@ -0,0 +1,163 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flstdc.h + \brief Definitions to unite MaxMSP and PD notions + + This file contains a few definitions to unite a few of the notions that + once drifted apart in Max and PD. It is not elegant but helps. +*/ + +#ifndef __FLEXT_STDC_H +#define __FLEXT_STDC_H + +// Be sure that one target is defined +#if !defined(PD) && !defined(MAXMSP) +#error Either PD or MAXMSP must be defined +#endif + +// Do some compiler checking +#if defined(__MRC__) && __MRC__ < 0x500 +#error Apple MPW MrCpp v.5.0.0 or better compiler required +#endif + + +// PD stuff + +#ifdef PD + +/* PD definitions start here */ + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable:4091) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Include the relevant PD header files +#ifdef _DEBUG +#include <m_imp.h> // for easier debugging +#else +#include <m_pd.h> +#endif + +#ifdef __cplusplus +} +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +typedef t_object t_sigobj; +typedef t_gpointer *t_ptrtype; + +typedef t_float t_flint; +typedef t_symbol *t_symptr; +typedef t_symbol *t_symtype; +typedef t_class **t_thing; + +typedef t_clock t_qelem; + +#define A_NOTHING A_NULL +#define A_FLINT A_FLOAT +#define A_DEFFLINT A_DEFFLOAT + +// MAX stuff +#elif defined(MAXMSP) + +/* MaxMSP definitions start here */ + +// Include the relevant MaxMSP header files +extern "C" +{ +#include "ext.h" +//#include "ext_strings.h" // clashes with MPW +#include "ext_user.h" +#include "z_dsp.h" +//#include "z_atom.h" +} + +typedef t_pxbox t_sigobj; // that's the all-in-one object type of MaxMSP (not very memory-efficent, i guess) +typedef t_patcher t_canvas; + +typedef t_int t_flint; +typedef t_symbol *t_symptr; +typedef t_symbol *t_symtype; +typedef t_object *t_thing; + +typedef qelem t_qelem; + +typedef method t_method; +typedef method t_newmethod; +typedef int t_atomtype; + +typedef struct clock t_clock; +typedef void t_binbuf; + +#undef clock_free +#define clock_free(tick) freeobject((object *)tick) + +#define A_NULL A_NOTHING +#define A_FLINT A_INT +#define A_DEFFLINT A_DEFLONG + +#endif + + +#ifdef _LOG + +/* If _LOG is defined implement logging */ +#define LOG(s) post(s) +#define LOG1(s,v1) post(s,v1) +#define LOG2(s,v1,v2) post(s,v1,v2) +#define LOG3(s,v1,v2,v3) post(s,v1,v2,v3) +#define LOG4(s,v1,v2,v3,v4) post(s,v1,v2,v3,v4) +#define LOG5(s,v1,v2,v3,v4,v5) post(s,v1,v2,v3,v4,v5) + + +#else + +/* If _LOG is not defined avoid logging */ +#define LOG(s) ((void)0) +#define LOG1(s,v1) ((void)0) +#define LOG2(s,v1,v2) ((void)0) +#define LOG3(s,v1,v2,v3) ((void)0) +#define LOG4(s,v1,v2,v3,v4) ((void)0) +#define LOG5(s,v1,v2,v3,v4,v5) ((void)0) + +#endif + +#ifdef _DEBUG +#define ASSERT(b) ((void)(!(b)?(error("Assertion failed: " #b " - in " __FILE__ " line %i",(int)__LINE__),0):0)) +#else +#define ASSERT(b) ((void)0) +#endif + +#define ERRINTERNAL() error("flext: Internal error in file " __FILE__ ", line %i - please report",(int)__LINE__) + + +/* Set the right calling convention (and exporting) for the OS */ + +#if defined(NT) +#define FLEXT_EXT __declspec(dllexport) +#else // other OS's +#define FLEXT_EXT +#endif + +#endif + + + + + diff --git a/externals/grill/flext/source/flsupport.cpp b/externals/grill/flext/source/flsupport.cpp new file mode 100644 index 00000000..854fe871 --- /dev/null +++ b/externals/grill/flext/source/flsupport.cpp @@ -0,0 +1,58 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flsupport.cpp + \brief flext support functions and classes. +*/ + +#include "flsupport.h" + +const t_symbol *flext::sym_float = NULL; +const t_symbol *flext::sym_symbol = NULL; +const t_symbol *flext::sym_bang = NULL; +const t_symbol *flext::sym_list = NULL; +const t_symbol *flext::sym_anything = NULL; +const t_symbol *flext::sym_pointer = NULL; +const t_symbol *flext::sym_int = NULL; + +#ifdef PD +const t_symbol *flext::sym_signal = NULL; +#endif + +void flext::Setup() +{ +#ifdef PD + sym_anything = &s_anything; + sym_pointer = &s_pointer; + sym_float = &s_float; + sym_symbol = &s_symbol; + sym_bang = &s_bang; + sym_list = &s_list; + sym_signal = &s_signal; +#elif defined(MAXMSP) + sym_int = gensym("int"); + sym_float = gensym("float"); + sym_symbol = gensym("symbol"); + sym_bang = gensym("bang"); + sym_list = gensym("list"); + sym_anything = gensym("anything"); +#endif +} + +void flext::GetAString(const t_atom &a,char *buf,int szbuf) +{ +#ifdef PD + atom_string(const_cast<t_atom *>(&a),buf,szbuf); +#else + if(IsSymbol(a)) sprintf(buf,GetString(a)); + else if(IsFloat(a)) sprintf(buf,"%f",GetFloat(a)); + else if(IsInt(a)) sprintf(buf,"%i",GetInt(a)); +#endif +} diff --git a/externals/grill/flext/source/flsupport.h b/externals/grill/flext/source/flsupport.h new file mode 100644 index 00000000..148790ae --- /dev/null +++ b/externals/grill/flext/source/flsupport.h @@ -0,0 +1,438 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flsupport.h + \brief flext support functions and classes +*/ + +#ifndef __FLSUPPORT_H +#define __FLSUPPORT_H + +#include "flstdc.h" + +#ifdef FLEXT_THREADS +#include <pthread.h> +#endif + +class FLEXT_EXT flext { +public: +// --- buffer/array stuff ----------------------------------------- + + /*! \defgroup FLEXT_N_BUFFER Flext buffer handling + + @{ + */ + + //! Class for platform independent buffer handling + class buffer + { + public: + /*! \brief Construct buffer. + \param delayed = true: only sets name, needs another Set(NULL) to really initialize the buffer + \remark As externals can be created prior to the buffer objects they are pointing to, initialization should be done at loadbang! + */ + buffer(const t_symbol *s = NULL,bool delayed = false); + + //! Destroy buffer + ~buffer(); + + /*! \brief Check if the data is valid + */ + bool Ok() const { return sym != NULL && data != NULL; } + + /*! \brief Check and update if the buffer has been changed (e.g. resized) + */ + bool Update(); + + /*! \brief Set to specified buffer. + \param nameonly: if true sets name only, but doesn't look at buffer actually + */ + int Set(const t_symbol *s = NULL,bool nameonly = false); + + /*! \brief Declare buffer content as dirty. + \param refr: if true forces immediate graphics refresh + */ + void Dirty(bool refr = false); + + //! Get symbol of buffer + t_symbol *Symbol() const { return const_cast<t_symbol *>(sym); } + + //! Get literal name of buffer + const char *Name() const { return sym?sym->s_name:""; } + + /*! \brief Get pointer to buffer, channel and frame count. + \remark Channels are interleaved + */ + t_sample *Data() { return data; } + + //! Get channel count + int Channels() const { return chns; } + //! Get frame count + int Frames() const { return frames; } + //! Set frame count + void Frames(int fr,bool keep = false); + + //! Graphic auto refresh interval + void SetRefrIntv(float intv); + + protected: + const t_symbol *sym; + t_sample *data; + int chns,frames; +#ifdef PD + t_garray *arr; + float interval; + bool isdirty,ticking; + t_clock *tick; + + private: + static void cb_tick(buffer *b); +#endif + }; + +//! @} + +// --- various symbols -------------------------------------------- + + /*! \defgroup FLEXT_N_SYMBOL Flext atom/symbol handling + + @{ + */ + + //! Symbol constant for "float" + static const t_symbol *sym_float; + //! Symbol constant for "symbol" + static const t_symbol *sym_symbol; + //! Symbol constant for "bang" + static const t_symbol *sym_bang; + //! Symbol constant for "list" + static const t_symbol *sym_list; + //! Symbol constant for "anything" + static const t_symbol *sym_anything; + + /*! \brief Symbol constant for "int" + \note Only the Max/MSP system has this defined as an internal type + */ + static const t_symbol *sym_int; + + /*! Symbol constant for "pointer" + \note Only PD has this defined as an internal type + */ + static const t_symbol *sym_pointer; + +#ifdef PD + + /*! \brief Symbol constant for "signal" + \note PD only + */ + static const t_symbol *sym_signal; +#endif + + //! Make a symbol from a string + static const t_symbol *MakeSymbol(const char *s) { return gensym(const_cast<char *>(s)); } + + //! Get symbol string + static const char *GetString(const t_symbol *s) { return s->s_name; } + //! Check for symbol and get string + static const char *GetAString(const t_symbol *s) { return s?s->s_name:""; } + +//! @} + +// --- utilities -------------------------------------------------- + + /*! \defgroup FLEXT_C_UTIL Flext utility functions + + @{ + */ + + //! Copy an atom + static void CopyAtom(t_atom *dst,const t_atom *src) { *dst = *src; } + + //! Copy a list of atoms + static t_atom *CopyList(int argc,const t_atom *argv); + //! Copy a memory region + static void CopyMem(void *dst,const void *src,int bytes); + //! Sleep for an amount of time + static void Sleep(float s); + +//! @} + +// --- atom stuff ---------------------------------------- + + //! Set atom from another atom + static void SetAtom(t_atom &a,const t_atom &b) { CopyAtom(&a,&b); } + + //! Check whether the atom is nothing + static bool IsNothing(const t_atom &a) { return a.a_type == A_NULL; } + //! Set the atom to represent nothing + static void SetNothing(t_atom &a) { a.a_type = A_NULL; } + + //! Check whether the atom is a float + static bool IsFloat(const t_atom &a) { return a.a_type == A_FLOAT; } + //! Check whether the atom can be represented as a float + static bool CanbeFloat(const t_atom &a) { return IsFloat(a) || IsInt(a); } + //! Access the float value (without type check) + static float GetFloat(const t_atom &a) { return a.a_w.w_float; } + //! Set the atom to represent a float + static void SetFloat(t_atom &a,float v) { a.a_type = A_FLOAT; a.a_w.w_float = v; } + + //! Check whether the atom is a symbol + static bool IsSymbol(const t_atom &a) { return a.a_type == A_SYMBOL; } + //! Access the symbol value (without type check) + static t_symbol *GetSymbol(const t_atom &a) { return a.a_w.w_symbol; } + //! Check for a symbol and get its value + static t_symbol *GetASymbol(const t_atom &a) { return IsSymbol(a)?GetSymbol(a):NULL; } // NULL or empty symbol? + //! Set the atom to represent a symbol + static void SetSymbol(t_atom &a,const t_symbol *s) { a.a_type = A_SYMBOL; a.a_w.w_symbol = const_cast<t_symbol *>(s); } + + //! Check whether the atom is a string + static bool IsString(const t_atom &a) { return IsSymbol(a); } + //! Access the string value (without type check) + static const char *GetString(const t_atom &a) { t_symbol *s = GetSymbol(a); return s?GetString(s):NULL; } + //! Check for a string and get its value + static void GetAString(const t_atom &a,char *buf,int szbuf); + //! Set the atom to represent a string + static void SetString(t_atom &a,const char *c) { SetSymbol(a,gensym(const_cast<char *>(c))); } + + //! Check whether the atom can be represented as an integer + static bool CanbeInt(const t_atom &a) { return IsFloat(a) || IsInt(a); } + + //! Check whether the atom can be represented as a boolean + static bool CanbeBool(const t_atom &a) { return CanbeInt(a); } + //! Check for an boolean and get its value + static bool GetABool(const t_atom &a) { return GetAInt(a) != 0; } + +#ifdef PD + //! Check for a float and get its value + static float GetAFloat(const t_atom &a) { return IsFloat(a)?GetFloat(a):0; } + + //! Check whether the atom is an integer + static bool IsInt(const t_atom &) { return false; } + //! Access the integer value (without type check) + static int GetInt(const t_atom &a) { return (int)GetFloat(a); } + //! Check for an integer and get its value + static int GetAInt(const t_atom &a) { return (int)GetAFloat(a); } + //! Set the atom to represent a integer (depending on the system) + static void SetInt(t_atom &a,int v) { a.a_type = A_FLOAT; a.a_w.w_float = (float)v; } + + //! Check whether the atom is a pointer + static bool IsPointer(const t_atom &a) { return a.a_type == A_POINTER; } + //! Access the pointer value (without type check) + static t_gpointer *GetPointer(const t_atom &a) { return a.a_w.w_gpointer; } + //! Check for a pointer and get its value + static t_gpointer *GetAPointer(const t_atom &a) { return IsPointer(a)?GetPointer(a):NULL; } + //! Set the atom to represent a pointer + static void SetPointer(t_atom &a,t_gpointer *p) { a.a_type = A_POINTER; a.a_w.w_gpointer = p; } + +#elif defined(MAXMSP) + //! Check for a float and get its value + static float GetAFloat(const t_atom &a) { return IsFloat(a)?GetFloat(a):(IsInt(a)?GetInt(a):0); } + + //! Check whether the atom is an int + static bool IsInt(const t_atom &a) { return a.a_type == A_INT; } + //! Access the integer value (without type check) + static int GetInt(const t_atom &a) { return a.a_w.w_long; } + //! Check for an integer and get its value + static int GetAInt(const t_atom &a) { return IsInt(a)?GetInt(a):(IsFloat(a)?GetFloat(a):0); } + //! Set the atom to represent an integer + static void SetInt(t_atom &a,int v) { a.a_type = A_INT; a.a_w.w_long = v; } + + //! Check whether the atom is a pointer + static bool IsPointer(const t_atom &) { return false; } + //! Access the pointer value (without type check) + static void *GetPointer(const t_atom &) { return NULL; } + //! Check for a pointer and get its value + static void *GetAPointer(const t_atom &) { return NULL; } +// void SetPointer(t_atom &,void *) {} +#endif + +// --- atom list stuff ------------------------------------------- + + /*! \defgroup FLEXT_N_ATOM Flext atom/list handling + + @{ + */ + + //! Class representing a list of atoms + class AtomList + { + public: + //! Construct list + AtomList(int argc = 0,const t_atom *argv = NULL); + //! Construct list + AtomList(const AtomList &a); + //! Destroy list + ~AtomList(); + + //! Clear list + AtomList &Clear() { return operator()(); } + + //! Set list + AtomList &operator()(int argc = 0,const t_atom *argv = NULL); + //! Set list by another AtomList + AtomList &operator =(const AtomList &a) { return operator()(a.Count(),a.Atoms()); } + + //! Get number of atoms in the list + int Count() const { return cnt; } + //! Get a reference to an indexed atom + t_atom &operator [](int ix) { return lst[ix]; } + //! Get a reference to an indexed atom + const t_atom &operator [](int ix) const { return lst[ix]; } + + //! Get a pointer to the list of atoms + t_atom *Atoms() { return lst; } + //! Get a pointer to the list of atoms + const t_atom *Atoms() const { return lst; } + + //! Append an atom to the list + AtomList &Append(const t_atom &a); + //! Append an atom list to the list + AtomList &Append(int argc,const t_atom *argv); + //! Append an atom list to the list + AtomList &Append(const AtomList &a) { return Append(a.Count(),a.Atoms()); } + //! Prepend an atom to the list + AtomList &Prepend(const t_atom &a); + //! Prepend an atom list to the list + AtomList &Prepend(int argc,const t_atom *argv); + //! Prepend an atom list to the list + AtomList &Prepend(const AtomList &a) { return Prepend(a.Count(),a.Atoms()); } + + //! Get a part of the list + AtomList GetPart(int offs,int len) const; + //! Set to a part of the list + AtomList &Part(int offs,int len) { return (*this = GetPart(offs,len)); } + + protected: + int cnt; + t_atom *lst; + }; + + + //! Class representing an "anything" + class AtomAnything: + public AtomList + { + public: + //! Construct anything + AtomAnything(const t_symbol *h = NULL,int argc = 0,const t_atom *argv = NULL): AtomList(argc,argv),hdr(h) {} + //! Construct anything + AtomAnything(const char *h,int argc = 0,const t_atom *argv = NULL): AtomList(argc,argv),hdr(MakeSymbol(h)) {} + //! Construct anything + AtomAnything(const AtomAnything &a): AtomList(a),hdr(a.hdr) {} + + //! Clear anything + AtomAnything &Clear() { return operator()(); } + + //! Get header symbol of anything + const t_symbol *Header() const { return hdr; } + + //! Set anything + AtomAnything &operator()(const t_symbol *h = NULL,int argc = 0,const t_atom *argv = NULL) + { + hdr = h; AtomList::operator()(argc,argv); + return *this; + } + + //! Set list by another AtomAnything + AtomAnything &operator =(const AtomAnything &a) { return operator()(a.Header(),a.Count(),a.Atoms()); } + + protected: + const t_symbol *hdr; + }; + +//! @} + +// --- clock stuff ------------------------------------------------ + + + /*! \defgroup FLEXT_N_CLOCK Flext clock functions + + At the moment there are none + + @{ + */ + +//! @} + + +// --- thread stuff ----------------------------------------------- + +#ifdef FLEXT_THREADS + /*! \defgroup FLEXT_N_THREAD Flext thread handling + + @{ + */ + + /*! \brief Thread mutex + \sa pthreads documentation + */ + class ThrMutex + { + public: + //! Construct thread mutex + ThrMutex(): cnt(0) { pthread_mutex_init(&mutex,NULL); } + //! Destroy thread mutex + ~ThrMutex() { pthread_mutex_destroy(&mutex); } + + //! Lock thread mutex + int Lock() { cnt = 1; return pthread_mutex_lock(&mutex); } + //! Try to lock, but don't wait + int TryLock() { return pthread_mutex_trylock(&mutex); } + //! Unlock thread mutex + int Unlock() { cnt = 0; return pthread_mutex_unlock(&mutex); } + + //! Lock thread mutex (increase lock count by one) + void Push() { if(!cnt++) Lock(); } + //! Unlock thread mutex if lock count reaches zero + void Pop() { if(!--cnt) Unlock(); } + protected: + pthread_mutex_t mutex; + int cnt; + }; + + /*! \brief Thread conditional + \sa pthreads documentation + */ + class ThrCond: + public ThrMutex + { + public: + //! Construct thread conditional + ThrCond() { pthread_cond_init(&cond,NULL); } + //! Destroy thread conditional + ~ThrCond() { pthread_cond_destroy(&cond); } + + //! Wait for condition + int Wait() { return pthread_cond_wait(&cond,&mutex); } + + /*! \brief Wait for condition (for a certain time) + \param time Wait time in seconds + */ + int TimedWait(float time) + { + timespec tm; tm.tv_sec = (long)time; tm.tv_nsec = (long)((time-(long)time)*1.e9); + return pthread_cond_timedwait(&cond,&mutex,&tm); + } + + //! Signal condition + int Signal() { return pthread_cond_signal(&cond); } + //! Broadcast condition + int Broadcast() { return pthread_cond_broadcast(&cond); } + protected: + pthread_cond_t cond; + }; +//! @} +#endif // FLEXT_THREADS + +protected: + static void Setup(); +}; + +#endif diff --git a/externals/grill/flext/source/flthr.cpp b/externals/grill/flext/source/flthr.cpp new file mode 100644 index 00000000..fd780a1c --- /dev/null +++ b/externals/grill/flext/source/flthr.cpp @@ -0,0 +1,237 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flthr.cpp + \brief Implementation of the flext thread functionality. +*/ + +#ifdef FLEXT_THREADS + +#include "flext.h" +#include "flinternal.h" + +#ifdef MAXMSP +#define SCHEDTICK 1 +#endif + +#ifdef NT +#include <windows.h> +#endif +#include <errno.h> + +bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname) +{ + static bool init = false; + static pthread_attr_t attr; +#ifdef _DEBUG + if(!p) { + ERRINTERNAL(); + return false; + } +#endif + if(!init) { + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + init = true; + } + + // set thread priority one point below normal + // so thread construction won't disturb real-time audio + pthread_t id = pthread_self(); + sched_param parm; + int policy; + pthread_getschedparam(id,&policy,&parm); + int prio = parm.sched_priority; + int schmin = sched_get_priority_min(policy); + if(prio > schmin) { + parm.sched_priority = prio-1; + pthread_setschedparam(id,policy,&parm); + } + + pthread_t thrid; + int ret = pthread_create (&thrid,&attr,(void *(*)(void *))meth,p); + + // set thread priority back to normal + parm.sched_priority = prio; + pthread_setschedparam(id,policy,&parm); + + if(ret) { +#ifdef _DEBUG + error((char *)(ret == EAGAIN?"%s - Unsufficient resources to launch thread!":"%s - Could not launch method!"),methname); +#endif + delete p; + return false; + } + else { +#ifdef MAXMSP + sched_yield(); +#endif + return true; + } +} + +bool flext_base::PushThread() +{ + tlmutex.Lock(); + + // make an entry into thread list + thr_entry *nt = new thr_entry; + if(thrtail) thrtail->nxt = nt; + else thrhead = nt; + thrtail = nt; + + { +#ifdef NT + // set detached thread to lower priority class + DWORD err; + HANDLE thr = GetCurrentThread(); + DWORD cl = GetThreadPriority(thr); + if(!cl && (err = GetLastError())) + post("flext - error getting thread priority"); + else { + BOOL ret = SetThreadPriority(thr,cl-2); + if(!ret) { + err = GetLastError(); + if(!err) post("flext - error setting thread priority"); + } + } +#else + // set initial detached thread priority two points below normal + sched_param parm; + int policy; + if(pthread_getschedparam(nt->thrid,&policy,&parm)) + post("flext - can't get thread parameters"); + int prio = parm.sched_priority; + int schmin = sched_get_priority_min(policy); + if(prio > schmin) { + parm.sched_priority = prio-2; + if(pthread_setschedparam(nt->thrid,policy,&parm)) + post("flext - can't set thread parameters"); + } +#endif + } + + tlmutex.Unlock(); + +#ifdef MAXMSP + clock_delay(yclk,0); +#endif + return true; +} + +void flext_base::PopThread() +{ + tlmutex.Lock(); + + pthread_t id = pthread_self(); + + thr_entry *prv = NULL,*ti; + for(ti = thrhead; ti; prv = ti,ti = ti->nxt) + if(ti->Is()) break; + + if(ti) { + if(prv) + prv->nxt = ti->nxt; + else + thrhead = ti->nxt; + if(thrtail == ti) thrtail = prv; + + ti->nxt = NULL; + delete ti; + } + else { +#ifdef _DEBUG + post("%s - INTERNAL ERROR: Thread not found!",thisName()); +#endif + } + + tlmutex.Unlock(); +} + +#ifdef MAXMSP +void flext_base::YTick(flext_base *th) +{ + clock_delay(th->yclk,0); + qelem_set(th->qclk); + sched_yield(); +} +#endif + +flext_base::thrid_t flext_base::GetThreadId() +{ + return pthread_self(); +} + +bool flext_base::ChangePriority(int dp,thrid_t id) +{ + sched_param parm; + int policy; + if(pthread_getschedparam(id,&policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to get parms"); +#endif + return false; + } + else { + parm.sched_priority += dp; + if(pthread_setschedparam(id,policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to change priority"); +#endif + return false; + } + } + return true; +} + + +int flext_base::GetPriority(thrid_t id) +{ + sched_param parm; + int policy; + if(pthread_getschedparam(id,&policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to get parms"); +#endif + return -1; + } + return parm.sched_priority; +} + + +bool flext_base::SetPriority(int p,thrid_t id) +{ + sched_param parm; + int policy; + if(pthread_getschedparam(id,&policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to get parms"); +#endif + return false; + } + else { + parm.sched_priority = p; + if(pthread_setschedparam(id,policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to change priority"); +#endif + return false; + } + } + return true; +} + +flext_base::thr_params::thr_params(flext_base *c,int n): cl(c),var(new _data[n]) {} +flext_base::thr_params::~thr_params() { if(var) delete[] var; } + +void flext_base::thr_params::set_any(const t_symbol *s,int argc,const t_atom *argv) { var[0]._any.args = new AtomAnything(s,argc,argv); } +void flext_base::thr_params::set_list(int argc,const t_atom *argv) { var[0]._list.args = new AtomList(argc,argv); } + +#endif // FLEXT_THREADS diff --git a/externals/grill/flext/source/flutil.cpp b/externals/grill/flext/source/flutil.cpp new file mode 100644 index 00000000..509c3ab4 --- /dev/null +++ b/externals/grill/flext/source/flutil.cpp @@ -0,0 +1,68 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flutil.cpp + \brief Implementation of the various utility functions. +*/ + +#include "flext.h" +#include <string.h> + +#ifdef NT +#include <windows.h> +#endif + +#ifdef MAXMSP +#include <Timer.h> +#include <Threads.h> +#endif + +#ifdef unix +#include <unistd.h> +#endif + +//namespace flext { + +t_atom *flext::CopyList(int argc,const t_atom *argv) +{ + int i; + t_atom *dst = new t_atom[argc]; + for(i = 0; i < argc; ++i) CopyAtom(dst+i,argv+i); + return dst; +} + +void flext::CopyMem(void *dst,const void *src,int bytes) +{ +#ifdef macintosh + BlockMoveData(src,dst,bytes); +#else + memcpy(dst,src,bytes); +#endif +} + +void flext::Sleep(float s) +{ +#ifdef NT + ::Sleep((long)(s*1000)); +#elif defined MAXMSP + UnsignedWide tick; + Microseconds(&tick); + double target = tick.hi*((double)(1L<<((sizeof tick.lo)*4))*(double)(1L<<((sizeof tick.lo)*4)))+tick.lo+s*1.e6; + for(;;) { + Microseconds(&tick); + if(target <= tick.hi*((double)(1L<<((sizeof tick.lo)*4))*(double)(1L<<((sizeof tick.lo)*4)))+tick.lo) break; + YieldToAnyThread(); // should we really yield? + } +#else + usleep((long)(s*1000000)); +#endif +} + +//} // namespace flext diff --git a/externals/grill/flext/source/flxlet.cpp b/externals/grill/flext/source/flxlet.cpp new file mode 100755 index 00000000..881769da --- /dev/null +++ b/externals/grill/flext/source/flxlet.cpp @@ -0,0 +1,88 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flxlet.cpp + \brief Implementation of the variable inlet/outlet functionality. +*/ + +#include "flext.h" +#include "flinternal.h" +#include <string.h> +#include <stdarg.h> + +//namespace flext { + +flext_base::xlet::xlet(type t,const char *d): + tp(t),nxt(NULL) +{ + if(d) { + int ln = strlen(d); + desc = new char[ln]; + strncpy(desc,d,ln); + } + else desc = NULL; +} + +flext_base::xlet::~xlet() +{ + if(desc) delete[] desc; + if(nxt) delete nxt; +} + +void flext_base::AddXlet(xlet::type tp,int mult,const char *desc,xlet *&root) +{ + if(!root && mult) { root = new xlet(tp,desc); --mult; } + if(mult) { + xlet *xi = root; + while(xi->nxt) xi = xi->nxt; + while(mult--) xi = xi->nxt = new xlet(tp,desc); + } +} + +void flext_base::DescXlet(int ix,const char *desc,xlet *&root) +{ + post("%s - sorry, not implemented",thisName()); +} + +unsigned long flext_base::XletCode(xlet::type tp,...) +{ + unsigned long code = 0; + + va_list marker; + va_start(marker,tp); + int cnt = 0; + xlet::type *args = NULL,arg = tp; + for(; arg; ++cnt) { +#ifdef _DEBUG + if(cnt > 9) { + error("%s - Too many in/outlets defined - truncated to 9",thisName()); + break; + } +#endif + + code = code*10+(int)arg; + arg = (xlet::type)va_arg(marker,int); + } + va_end(marker); + + return code; +} + +void flext_base::AddInlets(unsigned long code) +{ + for(; code; code /= 10) AddInlet((xlet::type)(code%10)); +} + +void flext_base::AddOutlets(unsigned long code) +{ + for(; code; code /= 10) AddOutlet((xlet::type)(code%10)); +} + +//} // namespace flext |