flsupport.h
Go to the documentation of this file.
/*
flext - C++ layer for Max and Pure Data externals
Copyright (c) 2001-2015 Thomas Grill (gr@grrrr.org)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.
*/
#ifndef __FLSUPPORT_H
#define __FLSUPPORT_H
#include "flstdc.h"
#include <new>
#include <cstring>
#include "flpushns.h"
#if C74_MAX_SDK_VERSION >= 0x0610
// really bad: post and error are #defines in Max SDK >= 610
#undef post
#undef error
#endif
FLEXT_TEMPLATE class FLEXT_SHARE FLEXT_CLASSDEF(flext_root);
typedef FLEXT_TEMPINST(FLEXT_SHARE FLEXT_CLASSDEF(flext_root)) flext_root;
FLEXT_TEMPLATE
class FLEXT_SHARE FLEXT_CLASSDEF(flext_root) {
public:
// --- console output -----------------------------------------------
static void post(const char *fmt,...);
static void error(const char *fmt,...);
// --- memory -------------------------------------------------------
#ifdef FLEXT_NOGLOBALNEW
#error FLEXT_NOGLOBALNEW is deprecated, define FLEXT_USE_CMEM instead
#define FLEXT_USE_CMEM
#endif
#ifdef FLEXT_USE_CMEM
inline void *operator new(size_t bytes) { return ::operator new(bytes); }
inline void operator delete(void *blk) { ::operator delete(blk); }
inline void *operator new[](size_t bytes) { return ::operator new[](bytes); }
inline void operator delete[](void *blk) { ::operator delete[](blk); }
static bool MemCheck(void *) { return true; }
#else
void *operator new(size_t bytes);
void operator delete(void *blk);
#ifndef __MRC__ // doesn't allow new[] overloading?!
inline void *operator new[](size_t bytes) { return operator new(bytes); }
inline void operator delete[](void *blk) { operator delete(blk); }
#endif
#ifdef FLEXT_DEBUGMEM
static bool MemCheck(void *blk);
#else
static bool MemCheck(void *) { return true; }
#endif
#endif // USECMEM
#ifndef __BORLANDC__
inline void *operator new(size_t,void *p) { return p; }
inline void operator delete(void *,void *) {}
#ifndef __MRC__
inline void *operator new[](size_t,void *p) { return p; }
inline void operator delete[](void *,void *) {}
#endif
#endif
static void *NewAligned(size_t bytes,int bitalign = 128);
// same with templated type
template<typename T>
static T *NewAligned(size_t times,int bitalign = 128) { return static_cast<T *>(NewAligned(times*sizeof(T),bitalign)); }
static void FreeAligned(void *blk);
static bool IsAligned(void *ptr,int bitalign = 128) {
return (reinterpret_cast<size_t>(ptr)&(bitalign-1)) == 0;
}
};
#ifndef FLEXT_USE_CMEM
/************************************************************************/
// MFC doesn't like global overloading of allocators
// anyway, who likes MFC
#if !defined(_MSC_VER) && !defined(__BORLANDC__)
#define NEWTHROW throw(std::bad_alloc)
#define DELTHROW throw()
#else
#define NEWTHROW
#define DELTHROW
#endif
// define global new/delete operators
inline void *operator new(size_t bytes) NEWTHROW { return flext_root::operator new(bytes); }
inline void operator delete(void *blk) DELTHROW { flext_root::operator delete(blk); }
#ifndef __MRC__ // doesn't allow new[] overloading?!
inline void *operator new[](size_t bytes) NEWTHROW { return flext_root::operator new[](bytes); }
inline void operator delete[](void *blk) DELTHROW { flext_root::operator delete[](blk); }
#endif
#endif // FLEXT_USE_CMEM
/************************************************************************/
FLEXT_TEMPLATE class FLEXT_SHARE FLEXT_CLASSDEF(flext);
typedef FLEXT_TEMPINST(FLEXT_CLASSDEF(flext)) flext;
FLEXT_TEMPLATE class FLEXT_SHARE FLEXT_CLASSDEF(flext_base);
FLEXT_TEMPLATE
class FLEXT_SHARE FLEXT_CLASSDEF(flext):
public flext_root
{
public:
// --- version -----------------------------------------------
static int Version();
static const char *VersionStr();
// --- special typedefs ---------------------------------------------
// later!
#if 0
typedef t_float Float;
typedef t_int Int;
typedef t_sample Sample;
typedef const t_symbol *Symbol;
typedef t_atom Atom;
#endif
// --- buffer/array stuff -----------------------------------------
class FLEXT_SHARE buffer:
public flext_root
{
public:
#if FLEXT_SYS == FLEXT_SYS_PD
typedef bool lock_t;
#elif FLEXT_SYS == FLEXT_SYS_MAX
typedef long lock_t;
#else
#error Not implemented
#endif
// PD 64-bit buffer handling macros
#if FLEXT_SYS == FLEXT_SYS_PD
# if PD_MINOR_VERSION >= 41
/* use new garray support that is 64-bit safe */
# define FLEXT_PD_ARRAYGRAB garray_getfloatwords
# define FLEXT_ARRAYTYPE t_word
# define FLEXT_GETSAMPLE(x) ((x).w_float)
# else
/* use old garray support, not 64-bit safe */
# define FLEXT_PD_ARRAYGRAB garray_getfloatarray
# define FLEXT_ARRAYTYPE t_sample
# define FLEXT_GETSAMPLE(x) (x)
# endif
#elif FLEXT_SYS == FLEXT_SYS_MAX
# define FLEXT_ARRAYTYPE t_sample
# define FLEXT_GETSAMPLE(x) (x)
#endif
class Element {
public:
Element() {}
Element(t_sample s) { FLEXT_GETSAMPLE(el) = s; }
operator t_sample &() { return FLEXT_GETSAMPLE(el); }
operator t_sample () const { return FLEXT_GETSAMPLE(el); }
protected:
FLEXT_ARRAYTYPE el;
};
buffer(const t_symbol *s = NULL,bool delayed = false);
~buffer();
bool Ok() const
{
return sym
#if FLEXT_SYS == FLEXT_SYS_PD
&& arr
#endif
&& data;
}
bool Valid() const
{
FLEXT_ASSERT(sym);
#if FLEXT_SYS == FLEXT_SYS_PD
return true;
#elif FLEXT_SYS == FLEXT_SYS_MAX
const t_buffer *p = (const t_buffer *)sym->s_thing;
return p && p->b_valid;
#else
#error not implemented
#endif
}
bool Update();
lock_t Lock();
void Unlock(lock_t prv);
int Set(const t_symbol *s = NULL,bool nameonly = false);
void Dirty(bool refr = false);
void ClearDirty();
bool IsDirty() const;
const t_symbol *Symbol() const { return sym; }
const char *Name() const { return sym?GetString(sym):""; }
Element *Data() { return data; }
const Element *Data() const { return data; }
int Channels() const { return chns; }
int Frames() const { return frames; }
void Frames(int fr,bool keep = false,bool zero = true);
inline t_sample operator [](int index) const { return data[index]; }
inline t_sample &operator [](int index) { return data[index]; }
void SetRefrIntv(float intv);
class Locker
{
public:
Locker(buffer &b): buf(b),lock(b.Lock()) {}
~Locker() { buf.Unlock(lock); }
private:
buffer &buf;
lock_t lock;
};
protected:
const t_symbol *sym;
Element *data;
int chns;
int frames;
#if FLEXT_SYS == FLEXT_SYS_PD
t_garray *arr;
float interval;
bool isdirty;
bool ticking;
t_clock *tick;
double cleantime;
private:
static void cb_tick(buffer *b);
#elif FLEXT_SYS == FLEXT_SYS_MAX
long cleantime;
#endif
};
// --- utilities --------------------------------------------------
static void CopyAtom(t_atom *dst,const t_atom *src) { *dst = *src; }
static void CopyAtoms(int cnt,t_atom *dst,const t_atom *src);
static bool PrintAtom(const t_atom &a,char *buf,size_t bufsz);
static const char *ScanAtom(t_atom &a,const char *buf);
static t_atom *CopyList(int argc,const t_atom *argv);
static bool PrintList(int argc,const t_atom *argv,char *buf,size_t bufsz);
static int ScanList(int argc,t_atom *argv,const char *buf);
static void CopyMem(void *dst,const void *src,int bytes);
static void CopySamples(t_sample *dst,const t_sample *src,int cnt);
template<typename T> static void CopySamples(T *dst,const T *src,int cnt) { CopyMem(dst,src,sizeof(*src)*cnt); }
static void ZeroMem(void *dst,int bytes);
static void SetSamples(t_sample *dst,int cnt,t_sample s);
template<typename T> static void SetSamples(T *dst,int cnt,t_sample s) { for(int i = 0; i < cnt; ++i) dst[i] = s; }
static void ZeroSamples(t_sample *dst,int cnt) { SetSamples(dst,cnt,0); }
template<typename T> static void ZeroSamples(T *dst,int cnt) { ZeroMem(dst,sizeof(*dst)*cnt); }
static unsigned long AtomHash(const t_atom &a);
// --- various symbols --------------------------------------------
static const t_symbol *sym__;
static const t_symbol *sym_float;
static const t_symbol *sym_symbol;
static const t_symbol *sym_bang;
static const t_symbol *sym_list;
static const t_symbol *sym_anything;
static const t_symbol *sym_int;
static const t_symbol *sym_pointer;
static const t_symbol *sym_signal;
static const t_symbol *MakeSymbol(const t_symbol *s) { return s; }
static const t_symbol *MakeSymbol(const char *s) { return ::gensym(const_cast<char *>(s)); }
static const char *GetString(const t_symbol *s) { return s->s_name; }
static const char *GetAString(const t_symbol *s,const char *def = NULL) { return s?GetString(s):def; }
// --- atom stuff ----------------------------------------
static void SetAtom(t_atom &a,const t_atom &b) { CopyAtom(&a,&b); }
static int CmpAtom(const t_atom &a,const t_atom &b);
// there are some more comparison functions for t_atom types outside the class
static int GetType(const t_atom &a) { return a.a_type; }
static bool IsNothing(const t_atom &a) { return a.a_type == A_NULL; }
static void SetNothing(t_atom &a) { a.a_type = A_NULL; }
static bool IsFloat(const t_atom &a) { return a.a_type == A_FLOAT; }
static bool CanbeFloat(const t_atom &a) { return IsFloat(a) || IsInt(a); }
static float GetFloat(const t_atom &a) { return a.a_w.w_float; }
static void SetFloat(t_atom &a,float v) { a.a_type = A_FLOAT; a.a_w.w_float = v; }
static bool IsSymbol(const t_atom &a) { return a.a_type == A_SYMBOL; }
#if FLEXT_SYS == FLEXT_SYS_PD
static const t_symbol *GetSymbol(const t_atom &a) { return const_cast<const t_symbol *>(a.a_w.w_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); }
#elif FLEXT_SYS == FLEXT_SYS_MAX
static const t_symbol *GetSymbol(const t_atom &a) { return const_cast<const t_symbol *>(a.a_w.w_sym); }
static void SetSymbol(t_atom &a,const t_symbol *s) { a.a_type = A_SYMBOL; a.a_w.w_sym = const_cast<t_symbol *>(s); }
#else
#error
#endif
static const t_symbol *GetASymbol(const t_atom &a,const t_symbol *def = NULL) { return IsSymbol(a)?GetSymbol(a):def; } // NULL or empty symbol?
static bool IsString(const t_atom &a) { return IsSymbol(a); }
static const char *GetString(const t_atom &a) { const t_symbol *s = GetSymbol(a); return s?GetString(s):NULL; }
static const char *GetAString(const t_atom &a,const char *def = NULL) { return IsSymbol(a)?GetAString(GetSymbol(a),def):def; }
static void GetAString(const t_atom &a,char *buf,size_t szbuf);
static void SetString(t_atom &a,const char *c) { SetSymbol(a,MakeSymbol(c)); }
static bool CanbeInt(const t_atom &a) { return IsFloat(a) || IsInt(a); }
#if FLEXT_SYS == FLEXT_SYS_PD
static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):def; }
static bool IsInt(const t_atom &) { return false; }
static int GetInt(const t_atom &a) { return (int)GetFloat(a); }
static int GetAInt(const t_atom &a,int def = 0) { return (int)GetAFloat(a,(float)def); }
static void SetInt(t_atom &a,int v) { a.a_type = A_FLOAT; a.a_w.w_float = (float)v; }
#ifndef FLEXT_COMPATIBLE
static bool IsPointer(const t_atom &a) { return a.a_type == A_POINTER; }
static bool CanbePointer(const t_atom &a) { return IsPointer(a); }
static t_gpointer *GetPointer(const t_atom &a) { return a.a_w.w_gpointer; }
static t_gpointer *GetAPointer(const t_atom &a,t_gpointer *def = NULL) { return IsPointer(a)?GetPointer(a):def; }
static void SetPointer(t_atom &a,t_gpointer *p) { a.a_type = A_POINTER; a.a_w.w_gpointer = (t_gpointer *)p; }
#endif
#elif FLEXT_SYS == FLEXT_SYS_MAX
static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):(IsInt(a)?GetInt(a):def); }
static bool IsInt(const t_atom &a) { return a.a_type == A_INT; }
static int GetInt(const t_atom &a) { return a.a_w.w_long; }
static int GetAInt(const t_atom &a,int def = 0) { return IsInt(a)?GetInt(a):(IsFloat(a)?(int)GetFloat(a):def); }
static void SetInt(t_atom &a,int v) { a.a_type = A_INT; a.a_w.w_long = v; }
#else
#error "Platform not supported"
#endif
// bool type - based on int
static void SetBool(t_atom &a,bool v) { SetInt(a,v?1:0); }
static bool CanbeBool(const t_atom &a) { return CanbeInt(a); }
static bool GetABool(const t_atom &a) { return GetAInt(a) != 0; }
static bool GetBool(const t_atom &a) { return GetInt(a) != 0; }
// --- atom list stuff -------------------------------------------
class FLEXT_SHARE AtomList
: public flext_root
{
public:
AtomList(): cnt(0),lst(NULL) {}
explicit AtomList(int argc,const t_atom *argv = NULL): cnt(0),lst(NULL) { operator()(argc,argv); }
AtomList(const AtomList &a): cnt(0),lst(NULL) { operator =(a); }
virtual ~AtomList();
AtomList &Clear() { return operator()(); }
AtomList &Set(int argc,const t_atom *argv,int offs = 0,bool resize = false);
int Get(t_atom *argv,int mxsz = -1) const;
AtomList &operator()(int argc = 0,const t_atom *argv = NULL) { return Set(argc,argv,0,true); }
AtomList &operator =(const AtomList &a) { return operator()(a.Count(),a.Atoms()); }
int Compare(const AtomList &a) const;
bool operator <(const AtomList &a) const { return Compare(a) < 0; }
bool operator <=(const AtomList &a) const { return Compare(a) <= 0; }
bool operator >(const AtomList &a) const { return Compare(a) > 0; }
bool operator >=(const AtomList &a) const { return Compare(a) >= 0; }
bool operator ==(const AtomList &a) const { return Compare(a) == 0; }
bool operator !=(const AtomList &a) const { return Compare(a) != 0; }
int Count() const { return cnt; }
t_atom &operator [](int ix) { return lst[ix]; }
const t_atom &operator [](int ix) const { return lst[ix]; }
t_atom *Atoms() { return lst; }
const t_atom *Atoms() const { return lst; }
AtomList &Append(int argc,const t_atom *argv = NULL)
{
int c = Count();
Alloc(c+argc,0,c);
Set(argc,argv,c);
return *this;
}
AtomList &Prepend(int argc,const t_atom *argv = NULL)
{
int c = Count();
Alloc(c+argc,0,c,argc);
Set(argc,argv);
return *this;
}
AtomList &Append(const t_atom &a) { return Append(1,&a); }
AtomList &Append(const AtomList &a) { return Append(a.Count(),a.Atoms()); }
AtomList &Prepend(const t_atom &a) { return Prepend(1,&a); }
AtomList &Prepend(const AtomList &a) { return Prepend(a.Count(),a.Atoms()); }
void GetPart(int offs,int len,AtomList &ret) const;
AtomList &Part(int offs,int len) { GetPart(offs,len,*this); return *this; }
bool Print(char *buffer,int buflen) const { return flext::PrintList(Count(),Atoms(),buffer,buflen); }
int Scan(const char *buffer) { return flext::ScanList(Count(),Atoms(),buffer); }
protected:
virtual void Alloc(int sz,int keepix = -1,int keeplen = -1,int keepto = 0);
virtual void Free();
int cnt;
t_atom *lst;
};
class FLEXT_SHARE AtomListStaticBase
: public AtomList
{
protected:
explicit AtomListStaticBase(int pc,t_atom *dt): precnt(pc),predata(dt) {}
virtual ~AtomListStaticBase();
virtual void Alloc(int sz,int keepix = -1,int keeplen = -1,int keepto = 0);
virtual void Free();
AtomListStaticBase &operator =(const AtomList &a) { AtomList::operator =(a); return *this; }
AtomListStaticBase &operator =(const AtomListStaticBase &a) { AtomList::operator =(a); return *this; }
const int precnt;
t_atom *const predata;
};
template<int PRE>
class AtomListStatic
: public AtomListStaticBase
{
public:
explicit AtomListStatic(): AtomListStaticBase(PRE,pre) {}
explicit AtomListStatic(int argc,const t_atom *argv = NULL): AtomListStaticBase(PRE,pre) { AtomList::operator()(argc,argv); }
explicit AtomListStatic(const AtomList &a): AtomListStaticBase(PRE,pre) { operator =(a); }
AtomListStatic &operator =(const AtomList &a) { AtomListStaticBase::operator =(a); return *this; }
AtomListStatic &operator =(const AtomListStatic &a) { AtomListStaticBase::operator =(a); return *this; }
protected:
t_atom pre[PRE];
};
class FLEXT_SHARE AtomAnything:
public AtomList
{
public:
explicit AtomAnything(): hdr(NULL) {}
explicit AtomAnything(const t_symbol *h,int argc = 0,const t_atom *argv = NULL)
: AtomList(argc,argv),hdr(h?h:sym__)
{}
explicit AtomAnything(const char *h,int argc = 0,const t_atom *argv = NULL)
: AtomList(argc,argv),hdr(MakeSymbol(h))
{}
AtomAnything(const AtomAnything &a)
: AtomList(a),hdr(a.hdr)
{}
AtomAnything &Clear() { return operator()(); }
const t_symbol *Header() const { return hdr; }
void Header(const t_symbol *h) { hdr = h; }
AtomAnything &operator()(const t_symbol *h = NULL,int argc = 0,const t_atom *argv = NULL)
{
hdr = h; AtomList::operator()(argc,argv);
return *this;
}
AtomAnything &operator =(const AtomAnything &a) { return operator()(a.Header(),a.Count(),a.Atoms()); }
protected:
const t_symbol *hdr;
};
// double type - based on two floats
#ifdef _MSC_VER
#pragma optimize("p",off) // improve floating point precision consistency
#endif
static t_atom *SetDouble(t_atom *dbl,double d)
{
float f = static_cast<float>(d);
float r = static_cast<float>(d-f);
SetFloat(dbl[0],f);
SetFloat(dbl[1],r);
return dbl;
}
#ifdef _MSC_VER
#pragma optimize("p",on)
#endif
static double GetDouble(int argc,const t_atom *argv)
{
double d = argc >= 1?GetAFloat(argv[0]):0;
return argc >= 2?d+GetAFloat(argv[1]):d;
}
static AtomList &SetDouble(AtomList &l,double d) { SetDouble(l(2).Atoms(),d); return l; }
static double GetDouble(const AtomList &l) { return GetDouble(l.Count(),l.Atoms()); }
// --- messages -------------------------------------------------------
class MsgBundle;
static MsgBundle *MsgNew();
static void MsgFree(MsgBundle *mb);
static void ToSysMsg(MsgBundle *mb);
static void ToOutMsg(MsgBundle *mb);
static void ToQueueMsg(MsgBundle *mb);
static bool Forward(const t_symbol *sym,const t_symbol *s,int argc,const t_atom *argv);
static bool Forward(const t_symbol *sym,const AtomAnything &args) { return Forward(sym,args.Header(),args.Count(),args.Atoms()); }
static bool Forward(const char *sym,const AtomAnything &args) { return Forward(MakeSymbol(sym),args.Header(),args.Count(),args.Atoms()); }
static bool Forward(const t_symbol *sym,int argc,const t_atom *argv) { return Forward(sym,sym_list,argc,argv); }
static bool Forward(const t_symbol *sym,const AtomList &args) { return Forward(sym,args.Count(),args.Atoms()); }
static bool Forward(const char *sym,const AtomList &args) { return Forward(MakeSymbol(sym),args.Count(),args.Atoms()); }
static bool SysForward(const t_symbol *sym,const t_symbol *s,int argc,const t_atom *argv);
static bool SysForward(const t_symbol *sym,const AtomAnything &args) { return SysForward(sym,args.Header(),args.Count(),args.Atoms()); }
static bool SysForward(const char *sym,const AtomAnything &args) { return SysForward(MakeSymbol(sym),args.Header(),args.Count(),args.Atoms()); }
static bool SysForward(const t_symbol *sym,int argc,const t_atom *argv) { return SysForward(sym,sym_list,argc,argv); }
static bool SysForward(const t_symbol *sym,const AtomList &args) { return SysForward(sym,args.Count(),args.Atoms()); }
static bool SysForward(const char *sym,const AtomList &args) { return SysForward(MakeSymbol(sym),args.Count(),args.Atoms()); }
static bool QueueForward(const t_symbol *sym,const t_symbol *s,int argc,const t_atom *argv);
static bool QueueForward(const t_symbol *sym,const AtomAnything &args) { return QueueForward(sym,args.Header(),args.Count(),args.Atoms()); }
static bool QueueForward(const char *sym,const AtomAnything &args) { return QueueForward(MakeSymbol(sym),args.Header(),args.Count(),args.Atoms()); }
static bool QueueForward(const t_symbol *sym,int argc,const t_atom *argv) { return QueueForward(sym,sym_list,argc,argv); }
static bool QueueForward(const t_symbol *sym,const AtomList &args) { return QueueForward(sym,args.Count(),args.Atoms()); }
static bool QueueForward(const char *sym,const AtomList &args) { return QueueForward(MakeSymbol(sym),args.Count(),args.Atoms()); }
static bool MsgForward(MsgBundle *mb,const t_symbol *sym,const t_symbol *s,int argc,const t_atom *argv);
static bool MsgForward(MsgBundle *mb,const t_symbol *sym,const AtomAnything &args) { return MsgForward(mb,sym,args.Header(),args.Count(),args.Atoms()); }
static bool MsgForward(MsgBundle *mb,const char *sym,const AtomAnything &args) { return MsgForward(mb,MakeSymbol(sym),args.Header(),args.Count(),args.Atoms()); }
static bool MsgForward(MsgBundle *mb,const t_symbol *sym,int argc,const t_atom *argv) { return MsgForward(mb,sym,sym_list,argc,argv); }
static bool MsgForward(MsgBundle *mb,const t_symbol *sym,const AtomList &args) { return MsgForward(mb,sym,args.Count(),args.Atoms()); }
static bool MsgForward(MsgBundle *mb,const char *sym,const AtomList &args) { return MsgForward(mb,MakeSymbol(sym),args.Count(),args.Atoms()); }
// --- thread stuff -----------------------------------------------
#if FLEXT_SYS == FLEXT_SYS_PD
#if PD_MINOR_VERSION >= 38 || (PD_MINOR_VERSION >= 37 && defined(PD_DEVEL_VERSION))
static void Lock() { sys_lock(); }
static void Unlock() { sys_unlock(); }
#else
// no system locking for old PD versions
static void Lock() {}
static void Unlock() {}
#endif
#elif FLEXT_SYS == FLEXT_SYS_MAX
// Max 4.2 upwards!
static void Lock() { critical_enter(0); }
static void Unlock() { critical_exit(0); }
#else
#error
#endif
#ifdef FLEXT_THREADS
static bool IsThreadRegistered();
#else
static bool IsThreadRegistered() { return false; }
#endif
#ifdef FLEXT_THREADS
# if FLEXT_THREADS == FLEXT_THR_MP
typedef MPTaskID thrid_t;
# elif FLEXT_THREADS == FLEXT_THR_POSIX
typedef pthread_t thrid_t;
# elif FLEXT_THREADS == FLEXT_THR_WIN32
typedef DWORD thrid_t;
# else
# error Threading model not supported
# endif
static thrid_t GetThreadId() {
#if FLEXT_THREADS == FLEXT_THR_POSIX
return pthread_self();
#elif FLEXT_THREADS == FLEXT_THR_MP
return MPCurrentTaskID();
#elif FLEXT_THREADS == FLEXT_THR_WIN32
return GetCurrentThreadId();
#else
#error
#endif
}
static thrid_t GetSysThreadId() { return thrid; }
static bool ShouldExit();
static bool IsThread(thrid_t t,thrid_t ref = GetThreadId()) {
#if FLEXT_THREADS == FLEXT_THR_POSIX
return pthread_equal(ref,t) != 0;
#else
return ref == t;
#endif
}
class FLEXT_SHARE thr_params:
public flext_root
{
public:
thr_params(int n = 1): cl(NULL),var(new _data[n]) {}
~thr_params() { delete[] var; }
void set_any(const t_symbol *s,int argc,const t_atom *argv) { var[0]._any = new AtomAnything(s,argc,argv); }
void set_list(int argc,const t_atom *argv) { var[0]._list = new AtomList(argc,argv); }
FLEXT_TEMPINST(FLEXT_CLASSDEF(flext_base)) *cl;
union _data {
bool _bool;
float _float;
int _int;
t_symptr _t_symptr;
AtomAnything *_any;
AtomList *_list;
void *_ext;
} *var;
};
protected:
static thrid_t thrhelpid;
static thrid_t thrmsgid;
static void ThrHelper(void *);
static thrid_t thrid; // the system thread
private:
static bool StartHelper(); // used in flext::Setup()
public:
static void ThrYield() {
#if FLEXT_THREADS == FLEXT_THR_POSIX
// for a preemptive system this should do nothing
sched_yield();
#elif FLEXT_THREADS == FLEXT_THR_MP
MPYield();
#elif FLEXT_THREADS == FLEXT_THR_WIN32
SwitchToThread();
#else
#error
#endif
}
static bool IsThreadPreemptive(thrid_t t = GetThreadId()) {
#if FLEXT_THREADS == FLEXT_THR_POSIX || FLEXT_THREADS == FLEXT_THR_WIN32
return true;
#elif FLEXT_THREADS == FLEXT_THR_MP
return MPTaskIsPreemptive(t);
#else
#error
#endif
}
static bool RelPriority(int dp,thrid_t ref = GetSysThreadId(),thrid_t thr = GetThreadId());
static int GetPriority(thrid_t thr = GetThreadId());
static bool SetPriority(int p,thrid_t thr = GetThreadId());
class FLEXT_SHARE ThrMutex:
public flext_root
#if FLEXT_THREADS == FLEXT_THR_POSIX
{
public:
ThrMutex() { pthread_mutex_init(&mutex,NULL); }
~ThrMutex() { pthread_mutex_destroy(&mutex); }
bool Lock() { return pthread_mutex_lock(&mutex) == 0; }
// bool WaitForLock(double tm) { return pthread_mutex_lock(&mutex) == 0; }
bool TryLock() { return pthread_mutex_trylock(&mutex) == 0; }
bool Unlock() { return pthread_mutex_unlock(&mutex) == 0; }
protected:
pthread_mutex_t mutex;
// int cnt;
};
#elif FLEXT_THREADS == FLEXT_THR_WIN32
{
public:
ThrMutex() { ::InitializeCriticalSection(&mutex); }
~ThrMutex() { ::DeleteCriticalSection(&mutex); }
bool Lock() { ::EnterCriticalSection(&mutex); return true; }
// bool WaitForLock(double tm) { return pthread_mutex_lock(&mutex) == 0; }
bool TryLock() { return ::TryEnterCriticalSection(&mutex) != 0; }
bool Unlock() { ::LeaveCriticalSection(&mutex); return true; }
protected:
CRITICAL_SECTION mutex;
};
#elif FLEXT_THREADS == FLEXT_THR_MP
{
public:
ThrMutex() { MPCreateCriticalRegion(&crit); }
~ThrMutex() { MPDeleteCriticalRegion(crit); }
bool Lock() { return MPEnterCriticalRegion(crit,kDurationForever) == noErr; }
// bool WaitForLock(double tm) { return MPEnterCriticalRegion(crit,tm*kDurationMicrosecond*1.e6) == noErr; }
bool TryLock() { return MPEnterCriticalRegion(crit,kDurationImmediate) == noErr; }
bool Unlock() { return MPExitCriticalRegion(crit) == noErr; }
protected:
MPCriticalRegionID crit;
};
#else
#error "Not implemented"
#endif
class FLEXT_SHARE ThrCond
#if FLEXT_THREADS == FLEXT_THR_POSIX
:public ThrMutex
{
public:
ThrCond() { pthread_cond_init(&cond,NULL); }
~ThrCond() { pthread_cond_destroy(&cond); }
bool Wait();
bool TimedWait(double ftime);
bool Signal() { return pthread_cond_signal(&cond) == 0; }
protected:
pthread_cond_t cond;
};
#elif FLEXT_THREADS == FLEXT_THR_WIN32
{
public:
ThrCond() { cond = CreateEvent(NULL,FALSE,FALSE,NULL); }
~ThrCond() { CloseHandle(cond); }
bool Wait() { return WaitForSingleObject(cond,INFINITE) == WAIT_OBJECT_0; }
bool TimedWait(double ftime) { return WaitForSingleObject(cond,(LONG)(ftime*1000)) == WAIT_OBJECT_0; }
bool Signal() { return SetEvent(cond) != 0; }
protected:
HANDLE cond;
};
#elif FLEXT_THREADS == FLEXT_THR_MP
{
public:
ThrCond() { MPCreateEvent(&ev); }
~ThrCond() { MPDeleteEvent(ev); }
bool Wait() { return MPWaitForEvent(ev,NULL,kDurationForever) == noErr; }
bool TimedWait(double tm) { return MPWaitForEvent(ev,NULL,tm*kDurationMicrosecond*1.e6) == noErr; }
bool Signal() { return MPSetEvent(ev,1) == noErr; } // one bit needs to be set at least
protected:
MPEventID ev;
};
#else
#error "Not implemented"
#endif
protected:
static bool PushThread();
static void PopThread();
public:
static bool LaunchThread(void (*meth)(thr_params *p),thr_params *params = NULL);
static bool StopThread(void (*meth)(thr_params *p),thr_params *params = NULL,bool wait = false);
static void RegisterThread(thrid_t id = GetThreadId());
static void UnregisterThread(thrid_t id = GetThreadId());
#endif // FLEXT_THREADS
public:
// --- timer stuff -----------------------------------------------
static double GetTime()
{
#if FLEXT_SYS == FLEXT_SYS_PD
return clock_gettimesince(0)*0.001;
#elif FLEXT_SYS == FLEXT_SYS_MAX
double tm;
clock_getftime(&tm);
return tm*0.001;
#else
#error Not implemented
#endif
}
static double GetTimeGrain()
{
#if FLEXT_SYS == FLEXT_SYS_PD
return 0;
#elif FLEXT_SYS == FLEXT_SYS_MAX
return 0.001;
#else
#error Not implemented
#endif
}
static double GetOSTime();
static void Sleep(double s);
class FLEXT_SHARE Timer:
public flext_root
{
public:
Timer(bool queued = false);
virtual ~Timer();
void SetCallback(void (*cb)(void *data)) { clss = NULL,cback = cb; }
void SetCallback(FLEXT_TEMPINST(FLEXT_CLASSDEF(flext_base)) &th,bool (*cb)(FLEXT_TEMPINST(FLEXT_CLASSDEF(flext_base)) *th,void *data)) { clss = &th,cback = (void (*)(void *))cb; }
bool Reset();
bool At(double time,void *data = NULL,bool dopast = true);
bool Delay(double time,void *data = NULL);
bool Periodic(double time,void *data = NULL);
bool Now(void *data = NULL) { return Delay(0,data); }
virtual void Work();
protected:
static void callback(Timer *tmr);
#if FLEXT_SYS == FLEXT_SYS_PD
t_clock *clk;
#elif FLEXT_SYS == FLEXT_SYS_MAX
static void queuefun(Timer *tmr);
t_clock *clk;
t_qelem *qelem;
#else
#error Not implemented
#endif
const bool queued;
void (*cback)(void *data);
FLEXT_TEMPINST(FLEXT_CLASSDEF(flext_base)) *clss;
void *userdata;
double period;
};
static bool InDSP() { return indsp; }
// --- SIMD functionality -----------------------------------------------
enum simd_type {
simd_none = 0,
simd_mmx = 0x01,
simd_3dnow = 0x02,
simd_sse = 0x04,
simd_sse2 = 0x08,
simd_altivec = 0x10
};
static unsigned long GetSIMDCapabilities();
static void MulSamples(t_sample *dst,const t_sample *src,t_sample mul,int cnt);
static void MulSamples(t_sample *dst,const t_sample *src,const t_sample *mul,int cnt);
static void AddSamples(t_sample *dst,const t_sample *src,t_sample add,int cnt);
static void AddSamples(t_sample *dst,const t_sample *src,const t_sample *add,int cnt);
static void ScaleSamples(t_sample *dst,const t_sample *src,t_sample mul,t_sample add,int cnt);
static void ScaleSamples(t_sample *dst,const t_sample *src,t_sample mul,const t_sample *add,int cnt);
static void ScaleSamples(t_sample *dst,const t_sample *src,const t_sample *mul,const t_sample *add,int cnt);
protected:
#ifdef __MRC__
friend class flext_obj;
#endif
static void Setup();
static bool chktilde(const char *objname);
static unsigned long simdcaps;
static const t_symbol *sym_attributes;
static const t_symbol *sym_methods;
#if FLEXT_SYS == FLEXT_SYS_MAX
static const t_symbol *sym_buffer;
static const t_symbol *sym_size;
static const t_symbol *sym_dirty;
#endif
static bool indsp;
};
// gcc doesn't like these to be included into the flext class (even if static)
inline bool operator ==(const t_atom &a,const t_atom &b) { return flext::CmpAtom(a,b) == 0; }
inline bool operator !=(const t_atom &a,const t_atom &b) { return flext::CmpAtom(a,b) != 0; }
inline bool operator <(const t_atom &a,const t_atom &b) { return flext::CmpAtom(a,b) < 0; }
inline bool operator <=(const t_atom &a,const t_atom &b) { return flext::CmpAtom(a,b) <= 0; }
inline bool operator >(const t_atom &a,const t_atom &b) { return flext::CmpAtom(a,b) > 0; }
inline bool operator >=(const t_atom &a,const t_atom &b) { return flext::CmpAtom(a,b) >= 0; }
#include "flpopns.h"
#endif
FLEXT_CLASSDEF
FLEXT_TEMPLATE class FLEXT_SHARE FLEXT_CLASSDEF(flext_root)
operator<
bool operator<(const t_atom &a, const t_atom &b)
Definition: flsupport.h:1396
operator<=
bool operator<=(const t_atom &a, const t_atom &b)
Definition: flsupport.h:1397
t_symptr
t_symbol * t_symptr
Definition: flstdc.h:225
FLEXT_ASSERT
#define FLEXT_ASSERT(b)
Definition: flstdc.h:284
operator==
bool operator==(const t_atom &a, const t_atom &b)
Definition: flsupport.h:1394
FLEXT_THR_POSIX
#define FLEXT_THR_POSIX
Definition: flprefix.h:80
FLEXT_TEMPLATE
#define FLEXT_TEMPLATE
Definition: flprefix.h:455
NEWTHROW
#define NEWTHROW
Definition: flsupport.h:122
flpushns.h
DELTHROW
#define DELTHROW
Definition: flsupport.h:123
flpopns.h
FLEXT_SHARE
#define FLEXT_SHARE
Definition: flprefix.h:418
operator>=
bool operator>=(const t_atom &a, const t_atom &b)
Definition: flsupport.h:1399
flstdc.h
Definitions to unite Max/MSP and PD notions.
operator>
bool operator>(const t_atom &a, const t_atom &b)
Definition: flsupport.h:1398
FLEXT_TEMPINST
typedef FLEXT_TEMPINST(FLEXT_SHARE FLEXT_CLASSDEF(flext_root)) flext_root
operator!=
bool operator!=(const t_atom &a, const t_atom &b)
Definition: flsupport.h:1395