aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/flext/source/fltimer.cpp
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2003-03-03 07:57:50 +0000
committerThomas Grill <xovo@users.sourceforge.net>2003-03-03 07:57:50 +0000
commitc3ae6e7ab08db709ffa1975eea70bfc9461f1d6a (patch)
tree04f0076fb51a1ed9ff22b16385e07a4105bb34c3 /externals/grill/flext/source/fltimer.cpp
parentfe9b0d819d5478fa8256a612f3ba7de44894baf5 (diff)
""
svn path=/trunk/; revision=448
Diffstat (limited to 'externals/grill/flext/source/fltimer.cpp')
-rwxr-xr-xexternals/grill/flext/source/fltimer.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/externals/grill/flext/source/fltimer.cpp b/externals/grill/flext/source/fltimer.cpp
new file mode 100755
index 00000000..9b69de2b
--- /dev/null
+++ b/externals/grill/flext/source/fltimer.cpp
@@ -0,0 +1,262 @@
+/*
+
+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 fltimer.cpp
+ \brief flext timer functions and classes
+*/
+
+#include "flext.h"
+
+#if FLEXT_OS == FLEXT_OS_WIN
+#include <windows.h>
+#elif FLEXT_OS == FLEXT_OS_LINUX || FLEXT_OS == FLEXT_OS_IRIX || FLEXT_OSAPI == FLEXT_OSAPI_MAC_OSX
+#include <unistd.h>
+#include <sys/time.h>
+#elif FLEXT_OS == FLEXT_OS_MAC
+#include <Timer.h>
+#include <Threads.h>
+#endif
+
+
+
+double flext::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
+}
+
+double flext::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 getstarttime();
+static double starttime = getstarttime();
+
+static double getstarttime()
+{
+ starttime = 0;
+ return flext::GetOSTime();
+}
+
+double flext::GetOSTime()
+{
+ double tm;
+
+#if FLEXT_OS == FLEXT_OS_WIN
+ LARGE_INTEGER frq,cnt;
+ if(QueryPerformanceFrequency(&frq) && QueryPerformanceCounter(&cnt))
+ tm = (double)(cnt.QuadPart)/frq.QuadPart;
+ else {
+ SYSTEMTIME systm;
+ FILETIME fltm;
+ GetSystemTime(&systm);
+ SystemTimeToFileTime(&systm,&fltm);
+ tm = (double)((LARGE_INTEGER *)&fltm)->QuadPart*0.001;
+ }
+#elif FLEXT_OS == FLEXT_OS_LINUX || FLEXT_OS == FLEXT_OS_IRIX || FLEXT_OSAPI == FLEXT_OSAPI_MAC_OSX // POSIX
+ timeval tmv;
+ gettimeofday(&tmv,NULL);
+ tm = tmv.tv_sec+tmv.tv_usec*1.e-6;
+#elif FLEXT_OS == FLEXT_OS_MAC // that's just for OS9 & Carbon!
+ UnsignedWide tick;
+ Microseconds(&tick);
+ tm = (tick.hi*((double)(1L<<((sizeof tick.lo)*4))*(double)(1L<<((sizeof tick.lo)*4)))+tick.lo)*1.e-6;
+#else
+ #error Not implemented
+#endif
+ return tm-starttime;
+}
+
+void flext::Sleep(double s)
+{
+#if FLEXT_OS == FLEXT_OS_WIN
+ ::Sleep((long)(s*1000.));
+#elif FLEXT_OS == FLEXT_OS_LINUX || FLEXT_OS == FLEXT_OS_IRIX || FLEXT_OSAPI == FLEXT_OSAPI_MAC_OSX // POSIX
+ usleep((long)(s*1000000.));
+#elif FLEXT_OS == FLEXT_OS_MAC // that's just for OS9 & Carbon!
+ 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(;;) {
+ // this is just a loop running until the time has passed - stone age (but we yield at least)
+ Microseconds(&tick);
+ if(target <= tick.hi*((double)(1L<<((sizeof tick.lo)*4))*(double)(1L<<((sizeof tick.lo)*4)))+tick.lo) break;
+ YieldToAnyThread(); // yielding surely reduces the timing precision (but we're civilized)
+ }
+#else
+ #error Not implemented
+#endif
+}
+
+
+/* \param qu determines whether timed messages should be queued (low priority - only when supported by the system).
+*/
+flext::Timer::Timer(bool qu):
+ queued(qu),
+ clss(NULL),userdata(NULL),
+ period(0)
+{
+#if FLEXT_SYS == FLEXT_SYS_PD
+ clk = (t_clock *)clock_new(this,(t_method)callback);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ clk = (t_clock *)clock_new(this,(t_method)callback);
+ if(queued) qelem = (t_qelem *)qelem_new(this,(method)queuefun);
+#else
+ #error Not implemented
+#endif
+}
+
+flext::Timer::~Timer()
+{
+#if FLEXT_SYS == FLEXT_SYS_PD
+ clock_free(clk);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ clock_free(clk);
+ if(queued) qelem_free(qelem);
+#else
+ #error Not implemented
+#endif
+}
+
+bool flext::Timer::Reset()
+{
+#if FLEXT_SYS == FLEXT_SYS_PD
+ clock_unset(clk);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ clock_unset(clk);
+ if(queued) qelem_unset(qelem);
+#else
+ #error Not implemented
+#endif
+ return true;
+}
+
+/*! \param tm absolute time (in seconds)
+ \param data user data
+ \param dopast if set events with times lying in the past will be triggered immediately, if not set they are ignored
+ \return true on success
+*/
+bool flext::Timer::At(double tm,void *data,bool dopast)
+{
+ userdata = data;
+ period = 0;
+#if FLEXT_SYS == FLEXT_SYS_PD
+ const double ms = tm*1000.;
+ if(dopast || clock_gettimesince(ms) <= 0)
+ clock_set(clk,ms);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ const double ms = tm*1000.;
+ double cur;
+ clock_getftime(&cur);
+ if(cur <= ms)
+ clock_fdelay(clk,ms-cur);
+ else if(dopast) // trigger timer is past
+ clock_fdelay(clk,0);
+#else
+ #error Not implemented
+#endif
+ return true;
+}
+
+/*! \param tm relative time (in seconds)
+ \param data user data
+ \return true on success
+*/
+bool flext::Timer::Delay(double tm,void *data)
+{
+ userdata = data;
+ period = 0;
+#if FLEXT_SYS == FLEXT_SYS_PD
+ clock_delay(clk,tm*1000);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ clock_fdelay(clk,tm*1000.);
+#else
+ #error Not implemented
+#endif
+ return true;
+}
+
+/*! \param tm relative time between periodic events (in seconds)
+ \param data user data
+ \return true on success
+ \note the first event will be delayed by tm
+*/
+bool flext::Timer::Periodic(double tm,void *data)
+{
+ userdata = data;
+ period = tm;
+#if FLEXT_SYS == FLEXT_SYS_PD
+ clock_delay(clk,tm*1000);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ clock_fdelay(clk,tm*1000.);
+#else
+ #error Not implemented
+#endif
+ return true;
+}
+
+/*! \brief Callback function for system clock
+ \todo Make periodic events scheduled as such
+*/
+void flext::Timer::callback(Timer *tmr)
+{
+ if(tmr->period) {
+ // clearly it would be more precise if the periodic event is scheduled as such
+ // and not retriggered every time
+#if FLEXT_SYS == FLEXT_SYS_PD
+ clock_delay(tmr->clk,tmr->period*1000);
+#elif FLEXT_SYS == FLEXT_SYS_MAX
+ clock_fdelay(tmr->clk,tmr->period*1000.);
+#else
+ #error Not implemented
+#endif
+ }
+
+ if(tmr->cback) {
+#if FLEXT_SYS == FLEXT_SYS_MAX
+ if(tmr->queued)
+ qelem_set(tmr->qelem);
+ else
+#endif
+ tmr->Work();
+ }
+}
+
+#if FLEXT_SYS == FLEXT_SYS_MAX
+/*! \brief Callback function for low priority clock (for queued messages)
+*/
+void flext::Timer::queuefun(Timer *tmr) { tmr->Work(); }
+#endif
+
+/*! \brief Virtual worker function - by default it calls the user callback function
+ \remark The respective callback parameter format is chosen depending on whether clss is defined or not.
+*/
+void flext::Timer::Work()
+{
+ if(clss)
+ ((bool (*)(flext_base *,void *))cback)(clss,userdata);
+ else
+ cback(userdata);
+}
+