@olilarkin this is my timer class. I was planning to eventually replace the Iplug2 SetTimer() code itself, but it may take me a while to get around to it.
the class transparently uses QueryPerformanceCounter() if available (these days everywhere), or falls back to QueryTickCount<64>() if not.
typical usage is:
timer Time;
Time.Start(); // starts counting
...
timer::time elapsed_ms = Time.ElapsedMS();
Time.Start(); // if you want to reset the count again (else it keeps accumulating)
note that timer::time is a double, as this is a high-precision (<1us) timer.
there are lots of convenience functions, like ElapsedNS(), ElapsedUS(), ElapsedSecs() etc.
//
// _timer.h - (c) desperateBeauty (info@desperateBeauty.com) 2001-2022
//
# if _MSC_VER > 1000
# pragma once
# endif
#ifdef _WIN32
# include "WinBase.h" // GetTickCount64()
# include <intrin.h>
# pragma intrinsic(_ReadWriteBarrier)
#endif // _WIN32
// timer class
struct timer
{
typedef double time;
timer()
{
#ifdef _WIN32
if(!bTimerInitialised)
Initialise();
#endif
// start the counter
Start();
}
public:
#ifdef _WIN32
typedef unsigned _int64 tick;
#else
# error "define timer type for this platform"
#endif
FORCE_INLINE void Start ()
{
_ReadWriteBarrier();
_Start = GetCurrentTick();
}
// this convenience function returns true if the period has expired since
// the last trigger (and automatically restarts the timer)
bool EveryMS (time period_ms)
{
bool trigger = (ElapsedMS() >= period_ms);
if(trigger)
Start();
return trigger;
}
FORCE_INLINE time StartTimeMS () const
{
return Ticks2MS(_Start);
}
FORCE_INLINE time StartTimeSecs () const
{
return StartTimeMS() * 0.001;
}
FORCE_INLINE volatile time ElapsedMS () const
{
// _ReadWriteBarrier();
return Ticks2MS(ElapsedTicks());
}
// version that supplies the current ms too
FORCE_INLINE volatile time ElapsedMS (time &curr_ms_out) const
{
tick curr_tick = GetCurrentTick();
curr_ms_out = Ticks2MS(curr_tick);
return Ticks2MS(curr_tick - _Start);
}
FORCE_INLINE volatile time ElapsedUS () const
{
// _ReadWriteBarrier();
return ElapsedMS() * 1e3;
}
FORCE_INLINE volatile time ElapsedNS () const
{
// _ReadWriteBarrier();
return ElapsedUS() * 1e3;
}
FORCE_INLINE volatile time ElapsedSecs () const
{
// _ReadWriteBarrier();
return Ticks2Secs(ElapsedTicks());
}
// get the actual ticks (advanced - not usually needed)
FORCE_INLINE volatile tick ElapsedTicks () const
{
_ReadWriteBarrier();
return GetCurrentTick() - _Start;
}
FORCE_INLINE static volatile tick GetCurrentTick ()
{
_ReadWriteBarrier();
#ifdef _WIN32
return bPerformanceCounter? QueryPerfCounter() : QueryTickCount();
#else
# error "implement timer for this platform"
#endif
}
FORCE_INLINE static volatile time GetCurrentMS ()
{ return Ticks2MS(GetCurrentTick()); }
FORCE_INLINE static volatile time GetCurrentUS ()
{ return Ticks2US(GetCurrentTick()); }
#ifdef _WIN32
FORCE_INLINE static time Ticks2US (tick ticks)
{
return Ticks2MS(ticks) / 1e3;
}
FORCE_INLINE static time Ticks2MS (tick ticks)
{
return bPerformanceCounter? ticks / QP_Frequency : ticks;
}
FORCE_INLINE static time Ticks2Secs (tick ticks)
{
// GetTickCount() is already in ms resolution (unfortunately)
return bPerformanceCounter? (ticks * 0.001 / QP_Frequency) :
(ticks * 0.001);
}
#else
# error "implement timer for this platform"
#endif
protected: // protos
#ifdef _WIN32
FORCE_INLINE static volatile tick QueryPerfCounter()
{
tick current;
QueryPerformanceCounter((LARGE_INTEGER*)¤t);
return current;
}
// GetTickCount() wraps after 49days, so use the 64bit version if
// the minimum supported OS is enabled:
# if (WINVER >= _WIN32_WINNT_VISTA) || (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
inline static tick QueryTickCount () { return (tick)GetTickCount64(); }
# else
inline static tick QueryTickCount () { return (tick)GetTickCount (); }
# endif
static inline void Initialise ()
{
// PerformanceCounter available (best accuracy)?
tick qp_freq = 0;
QueryPerformanceFrequency((LARGE_INTEGER*)&qp_freq);
if(qp_freq) {
// msec accuracy
QP_Frequency = qp_freq / 1000.;
bPerformanceCounter = true;
}
else
bPerformanceCounter = false;
bTimerInitialised = true;
}
#endif // _WIN32
protected: // data
tick _Start;
// class globals
#ifdef _WIN32
static bool bTimerInitialised;
static bool bPerformanceCounter;
static double QP_Frequency;
#endif
};