IBufferSender Implementation

@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*)&current);
		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
	};

It takes around 1.5 secs to open here every time. but I need to investigate exactly where the delay is. It could be because I’m always blasting it a) with the highest-resolution images (and letting the framework downscale them as needed), and b) with super-large (eg. nearly 32k height) animated knob bitmaps. will look into deeper …

speaking of super-large animated bitmaps, I thought it might be handy if you could have more than one row/column for those, so you could get closer to a square image. the gpus might prefer it?

So this is my own control class, which is derived from IControl.

I’m creating my control tags:

enum EParams
{
  pGainIn = 0,
  pGainOut = 1,
  pMix = 2,
  pMode = 3,
  pScope = 4,
  kNumParams
};

I am attaching the control like so (passing the pScope enum which is equal to 4):

pGraphics->AttachControl(new AAGraphUnit(b.GetCentredInside(132).GetHShifted(46).GetVShifted(-43), pScope));

Then in my own control constructor, I am passing through the ‘paramIdx’ to the base IControl class…

class MyControlClass: public IControl, public IVectorBase
{

public:
MyControlClass(const IRECT& bounds, int paramIdx) // << HERE
: IControl(bounds, paramIdx) // << AND HERE
, IVectorBase(false, false)
{
}

Clearly I’ve done something wrong… but I can’t see it

Thanks again!

Param index and control tag are two separate things. There is an argument to AttachControl() which specifies the control tag

2 Likes

This was the issue! - Thank you @olilarkin, it’s working brilliantly now.