High Resolution Timer and MessageManagerLock object issue

I am trying to use the high serolution timer. İt calculates the clicking time. I need it to be very accurate. That’s why i cannot use ordinary timer. It’s behavior changes all the time. Whenever I add something new to my code, my timer is ıncreasıng its error ratio.So I decided to use high resolution timer but it is crashing after the timercallback. I tried to use MessageManagerLock to solve the issue but still it triggers JUCE_ASSERT_MESSAGE_MANBAGER_IS_LOCKED . How should i use it ? where should i create the MessageManagerLock object ?

Juce has some asserts to avoid two thread access to the same variables at the same time (data races…). A way of solving it is using a lock (ie. MessageManagerLock) which prevent that while one thread is doing something in a funcion(s) or variables(s) another thread one use these.

In this case you are using a high resolution timer, which is in itself a thread. If you try to do something in the void hiResTimerCallback which affect something in the interface, ie, a Component::repaint or Component::setBounds, which are managed by the MessageThread, you will get that assert.

So a raw solution would be create a MessageManagerLock = it will block any MessageManager thread while your high resolution thread is refreshing the UI, or if the MessageThread is currently refreshing the UI, it will do your HighResolutionTimer waits until it can send the refreshs or whatever.

The easy way is, in the highResTimerCallback place these lines:

{
const MessageManagerLock myLock;
myComponent->repaint()
}

The “lock” will die as soon as the object die in the close bracket.

Two observations:

  1. While you lock the MessageThread because your timer is acting, everything will be freezed. This is usually a very small time. It also happens in the opposite way, your HighResolutionTimer locking the MessageThread.

  2. I don’t know the presition you need, but if you need, lets say 5ms, even if you don’t perform any lock to the MessageThread, the time may be increase due to heavy operations. You may try this creating, lets say, 100000 components and deleting them in each cycle. So, do light operations… or use another technique

Either way you rely on the messageThread. The accuracy of the timer is not so much different, just that the HighResolutionTimer can fire right away, while the Timer lets other tasks in the message queue finish.

IMHO since the HighResolutionTimer needs to wait until it can acquire the MMLock in order to do anything with the GUI, you are back to square one.

Is your precision a theoretical or a practical issue?

the problem is that I cannot get the correct time between two clicks with ordinary timer. While my DAW metronome gives me 120 bpm(500ms) , I am trying to click and catch ıt.The ınterval value of my normal timer is 1 millisecond and my timer gives me 344,372,401,335,…
There some other timers for doing some other things but I don’t need them to be so accurate . Only one must be very accurate. To see the difference i created an empty project with a button, a text label and a timer. The label show the bpm and clicktime. when i try it with that scenario , it works well. 502,528,485,512,477,…that’s is fine
But then i added another timer to create a blinking LED to show me the bpm, the clicktime timer starts lagging and increasing the error rate. results are like 443,432,474,512, 411
If the high resolution timer wont LED to blink since it is working with another timer, them i cant use it :confused:

what about sending the click from the audio thread and use AsyncUpdater to blink in the UI thread ?

@mesult, with “two clicks” do you mean two mouse clicks? If it’s that you should try Time:: getHighResolutionTicks() twice a get the difference. If not, try to explain to me what you pretend in a better way, maybe I could help you

This sounds good but I don’t think that I can do it without reviewing an example.

If Juan is getting you right, it doesn’t seem like you need a timer. If you need the timestamps of two mouse clicks, you can get that with juce::Time::getHighResolutionTicks() or std::chrono::steady_clock::now(). Take the timestamps synchronous with the clicks and store them, you don’t need to run a thread for that.

I hope this helps. A raw way of measuring elapsed time between clicks without a timer:

void mouseDown(const MouseEvent& e)
{
	static uint32 oldTime = Time::getMillisecondCounter();
	const uint32 currentTime = Time::getMillisecondCounter();
	const uint32 millisecondsEllapsed = currentTime - oldTime;
	if (millisecondsEllapsed < anyValue)
	{
		// do something
	}
	oldTime = currentTime;
}

oh the goal is not to display a metronome but calculate the tempo from mouse click ?
In that case, yes, yo should do that.
From some uvi code:

