diff options
Diffstat (limited to 'externals/grill/flext/source/flsupport.h')
-rw-r--r-- | externals/grill/flext/source/flsupport.h | 1764 |
1 files changed, 925 insertions, 839 deletions
diff --git a/externals/grill/flext/source/flsupport.h b/externals/grill/flext/source/flsupport.h index 8202922c..1963e56c 100644 --- a/externals/grill/flext/source/flsupport.h +++ b/externals/grill/flext/source/flsupport.h @@ -1,839 +1,925 @@ -/*
-
-flext - C++ layer for Max/MSP and pd (pure data) externals
-
-Copyright (c) 2001-2003 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"
-#include <time.h>
-
-class FLEXT_SHARE flext_base;
-
-/*! \brief Flext support class
- A number of methods (most are static functions) are defined here for convenience.
- This class doesn't define any data members, hence it can be inherited to all
- classes (not only PD objects) to profit from the cross-platform functionality.
- Examples are the overloaded memory allocation, atom and atom list functions,
- thread functions and classes, the sample buffer class and others.
-*/
-class FLEXT_SHARE flext {
-
- /*! \defgroup FLEXT_SUPPORT Flext support class
- @{
- */
-public:
-
-// --- console output -----------------------------------------------
-
-#if FLEXT_SYS == FLEXT_SYS_JMAX
- //! post message to console
- static void post(const char *s,...);
- //! post error message to console
- static void error(const char *s,...);
-#endif
-
-// --- memory -------------------------------------------------------
-
- /*! \defgroup FLEXT_S_MEMORY Memory allocation functions
- @{
- */
-
- /*! Overloaded new memory allocation method
- \warning Max/MSP (or MacOS) allows only 16K in overdrive mode!
- */
- void *operator new(size_t bytes);
- //! Overloaded delete method
- 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
-
- //! Get an aligned memory block
- static void *NewAligned(size_t bytes,int bitalign = 128);
- //! Free an aligned memory block
- static void FreeAligned(void *blk);
-
- //! @} FLEXT_S_MEMORY
-
-// --- buffer/array stuff -----------------------------------------
-
- /*! \defgroup FLEXT_S_BUFFER Buffer handling
- @{
- */
-
-// not for Jmax at the moment
-#if FLEXT_SYS != FLEXT_SYS_JMAX
-
- //! Class for platform independent buffer handling
- class FLEXT_SHARE buffer
- {
- public:
- /*! \brief Construct buffer.
- \param s: symbol name, can be NULL
- \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 if buffer is valid
- */
- bool Valid() const;
-
- /*! \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?GetString(sym):""; }
-
- /*! \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;
-#if FLEXT_SYS == FLEXT_SYS_PD
- t_garray *arr;
- float interval;
- bool isdirty,ticking;
- t_clock *tick;
-
- private:
- static void cb_tick(buffer *b);
-#endif
- };
-
-#endif // jmax
-
-//! @} FLEXT_S_BUFFER
-
-// --- utilities --------------------------------------------------
-
- /*! \defgroup FLEXT_S_UTIL Utility functions
- @{
- */
-
- //! Copy an atom
- static void CopyAtom(t_atom *dst,const t_atom *src) { *dst = *src; }
-
- //! Print an atom
- static void PrintAtom(const t_atom &a,char *buf,int bufsz = 0);
- //! Scan an atom
- static bool ScanAtom(t_atom &a,const char *buf);
-
- //! 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);
- static void CopySamples(t_sample *dst,const t_sample *src,int cnt);
- //! Set a memory region
- static void ZeroMem(void *dst,int bytes);
- static void SetSamples(t_sample *dst,int cnt,t_sample s);
- static void ZeroSamples(t_sample *dst,int cnt) { SetSamples(dst,cnt,0); }
-
- //! Sleep for an amount of time
- static void Sleep(double s);
-
-
- //! Get a 32 bit hash value frm an atom
- static unsigned long AtomHash(const t_atom &a);
-
- /*! \brief Fold value to a number of bits
- \remark Good for hash tables
- */
- static unsigned int FoldBits(unsigned long h,int bits);
-
- //! \brief How many bits are necessary to represent n
- static int Int2Bits(unsigned long n);
-
-//! @} FLEXT_S_UTIL
-
-// --- various symbols --------------------------------------------
-
- /*! \defgroup FLEXT_S_ATOM Atom/list 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;
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- /*! \brief Symbol constant for "signal"
- \note PD only
- */
- static const t_symbol *sym_signal;
-#endif
-
-#if FLEXT_SYS == FLEXT_SYS_JMAX
- //! Make a symbol from a string
- static const t_symbol *MakeSymbol(const char *s) { return ::fts_new_symbol(s); }
- //! Get symbol string
- static const char *GetString(const t_symbol *s); // ** TODO **
-#else
- //! 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; }
-#endif
- //! Check for symbol and get string
- static const char *GetAString(const t_symbol *s,const char *def = "") { return s?GetString(s):def; }
-
-// --- atom stuff ----------------------------------------
-
- //! Set atom from another atom
- static void SetAtom(t_atom &a,const t_atom &b) { CopyAtom(&a,&b); }
-
-#if FLEXT_SYS == FLEXT_SYS_JMAX
- //! Set atom from another atom
- static int GetType(const t_atom &a); // ** TODO **
-
- //! Check whether the atom is nothing
- static bool IsNothing(const t_atom &a) { return fts_is_a(&a,fts_void_class); }
- //! Set the atom to represent nothing
- static void SetNothing(t_atom &a) { fts_set_void(&a); }
-
- //! Check whether the atom is a float
- static bool IsFloat(const t_atom &a) { return fts_is_a(&a,fts_float_class); }
-#else
- //! Set atom from another atom
- static int GetType(const t_atom &a) { return a.a_type; }
-
- //! 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; }
-#endif
-
- //! Check whether the atom can be represented as a float
- static bool CanbeFloat(const t_atom &a) { return IsFloat(a) || IsInt(a); }
-
-#if FLEXT_SYS == FLEXT_SYS_JMAX
- //! Access the float value (without type check)
- static float GetFloat(const t_atom &a) { return fts_get_float(&a); }
- //! Set the atom to represent a float
- static void SetFloat(t_atom &a,float v) { fts_set_float(&a,v); }
-
- //! Check whether the atom is a symbol
- static bool IsSymbol(const t_atom &a) { return fts_is_a(&a,fts_symbol_class); }
-#else
- //! 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; }
-#endif
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- //! Access the symbol value (without type check)
- static t_symbol *GetSymbol(const t_atom &a) { return a.a_w.w_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); }
-#elif FLEXT_SYS == FLEXT_SYS_MAX
- //! Access the symbol value (without type check)
- static t_symbol *GetSymbol(const t_atom &a) { return a.a_w.w_sym; }
- //! 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_sym = const_cast<t_symbol *>(s); }
-#elif FLEXT_SYS == FLEXT_SYS_JMAX
- //! Access the symbol value (without type check)
- static t_symbol *GetSymbol(const t_atom &a); // ** TODO **
- //! Set the atom to represent a symbol
- static void SetSymbol(t_atom &a,const t_symbol *s) { fts_set_symbol(&a,s); }
-#else
-#error
-#endif
- //! Check for a symbol and get its value
- static t_symbol *GetASymbol(const t_atom &a,t_symbol *def = NULL) { return IsSymbol(a)?GetSymbol(a):def; } // NULL or empty symbol?
-
- //! 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,MakeSymbol(c)); }
-
- //! Check whether the atom can be represented as an integer
- static bool CanbeInt(const t_atom &a) { return IsFloat(a) || IsInt(a); }
-
- //! Set the atom to represent a boolean
- static void SetBool(t_atom &a,bool v) { SetInt(a,v?1:0); }
- //! 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; }
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- //! Check for a float and get its value
- static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):def; }
-
- //! 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,int def = 0) { return (int)GetAFloat(a,(float)def); }
- //! 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 strictly is a pointer
- static bool IsPointer(const t_atom &a) { return a.a_type == A_POINTER; }
- //! Check whether the atom can be a pointer
- static bool CanbePointer(const t_atom &a) { return IsPointer(a); }
- //! Access the pointer value (without type check)
- static void *GetPointer(const t_atom &a) { return a.a_w.w_gpointer; }
- //! Check for a pointer and get its value
- static void *GetAPointer(const t_atom &a,void *def = NULL) { return IsPointer(a)?GetPointer(a):def; }
- //! Set the atom to represent a pointer
- static void SetPointer(t_atom &a,void *p) { a.a_type = A_POINTER; a.a_w.w_gpointer = (t_gpointer *)p; }
-
-#elif FLEXT_SYS == FLEXT_SYS_MAX
- //! Check for a float and get its value
- static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):(IsInt(a)?GetInt(a):def); }
-
- //! 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,int def = 0) { return IsInt(a)?GetInt(a):(IsFloat(a)?(int)GetFloat(a):def); }
- //! 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 strictly is a pointer
- static bool IsPointer(const t_atom &) { return false; }
- //! Check whether the atom can be a pointer
- static bool CanbePointer(const t_atom &a) { return IsInt(a); }
- //! 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 &a,void *def = NULL) { return IsInt(a)?(void *)GetInt(a):def; }
- //! Set the atom to represent a pointer
- static void SetPointer(t_atom &a,void *p) { SetInt(a,(int)p); }
-#elif FLEXT_SYS == FLEXT_SYS_JMAX
- //! Check for a float and get its value
- static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):(IsInt(a)?GetInt(a):def); }
-
- //! Check whether the atom is an int
- static bool IsInt(const t_atom &a) { return fts_is_a(&a,fts_int_class); }
- //! Access the integer value (without type check)
- static int GetInt(const t_atom &a) { return fts_get_int(&a); }
- //! Check for an integer and get its value
- static int GetAInt(const t_atom &a,int def = 0) { return IsInt(a)?GetInt(a):(IsFloat(a)?(int)GetFloat(a):def); }
- //! Set the atom to represent an integer
- static void SetInt(t_atom &a,int v) { fts_set_int(&a,v); }
-
- //! Check whether the atom strictly is a pointer
- static bool IsPointer(const t_atom &a) { return fts_is_a(&a,fts_pointer_class); }
- //! Check whether the atom can be a pointer
- static bool CanbePointer(const t_atom &a) { return IsPointer(a); }
- //! Access the pointer value (without type check)
- static void *GetPointer(const t_atom &a) { return fts_get_pointer(&a); }
- //! Check for a pointer and get its value
- static void *GetAPointer(const t_atom &a,void *def = NULL) { return IsPointer(a)?GetPointer(a):def; }
- //! Set the atom to represent a pointer
- static void SetPointer(t_atom &a,void *p) { fts_set_pointer(&a,p); }
-#else
-#error "Platform not supported"
-#endif
-
-// --- atom list stuff -------------------------------------------
-
- //! Class representing a list of atoms
- class FLEXT_SHARE 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 &Set(int argc,const t_atom *argv,int offs = 0,bool resize = false);
- //! Get list
- int Get(t_atom *argv,int mxsz = -1) const;
-
- //! Set list
- AtomList &operator()(int argc = 0,const t_atom *argv = NULL) { return Set(argc,argv,0,true); }
- //! 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 = NULL);
- //! 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 = NULL);
- //! 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 FLEXT_SHARE AtomAnything:
- public AtomList
- {
- public:
-#if FLEXT_SYS != FLEXT_SYS_JMAX
- //! Construct anything
- AtomAnything(const t_symbol *h = NULL,int argc = 0,const t_atom *argv = NULL);
-#endif
- //! Construct anything
- AtomAnything(const char *h,int argc = 0,const t_atom *argv = NULL);
- //! Construct anything
- AtomAnything(const AtomAnything &a);
-
- //! Clear anything
- AtomAnything &Clear() { return operator()(); }
-
- //! Get header symbol of anything
- const t_symbol *Header() const { return hdr; }
-
- //! Set header symbol of anything
- void Header(const t_symbol *h) { hdr = h; }
-
- //! 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;
- };
-
-//! @} FLEXT_S_ATOM
-
-
-// --- clock stuff ------------------------------------------------
-
-
- /*! \defgroup FLEXT_S_CLOCK Flext clock functions
-
- At the moment there are none
-
- @{
- */
-
-//! @}
-
-
-// --- thread stuff -----------------------------------------------
-
-#ifdef FLEXT_THREADS
- /*! \defgroup FLEXT_S_THREAD Flext thread handling
- @{
- */
-
- //! thread type
-#if FLEXT_THREADS == FLEXT_THR_MP
- typedef MPTaskID thrid_t;
-#elif FLEXT_THREADS == FLEXT_THR_POSIX
- typedef pthread_t thrid_t;
-#else
-#error
-#endif
-
- /*! \brief Get current thread id
- */
- static thrid_t GetThreadId() {
-#if FLEXT_THREADS == FLEXT_THR_POSIX
- return pthread_self();
-#elif FLEXT_THREADS == FLEXT_THR_MP
- return MPCurrentTaskID();
-#else
-#error
-#endif
- }
-
- /*! \brief Get system thread id
- */
- static thrid_t GetSysThreadId() { return thrid; }
-
- //! Check if current thread is the realtime system's thread
- 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
- }
-
- //! Check if current thread is the realtime system's thread
- static bool IsSystemThread() { return IsThread(GetSysThreadId()); }
-
-
- /*! \brief Thread parameters
- \internal
- */
- class thr_params
- {
- public:
- thr_params(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;
- };
-
- /*! \brief This represents an entry to the list of active method threads
- \internal
- */
- class thr_entry
- {
- public:
- thr_entry(void (*m)(thr_params *),thr_params *p,thrid_t id = GetThreadId());
-
- //! \brief Check if this class represents the current thread
- bool Is(thrid_t id = GetThreadId()) const { return IsThread(thrid,id); }
-
- flext_base *This() const { return th; }
- thrid_t Id() const { return thrid; }
-
- flext_base *th;
- void (*meth)(thr_params *);
- thr_params *params;
- thrid_t thrid;
- bool active,shouldexit;
-#if FLEXT_THREADS == FLEXT_THR_MP
- int weight;
-#endif
- thr_entry *nxt;
- };
-
-protected:
-
- static thrid_t thrhelpid;
- static bool StartHelper();
- static bool StopHelper();
- static void ThrHelper(void *);
-
- //! system's thread id
- static thrid_t thrid; // the system thread
-
-public:
-
- /*! \brief Yield to other threads
- \remark A call to this is only needed for systems with cooperative multitasking like MacOS<=9
- */
- static void ThrYield() {
-#if FLEXT_THREADS == FLEXT_THR_POSIX
- sched_yield();
-#elif FLEXT_THREADS == FLEXT_THR_MP
- MPYield();
-#else
-#error
-#endif
- }
-
- /*! \brief Query whether task is preemptive
- */
- 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
- }
-
-
- /*! \brief Increase/Decrease priority of a thread
- */
- static bool RelPriority(int dp,thrid_t ref = GetSysThreadId(),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 Thread mutex
- \sa pthreads documentation
- */
- class FLEXT_SHARE ThrMutex
-#if FLEXT_THREADS == FLEXT_THR_POSIX
- {
- public:
- //! Construct thread mutex
- ThrMutex() /*: cnt(0)*/ { pthread_mutex_init(&mutex,NULL); }
- //! Destroy thread mutex
- ~ThrMutex() { pthread_mutex_destroy(&mutex); }
-
- //! Lock thread mutex
- bool Lock() { /*cnt = 1;*/ return pthread_mutex_lock(&mutex) == 0; }
- //! Lock thread mutex
- bool WaitForLock(float tm) { /*cnt = 1;*/ return pthread_mutex_lock(&mutex) == 0; }
- //! Try to lock, but don't wait
- bool TryLock() { return pthread_mutex_trylock(&mutex) == 0; }
- //! Unlock thread mutex
- bool Unlock() { /*cnt = 0;*/ return pthread_mutex_unlock(&mutex) == 0; }
-/*
- //! 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;
- };
-#elif FLEXT_THREADS == FLEXT_THR_MP
- {
- public:
- //! Construct thread mutex
- ThrMutex() /*: cnt(0)*/ { MPCreateCriticalRegion(&crit); }
- //! Destroy thread mutex
- ~ThrMutex() { MPDeleteCriticalRegion(crit); }
-
- //! Lock thread mutex
- bool Lock() { /*cnt = 1;*/ return MPEnterCriticalRegion(crit,kDurationForever) == noErr; }
- //! Wait to lock thread mutex
- bool WaitForLock(float tm) { /*cnt = 1;*/ return MPEnterCriticalRegion(crit,tm*kDurationMicrosecond*1.e6) == noErr; }
- //! Try to lock, but don't wait
- bool TryLock() { return MPEnterCriticalRegion(crit,kDurationImmediate) == noErr; }
- //! Unlock thread mutex
- bool Unlock() { /*cnt = 0;*/ return MPExitCriticalRegion(crit) == noErr; }
-
- protected:
- MPCriticalRegionID crit;
- };
-#else
-#error "Not implemented"
-#endif
-
- /*! \brief Thread conditional
- \sa pthreads documentation
- */
- class FLEXT_SHARE ThrCond
-#if FLEXT_THREADS == FLEXT_THR_POSIX
- :public ThrMutex
- {
- public:
- //! Construct thread conditional
- ThrCond() { pthread_cond_init(&cond,NULL); }
- //! Destroy thread conditional
- ~ThrCond() { pthread_cond_destroy(&cond); }
-
- //! Wait for condition
- bool Wait() {
- Lock();
- bool ret = pthread_cond_wait(&cond,&mutex) == 0;
- Unlock();
- return ret;
- }
-
- /*! \brief Wait for condition (for a certain time)
- \param ftime Wait time in seconds
- \ret 0 = signalled, 1 = timed out
- \remark Depending on the implementation ftime may not be fractional.
- \remark So if ftime = 0 this may suck away your cpu if used in a signalled loop.
- */
- bool TimedWait(float ftime)
- {
- timespec tm;
-#if 0 // find out when the following is defined
- clock_gettime(CLOCK_REALTIME,tm);
- tm.tv_nsec += (long)((ftime-(long)ftime)*1.e9);
- long nns = tm.tv_nsec%1000000000;
- tm.tv_sec += (long)ftime+(tm.tv_nsec-nns)/1000000000;
- tm.tv_nsec = nns;
-#else
- tm.tv_sec = time(NULL)+(long)ftime;
- tm.tv_nsec = 0;
-#endif
- Lock();
- bool ret = pthread_cond_timedwait(&cond,&mutex,&tm) == 0;
- Unlock();
- return ret;
- }
-
- //! Signal condition
- bool Signal()
- {
- Lock();
- bool ret = pthread_cond_signal(&cond) == 0;
- Unlock();
- return ret;
- }
- //! Broadcast condition
-// int Broadcast() { return pthread_cond_broadcast(&cond); }
- protected:
- pthread_cond_t cond;
- };
-#elif FLEXT_THREADS == FLEXT_THR_MP
- {
- public:
- //! Construct thread conditional
- ThrCond() { MPCreateEvent(&ev); }
- //! Destroy thread conditional
- ~ThrCond() { MPDeleteEvent(ev); }
-
- //! Wait for condition
- bool Wait() { return MPWaitForEvent(ev,NULL,kDurationForever) == noErr; }
-
- /*! \brief Wait for condition (for a certain time)
- \param time Wait time in seconds
- */
- bool TimedWait(float tm) { return MPWaitForEvent(ev,NULL,tm*kDurationMicrosecond*1.e6) == noErr; }
-
- //! Signal condition
- bool Signal() { return MPSetEvent(ev,1) == noErr; } // one bit needs to be set at least
- //! Broadcast condition
-// int Broadcast() { return pthread_cond_broadcast(&cond); }
- protected:
- MPEventID ev;
- };
-#else
-#error "Not implemented"
-#endif
-
- /*! \brief Add current thread to list of active threads
- \return true on success
- \internal
- */
- static bool PushThread();
-
- /*! \brief Remove current thread from list of active threads
- \internal
- */
- static void PopThread();
-
- /*! \brief Launch a thread
- \remark thr_params *p may be NULL if not needed
- */
- static bool LaunchThread(void (*meth)(thr_params *p),thr_params *p);
-
-//! @} FLEXT_S_THREAD
-
-#endif // FLEXT_THREADS
-
-//! @}
-
-protected:
-#ifdef __MRC__
- friend class flext_obj;
-#endif
- static void Setup();
-
- static bool chktilde(const char *objname);
-};
-
-#endif
+/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001-2003 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" +#include <time.h> + +class FLEXT_SHARE flext_base; + +/*! \brief Flext support class + A number of methods (most are static functions) are defined here for convenience. + This class doesn't define any data members, hence it can be inherited to all + classes (not only PD objects) to profit from the cross-platform functionality. + Examples are the overloaded memory allocation, atom and atom list functions, + thread functions and classes, the sample buffer class and others. +*/ +class FLEXT_SHARE flext { + + /*! \defgroup FLEXT_SUPPORT Flext support class + @{ + */ +public: + +// --- console output ----------------------------------------------- + +#if FLEXT_SYS == FLEXT_SYS_JMAX + //! post message to console + static void post(const char *s,...); + //! post error message to console + static void error(const char *s,...); +#endif + +// --- memory ------------------------------------------------------- + + /*! \defgroup FLEXT_S_MEMORY Memory allocation functions + @{ + */ + + /*! Overloaded new memory allocation method + \warning Max/MSP (or MacOS) allows only 16K in overdrive mode! + */ + void *operator new(size_t bytes); + //! Overloaded delete method + 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 + + //! Get an aligned memory block + static void *NewAligned(size_t bytes,int bitalign = 128); + //! Free an aligned memory block + static void FreeAligned(void *blk); + + //! @} FLEXT_S_MEMORY + +// --- buffer/array stuff ----------------------------------------- + + /*! \defgroup FLEXT_S_BUFFER Buffer handling + @{ + */ + +// not for Jmax at the moment +#if FLEXT_SYS != FLEXT_SYS_JMAX + + //! Class for platform independent buffer handling + class FLEXT_SHARE buffer + { + public: + /*! \brief Construct buffer. + \param s: symbol name, can be NULL + \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 if buffer is valid + */ + bool Valid() const; + + /*! \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?GetString(sym):""; } + + /*! \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; +#if FLEXT_SYS == FLEXT_SYS_PD + t_garray *arr; + float interval; + bool isdirty,ticking; + t_clock *tick; + + private: + static void cb_tick(buffer *b); +#endif + }; + +#endif // jmax + +//! @} FLEXT_S_BUFFER + +// --- utilities -------------------------------------------------- + + /*! \defgroup FLEXT_S_UTIL Utility functions + @{ + */ + + //! Copy an atom + static void CopyAtom(t_atom *dst,const t_atom *src) { *dst = *src; } + + //! Print an atom + static void PrintAtom(const t_atom &a,char *buf,int bufsz = 0); + //! Scan an atom + static bool ScanAtom(t_atom &a,const char *buf); + + //! 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); + //! Copy a sample array + static void CopySamples(t_sample *dst,const t_sample *src,int cnt); + //! Set a memory region + static void ZeroMem(void *dst,int bytes); + //! Set a sample array to a fixed value + static void SetSamples(t_sample *dst,int cnt,t_sample s); + //! Set a sample array to 0 + static void ZeroSamples(t_sample *dst,int cnt) { SetSamples(dst,cnt,0); } + + + //! Get a 32 bit hash value frm an atom + static unsigned long AtomHash(const t_atom &a); + + /*! \brief Fold value to a number of bits + \remark Good for hash tables + */ + static unsigned int FoldBits(unsigned long h,int bits); + + //! \brief How many bits are necessary to represent n + static int Int2Bits(unsigned long n); + +//! @} FLEXT_S_UTIL + +// --- various symbols -------------------------------------------- + + /*! \defgroup FLEXT_S_ATOM Atom/list 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; + +#if FLEXT_SYS == FLEXT_SYS_PD + /*! \brief Symbol constant for "signal" + \note PD only + */ + static const t_symbol *sym_signal; +#endif + +#if FLEXT_SYS == FLEXT_SYS_JMAX + //! Make a symbol from a string + static const t_symbol *MakeSymbol(const char *s) { return ::fts_new_symbol(s); } + //! Get symbol string + static const char *GetString(const t_symbol *s); // ** TODO ** +#else + //! 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; } +#endif + //! Check for symbol and get string + static const char *GetAString(const t_symbol *s,const char *def = "") { return s?GetString(s):def; } + +// --- atom stuff ---------------------------------------- + + //! Set atom from another atom + static void SetAtom(t_atom &a,const t_atom &b) { CopyAtom(&a,&b); } + +#if FLEXT_SYS == FLEXT_SYS_JMAX + //! Set atom from another atom + static int GetType(const t_atom &a); // ** TODO ** + + //! Check whether the atom is nothing + static bool IsNothing(const t_atom &a) { return fts_is_a(&a,fts_void_class); } + //! Set the atom to represent nothing + static void SetNothing(t_atom &a) { fts_set_void(&a); } + + //! Check whether the atom is a float + static bool IsFloat(const t_atom &a) { return fts_is_a(&a,fts_float_class); } +#else + //! Set atom from another atom + static int GetType(const t_atom &a) { return a.a_type; } + + //! 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; } +#endif + + //! Check whether the atom can be represented as a float + static bool CanbeFloat(const t_atom &a) { return IsFloat(a) || IsInt(a); } + +#if FLEXT_SYS == FLEXT_SYS_JMAX + //! Access the float value (without type check) + static float GetFloat(const t_atom &a) { return fts_get_float(&a); } + //! Set the atom to represent a float + static void SetFloat(t_atom &a,float v) { fts_set_float(&a,v); } + + //! Check whether the atom is a symbol + static bool IsSymbol(const t_atom &a) { return fts_is_a(&a,fts_symbol_class); } +#else + //! 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; } +#endif + +#if FLEXT_SYS == FLEXT_SYS_PD + //! Access the symbol value (without type check) + static t_symbol *GetSymbol(const t_atom &a) { return a.a_w.w_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); } +#elif FLEXT_SYS == FLEXT_SYS_MAX + //! Access the symbol value (without type check) + static t_symbol *GetSymbol(const t_atom &a) { return a.a_w.w_sym; } + //! 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_sym = const_cast<t_symbol *>(s); } +#elif FLEXT_SYS == FLEXT_SYS_JMAX + //! Access the symbol value (without type check) + static t_symbol *GetSymbol(const t_atom &a); // ** TODO ** + //! Set the atom to represent a symbol + static void SetSymbol(t_atom &a,const t_symbol *s) { fts_set_symbol(&a,s); } +#else +#error +#endif + //! Check for a symbol and get its value + static t_symbol *GetASymbol(const t_atom &a,t_symbol *def = NULL) { return IsSymbol(a)?GetSymbol(a):def; } // NULL or empty symbol? + + //! 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,MakeSymbol(c)); } + + //! Check whether the atom can be represented as an integer + static bool CanbeInt(const t_atom &a) { return IsFloat(a) || IsInt(a); } + + //! Set the atom to represent a boolean + static void SetBool(t_atom &a,bool v) { SetInt(a,v?1:0); } + //! 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; } + +#if FLEXT_SYS == FLEXT_SYS_PD + //! Check for a float and get its value + static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):def; } + + //! 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,int def = 0) { return (int)GetAFloat(a,(float)def); } + //! 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 strictly is a pointer + static bool IsPointer(const t_atom &a) { return a.a_type == A_POINTER; } + //! Check whether the atom can be a pointer + static bool CanbePointer(const t_atom &a) { return IsPointer(a); } + //! Access the pointer value (without type check) + static void *GetPointer(const t_atom &a) { return a.a_w.w_gpointer; } + //! Check for a pointer and get its value + static void *GetAPointer(const t_atom &a,void *def = NULL) { return IsPointer(a)?GetPointer(a):def; } + //! Set the atom to represent a pointer + static void SetPointer(t_atom &a,void *p) { a.a_type = A_POINTER; a.a_w.w_gpointer = (t_gpointer *)p; } + +#elif FLEXT_SYS == FLEXT_SYS_MAX + //! Check for a float and get its value + static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):(IsInt(a)?GetInt(a):def); } + + //! 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,int def = 0) { return IsInt(a)?GetInt(a):(IsFloat(a)?(int)GetFloat(a):def); } + //! 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 strictly is a pointer + static bool IsPointer(const t_atom &) { return false; } + //! Check whether the atom can be a pointer + static bool CanbePointer(const t_atom &a) { return IsInt(a); } + //! 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 &a,void *def = NULL) { return IsInt(a)?(void *)GetInt(a):def; } + //! Set the atom to represent a pointer + static void SetPointer(t_atom &a,void *p) { SetInt(a,(int)p); } +#elif FLEXT_SYS == FLEXT_SYS_JMAX + //! Check for a float and get its value + static float GetAFloat(const t_atom &a,float def = 0) { return IsFloat(a)?GetFloat(a):(IsInt(a)?GetInt(a):def); } + + //! Check whether the atom is an int + static bool IsInt(const t_atom &a) { return fts_is_a(&a,fts_int_class); } + //! Access the integer value (without type check) + static int GetInt(const t_atom &a) { return fts_get_int(&a); } + //! Check for an integer and get its value + static int GetAInt(const t_atom &a,int def = 0) { return IsInt(a)?GetInt(a):(IsFloat(a)?(int)GetFloat(a):def); } + //! Set the atom to represent an integer + static void SetInt(t_atom &a,int v) { fts_set_int(&a,v); } + + //! Check whether the atom strictly is a pointer + static bool IsPointer(const t_atom &a) { return fts_is_a(&a,fts_pointer_class); } + //! Check whether the atom can be a pointer + static bool CanbePointer(const t_atom &a) { return IsPointer(a); } + //! Access the pointer value (without type check) + static void *GetPointer(const t_atom &a) { return fts_get_pointer(&a); } + //! Check for a pointer and get its value + static void *GetAPointer(const t_atom &a,void *def = NULL) { return IsPointer(a)?GetPointer(a):def; } + //! Set the atom to represent a pointer + static void SetPointer(t_atom &a,void *p) { fts_set_pointer(&a,p); } +#else +#error "Platform not supported" +#endif + +// --- atom list stuff ------------------------------------------- + + //! Class representing a list of atoms + class FLEXT_SHARE 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 &Set(int argc,const t_atom *argv,int offs = 0,bool resize = false); + //! Get list + int Get(t_atom *argv,int mxsz = -1) const; + + //! Set list + AtomList &operator()(int argc = 0,const t_atom *argv = NULL) { return Set(argc,argv,0,true); } + //! 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 = NULL); + //! 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 = NULL); + //! 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 FLEXT_SHARE AtomAnything: + public AtomList + { + public: +#if FLEXT_SYS != FLEXT_SYS_JMAX + //! Construct anything + AtomAnything(const t_symbol *h = NULL,int argc = 0,const t_atom *argv = NULL); +#endif + //! Construct anything + AtomAnything(const char *h,int argc = 0,const t_atom *argv = NULL); + //! Construct anything + AtomAnything(const AtomAnything &a); + + //! Clear anything + AtomAnything &Clear() { return operator()(); } + + //! Get header symbol of anything + const t_symbol *Header() const { return hdr; } + + //! Set header symbol of anything + void Header(const t_symbol *h) { hdr = h; } + + //! 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; + }; + +//! @} FLEXT_S_ATOM + + +// --- thread stuff ----------------------------------------------- + +#ifdef FLEXT_THREADS + /*! \defgroup FLEXT_S_THREAD Flext thread handling + @{ + */ + + //! thread type +#if FLEXT_THREADS == FLEXT_THR_MP + typedef MPTaskID thrid_t; +#elif FLEXT_THREADS == FLEXT_THR_POSIX + typedef pthread_t thrid_t; +#else +#error +#endif + + /*! \brief Get current thread id + */ + static thrid_t GetThreadId() { +#if FLEXT_THREADS == FLEXT_THR_POSIX + return pthread_self(); +#elif FLEXT_THREADS == FLEXT_THR_MP + return MPCurrentTaskID(); +#else +#error +#endif + } + + /*! \brief Get system thread id + */ + static thrid_t GetSysThreadId() { return thrid; } + + //! Check if current thread is the realtime system's thread + 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 + } + + //! Check if current thread is the realtime system's thread + static bool IsSystemThread() { return IsThread(GetSysThreadId()); } + + + /*! \brief Thread parameters + \internal + */ + class thr_params + { + public: + thr_params(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; + }; + + /*! \brief This represents an entry to the list of active method threads + \internal + */ + class thr_entry + { + public: + thr_entry(void (*m)(thr_params *),thr_params *p,thrid_t id = GetThreadId()); + + //! \brief Check if this class represents the current thread + bool Is(thrid_t id = GetThreadId()) const { return IsThread(thrid,id); } + + flext_base *This() const { return th; } + thrid_t Id() const { return thrid; } + + flext_base *th; + void (*meth)(thr_params *); + thr_params *params; + thrid_t thrid; + bool active,shouldexit; +#if FLEXT_THREADS == FLEXT_THR_MP + int weight; +#endif + thr_entry *nxt; + }; + +protected: + + static thrid_t thrhelpid; + static bool StartHelper(); + static bool StopHelper(); + static void ThrHelper(void *); + + //! system's thread id + static thrid_t thrid; // the system thread + +public: + + /*! \brief Yield to other threads + \remark A call to this is only needed for systems with cooperative multitasking like MacOS<=9 + */ + 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(); +#else +#error +#endif + } + + /*! \brief Query whether task is preemptive + */ + 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 + } + + + /*! \brief Increase/Decrease priority of a thread + */ + static bool RelPriority(int dp,thrid_t ref = GetSysThreadId(),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 Thread mutex + \sa pthreads documentation + */ + class FLEXT_SHARE ThrMutex +#if FLEXT_THREADS == FLEXT_THR_POSIX + { + public: + //! Construct thread mutex + ThrMutex() { pthread_mutex_init(&mutex,NULL); } + //! Destroy thread mutex + ~ThrMutex() { pthread_mutex_destroy(&mutex); } + + //! Lock thread mutex + bool Lock() { return pthread_mutex_lock(&mutex) == 0; } + /*! \brief Wait to lock thread mutex + \todo Implement! + */ + bool WaitForLock(double tm) { return pthread_mutex_lock(&mutex) == 0; } + //! Try to lock, but don't wait + bool TryLock() { return pthread_mutex_trylock(&mutex) == 0; } + //! Unlock thread mutex + bool Unlock() { return pthread_mutex_unlock(&mutex) == 0; } + + protected: + pthread_mutex_t mutex; +// int cnt; + }; +#elif FLEXT_THREADS == FLEXT_THR_MP + { + public: + //! Construct thread mutex + ThrMutex() { MPCreateCriticalRegion(&crit); } + //! Destroy thread mutex + ~ThrMutex() { MPDeleteCriticalRegion(crit); } + + //! Lock thread mutex + bool Lock() { return MPEnterCriticalRegion(crit,kDurationForever) == noErr; } + //! Wait to lock thread mutex + bool WaitForLock(double tm) { return MPEnterCriticalRegion(crit,tm*kDurationMicrosecond*1.e6) == noErr; } + //! Try to lock, but don't wait + bool TryLock() { return MPEnterCriticalRegion(crit,kDurationImmediate) == noErr; } + //! Unlock thread mutex + bool Unlock() { return MPExitCriticalRegion(crit) == noErr; } + + protected: + MPCriticalRegionID crit; + }; +#else +#error "Not implemented" +#endif + + /*! \brief Thread conditional + \sa pthreads documentation + */ + class FLEXT_SHARE ThrCond +#if FLEXT_THREADS == FLEXT_THR_POSIX + :public ThrMutex + { + public: + //! Construct thread conditional + ThrCond() { pthread_cond_init(&cond,NULL); } + //! Destroy thread conditional + ~ThrCond() { pthread_cond_destroy(&cond); } + + //! Wait for condition + bool Wait() { + Lock(); + bool ret = pthread_cond_wait(&cond,&mutex) == 0; + Unlock(); + return ret; + } + + /*! \brief Wait for condition (for a certain time) + \param ftime Wait time in seconds + \ret 0 = signalled, 1 = timed out + \remark Depending on the implementation ftime may not be fractional. + \remark So if ftime = 0 this may suck away your cpu if used in a signalled loop. + */ + bool TimedWait(double ftime) + { + timespec tm; +#if 0 // find out when the following is defined + clock_gettime(CLOCK_REALTIME,tm); + tm.tv_nsec += (long)((ftime-(long)ftime)*1.e9); + long nns = tm.tv_nsec%1000000000; + tm.tv_sec += (long)ftime+(tm.tv_nsec-nns)/1000000000; + tm.tv_nsec = nns; +#else + tm.tv_sec = time(NULL)+(long)ftime; + tm.tv_nsec = 0; +#endif + Lock(); + bool ret = pthread_cond_timedwait(&cond,&mutex,&tm) == 0; + Unlock(); + return ret; + } + + //! Signal condition + bool Signal() + { + Lock(); + bool ret = pthread_cond_signal(&cond) == 0; + Unlock(); + return ret; + } + //! Broadcast condition +// int Broadcast() { return pthread_cond_broadcast(&cond); } + protected: + pthread_cond_t cond; + }; +#elif FLEXT_THREADS == FLEXT_THR_MP + { + public: + //! Construct thread conditional + ThrCond() { MPCreateEvent(&ev); } + //! Destroy thread conditional + ~ThrCond() { MPDeleteEvent(ev); } + + //! Wait for condition + bool Wait() { return MPWaitForEvent(ev,NULL,kDurationForever) == noErr; } + + /*! \brief Wait for condition (for a certain time) + \param time Wait time in seconds + */ + bool TimedWait(double tm) { return MPWaitForEvent(ev,NULL,tm*kDurationMicrosecond*1.e6) == noErr; } + + //! Signal condition + bool Signal() { return MPSetEvent(ev,1) == noErr; } // one bit needs to be set at least + //! Broadcast condition +// int Broadcast() { return pthread_cond_broadcast(&cond); } + protected: + MPEventID ev; + }; +#else +#error "Not implemented" +#endif + + /*! \brief Add current thread to list of active threads + \return true on success + \internal + */ + static bool PushThread(); + + /*! \brief Remove current thread from list of active threads + \internal + */ + static void PopThread(); + + /*! \brief Launch a thread + \remark thr_params *p may be NULL if not needed + */ + static bool LaunchThread(void (*meth)(thr_params *p),thr_params *p); + +//! @} FLEXT_S_THREAD + + +#endif // FLEXT_THREADS + + +// --- timer stuff ----------------------------------------------- + +/*! \defgroup FLEXT_S_TIMER Flext timer handling + @{ + + \remark The clock of the real-time system is used for most of these functions. + \remark Since this clock can be synchronized to an external clock (or e.g. the audio card) + \remark it may differ from the clock of the operating system +*/ + /*! \brief Get time since real-time system startup + \note This is not the time of the operating system but of the real-time system. + \note It depends on the time source the system is synchronized to. + */ + static double GetTime(); + + /*! \brief Get time granularity of the GetTime function + \note This can be zero if not determined. + */ + static double GetTimeGrain(); + + /*! \brief Get operating system time since flext startup + */ + static double GetOSTime(); + + /*! \brief Sleep for an amount of time + \remark The OS clock is used for that + \note Clearly in a real-time system this should only be used in a detached thread + */ + static void Sleep(double s); + + /*! \brief Class encapsulating a timer with callback functionality + This class can either be used with FLEXT_ADDTIMER or used as a base class with an overloaded virtual Work function. + */ + class FLEXT_SHARE Timer + { + public: + Timer(bool queued = false); + ~Timer(); + + //! Set timer callback function + void SetCallback(void (*cb)(void *data)) { clss = NULL,cback = cb; } + //! Set timer callback function (with class pointer) + void SetCallback(flext_base &th,bool (*cb)(flext_base *th,void *data)) { clss = &th,cback = (void (*)(void *))cb; } + + //! Clear timer + bool Reset(); + //! Trigger a one shot at an absolute time + bool At(double tm,void *data = NULL,bool dopast = true); + //! Trigger a one shot interval + bool Delay(double tm,void *data = NULL); + //! Trigger a periodic interval + bool Periodic(double tm,void *data = NULL); + + //! Worker function, called on every timer event + 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_base *clss; + void *userdata; + double period; + }; + +//! @} FLEXT_S_TIMER + +// --- SIMD functionality ----------------------------------------------- + +/*! \defgroup FLEXT_S_SIMD Cross platform SIMD support for modern CPUs + @{ +*/ + 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() { return simdcaps; } + +//! @} FLEXT_S_SIMD + + +//! @} FLEXT_SUPPORT + +protected: +#ifdef __MRC__ + friend class flext_obj; +#endif + static void Setup(); + + static bool chktilde(const char *objname); + + static unsigned long simdcaps; +}; + +#endif |