void TapTempoButton::clicked()
{
  juce::Button::clicked();
  mTime = Time::getCurrentTime();

  juce::int64 diff = mTime.toMilliseconds() - mOldTime.toMilliseconds();
  mOldTime = mTime;
  juce::int64 threshold = 60000 / 10; // min is 10 BPM
  if (diff < threshold)
  {
    float tempo = 60000.f / diff;
    if (mTempo.size() == 3)
    {
      mTempo.pop_front();
    }
    mTempo.push_back(tempo);
    tempo = 0;
    for (uint i = 0; i < mTempo.size(); i++)
    {
      tempo += mTempo[i];
    }
    tempo = tempo / (float)mTempo.size();
    SetTempo(tempo)
  }
  else
  {
    mTempo.clear();
  }
}
juce::Time mTime;
juce::Time mOldTime;
std::deque<float> mTempo;

mTempo vector allows to smooth it.

Yes, but it is a bit more than that.This is going to be a bpm button. I will click on the button and it is count the interval bewteen my mouse clicks. If I click only once after a 1,5sn it will call timeout and everything will set to its initial value. If i click twice it should calculate de time(just like the Timer::getHighResolutionTicks() method that you suggest) but if click three times again it should calculate the time . There will be 2 timer value between my three clicks. It should return the average of them. If I click “n” times it should sum the all “n-1” time values and return the average of them . Since getHighResolutionTicks() or getDoubleClickTimeout() are going to calculate the double clicks , they will miss single time values. Right now my code with ordinary timer works with a big error rate. The only issue is it is not accurate. there are many repaint(), methods, many knobs, so timer cannot count correctly.

     void myComponent::buttonClicked(Button* _Button)
      {

      if (_Button == &_bpmButton && !pressedOnce)// first click
      {
	clickTime = 0;
	startTimer(1);
	pressedOnce = 1;
    }
     else if (_Button == &_bpmButton && pressedOnce ) // second click
    	{

	stopTimer();
	average = average + clickTime;
	cycleCounter++;
	previousClickTime = clickTime;
	clickTime = 0;
	startTimer(1);
       }

       }





   void myComponent::timerCallback()
      {

++clickTime;
if (clickTime < refactorPercentage) /* it is 1500ms . if it the user does not click more for more then 1500ms it will jump to timeout condition. */
{
	if (clickTime > (previousClickTime + previousClickTime * 0.2)) /* No one can click perfectly. thats why i check the prevıous clicking time. If the next one is around the previous one, then the code keep summing the values in button click event , but if the user stops clicking , then  it will get inside this code to calculate the time */
	{
		readyForSwitching = 1;
        }


	if (readyForSwitching && cycleCounter>0)
	{

		average = (average / cycleCounter);



		if (average > refactorTimeValue)
			average = refactorTimeValue;

		average = jmap(average, 0.0f, refactorTimeValue, 1.0f, 0.0f); //mapping it to 1.0f-0.0f
        /* another strange thing timer does not work the same in every plugin platform.It is different in macAU, macVST3 and win VST3. that is why  ı change some parts here. but these have nothing to do with my problem*/
        if(platform==0)
        {
		
        average= average-0.11;
	    result = average;
        }
        
		if (platform == 2)
		{
			
			average = average - 0.05;
			 result = average;
		}
        
        if(platform==1)
        {
   
            average= average-0.02;// it was 0.8 
            if(average<=0.03)
                average=0;
            result = average;
        }


		average = 0;
		cycleCounter = 0;
		pressedOnce = 0;
		previousClickTime = refactorTimeValue;
		readyForSwitching = 0;
		stopTimer();
	}



}
else if (clickTime >= refactorPercentage )
{
	DBG("time out");
	clickTime = 0;
	cycleCounter = 0;
	average = 0;
	pressedOnce = 0;


	stopTimer();
}

}

Thank you very much for all of your answers :pray: I will check all of them one by one now :pray:

I do not remember if the buttonClicked listener is not called with doubleclicks. But if you create a custom Component, and inherit the mouseDown() method, you may do what you want pretty easily. Just take my code and place in it an else to restart the average, or take @otristan one which is more finished, mine is in barebones :slight_smile:

Before a doubleClick event you will get a click event, IIRC.
The timeout for a double click is 400ms (just checked), it can be reset for all JUCE (it’s a static variable).
That leaves the fastest tempo at 150 bpm before a double click is registered.
I think you should be fine ignoring the doubleClick event completely and do your own timeout handling.

Thank you very much :pray: now it is perfect :slight_smile: by only two clicks it is a bit hard but after three and more it works perfectly. Actually i was using this method in embbeded systems (in my atmel-pic-stm designs), it is a good way to handle these kind of things without using a timer interrupt but normally, the one that works better is the interrupt method. That is why i have never considered to use getMillisecondcounter() . Thank you very much :pray: . you guys, you saved me :slight_smile: