git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
108
deps/juce/modules/juce_events/timers/juce_MultiTimer.cpp
vendored
Normal file
108
deps/juce/modules/juce_events/timers/juce_MultiTimer.cpp
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct MultiTimerCallback : public Timer
|
||||
{
|
||||
MultiTimerCallback (const int tid, MultiTimer& mt) noexcept
|
||||
: owner (mt), timerID (tid)
|
||||
{
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
owner.timerCallback (timerID);
|
||||
}
|
||||
|
||||
MultiTimer& owner;
|
||||
const int timerID;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiTimerCallback)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
MultiTimer::MultiTimer() noexcept {}
|
||||
MultiTimer::MultiTimer (const MultiTimer&) noexcept {}
|
||||
|
||||
MultiTimer::~MultiTimer()
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (timerListLock);
|
||||
timers.clear();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Timer* MultiTimer::getCallback (int timerID) const noexcept
|
||||
{
|
||||
for (int i = timers.size(); --i >= 0;)
|
||||
{
|
||||
MultiTimerCallback* const t = static_cast<MultiTimerCallback*> (timers.getUnchecked(i));
|
||||
|
||||
if (t->timerID == timerID)
|
||||
return t;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MultiTimer::startTimer (const int timerID, const int intervalInMilliseconds) noexcept
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (timerListLock);
|
||||
|
||||
Timer* timer = getCallback (timerID);
|
||||
|
||||
if (timer == nullptr)
|
||||
timers.add (timer = new MultiTimerCallback (timerID, *this));
|
||||
|
||||
timer->startTimer (intervalInMilliseconds);
|
||||
}
|
||||
|
||||
void MultiTimer::stopTimer (const int timerID) noexcept
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (timerListLock);
|
||||
|
||||
if (Timer* const t = getCallback (timerID))
|
||||
t->stopTimer();
|
||||
}
|
||||
|
||||
bool MultiTimer::isTimerRunning (const int timerID) const noexcept
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (timerListLock);
|
||||
|
||||
if (Timer* const t = getCallback (timerID))
|
||||
return t->isTimerRunning();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MultiTimer::getTimerInterval (const int timerID) const noexcept
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (timerListLock);
|
||||
|
||||
if (Timer* const t = getCallback (timerID))
|
||||
return t->getTimerInterval();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace juce
|
125
deps/juce/modules/juce_events/timers/juce_MultiTimer.h
vendored
Normal file
125
deps/juce/modules/juce_events/timers/juce_MultiTimer.h
vendored
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A type of timer class that can run multiple timers with different frequencies,
|
||||
all of which share a single callback.
|
||||
|
||||
This class is very similar to the Timer class, but allows you run multiple
|
||||
separate timers, where each one has a unique ID number. The methods in this
|
||||
class are exactly equivalent to those in Timer, but with the addition of
|
||||
this ID number.
|
||||
|
||||
To use it, you need to create a subclass of MultiTimer, implementing the
|
||||
timerCallback() method. Then you can start timers with startTimer(), and
|
||||
each time the callback is triggered, it passes in the ID of the timer that
|
||||
caused it.
|
||||
|
||||
@see Timer
|
||||
|
||||
@tags{Events}
|
||||
*/
|
||||
class JUCE_API MultiTimer
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates a MultiTimer.
|
||||
|
||||
When created, no timers are running, so use startTimer() to start things off.
|
||||
*/
|
||||
MultiTimer() noexcept;
|
||||
|
||||
/** Creates a copy of another timer.
|
||||
|
||||
Note that this timer will not contain any running timers, even if the one you're
|
||||
copying from was running.
|
||||
*/
|
||||
MultiTimer (const MultiTimer&) noexcept;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
virtual ~MultiTimer();
|
||||
|
||||
//==============================================================================
|
||||
/** The user-defined callback routine that actually gets called by each of the
|
||||
timers that are running.
|
||||
|
||||
It's perfectly ok to call startTimer() or stopTimer() from within this
|
||||
callback to change the subsequent intervals.
|
||||
*/
|
||||
virtual void timerCallback (int timerID) = 0;
|
||||
|
||||
//==============================================================================
|
||||
/** Starts a timer and sets the length of interval required.
|
||||
|
||||
If the timer is already started, this will reset it, so the
|
||||
time between calling this method and the next timer callback
|
||||
will not be less than the interval length passed in.
|
||||
|
||||
@param timerID a unique Id number that identifies the timer to
|
||||
start. This is the id that will be passed back
|
||||
to the timerCallback() method when this timer is
|
||||
triggered
|
||||
@param intervalInMilliseconds the interval to use (any values less than 1 will be
|
||||
rounded up to 1)
|
||||
*/
|
||||
void startTimer (int timerID, int intervalInMilliseconds) noexcept;
|
||||
|
||||
/** Stops a timer.
|
||||
|
||||
If a timer has been started with the given ID number, it will be cancelled.
|
||||
No more callbacks will be made for the specified timer after this method returns.
|
||||
|
||||
If this is called from a different thread, any callbacks that may
|
||||
be currently executing may be allowed to finish before the method
|
||||
returns.
|
||||
*/
|
||||
void stopTimer (int timerID) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Checks whether a timer has been started for a specified ID.
|
||||
@returns true if a timer with the given ID is running.
|
||||
*/
|
||||
bool isTimerRunning (int timerID) const noexcept;
|
||||
|
||||
/** Returns the interval for a specified timer ID.
|
||||
@returns the timer's interval in milliseconds if it's running, or 0 if no
|
||||
timer was running for the ID number specified.
|
||||
*/
|
||||
int getTimerInterval (int timerID) const noexcept;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
SpinLock timerListLock;
|
||||
OwnedArray<Timer> timers;
|
||||
|
||||
Timer* getCallback (int) const noexcept;
|
||||
MultiTimer& operator= (const MultiTimer&);
|
||||
};
|
||||
|
||||
} // namespace juce
|
397
deps/juce/modules/juce_events/timers/juce_Timer.cpp
vendored
Normal file
397
deps/juce/modules/juce_events/timers/juce_Timer.cpp
vendored
Normal file
@ -0,0 +1,397 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class Timer::TimerThread : private Thread,
|
||||
private DeletedAtShutdown,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
using LockType = CriticalSection; // (mysteriously, using a SpinLock here causes problems on some XP machines..)
|
||||
|
||||
TimerThread() : Thread ("JUCE Timer")
|
||||
{
|
||||
timers.reserve (32);
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
~TimerThread() override
|
||||
{
|
||||
signalThreadShouldExit();
|
||||
callbackArrived.signal();
|
||||
stopThread (4000);
|
||||
jassert (instance == this || instance == nullptr);
|
||||
|
||||
if (instance == this)
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
auto lastTime = Time::getMillisecondCounter();
|
||||
ReferenceCountedObjectPtr<CallTimersMessage> messageToSend (new CallTimersMessage());
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
auto now = Time::getMillisecondCounter();
|
||||
auto elapsed = (int) (now >= lastTime ? (now - lastTime)
|
||||
: (std::numeric_limits<uint32>::max() - (lastTime - now)));
|
||||
lastTime = now;
|
||||
|
||||
auto timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed);
|
||||
|
||||
if (timeUntilFirstTimer <= 0)
|
||||
{
|
||||
if (callbackArrived.wait (0))
|
||||
{
|
||||
// already a message in flight - do nothing..
|
||||
}
|
||||
else
|
||||
{
|
||||
messageToSend->post();
|
||||
|
||||
if (! callbackArrived.wait (300))
|
||||
{
|
||||
// Sometimes our message can get discarded by the OS (e.g. when running as an RTAS
|
||||
// when the app has a modal loop), so this is how long to wait before assuming the
|
||||
// message has been lost and trying again.
|
||||
messageToSend->post();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// don't wait for too long because running this loop also helps keep the
|
||||
// Time::getApproximateMillisecondTimer value stay up-to-date
|
||||
wait (jlimit (1, 100, timeUntilFirstTimer));
|
||||
}
|
||||
}
|
||||
|
||||
void callTimers()
|
||||
{
|
||||
auto timeout = Time::getMillisecondCounter() + 100;
|
||||
|
||||
const LockType::ScopedLockType sl (lock);
|
||||
|
||||
while (! timers.empty())
|
||||
{
|
||||
auto& first = timers.front();
|
||||
|
||||
if (first.countdownMs > 0)
|
||||
break;
|
||||
|
||||
auto* timer = first.timer;
|
||||
first.countdownMs = timer->timerPeriodMs;
|
||||
shuffleTimerBackInQueue (0);
|
||||
notify();
|
||||
|
||||
const LockType::ScopedUnlockType ul (lock);
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
timer->timerCallback();
|
||||
}
|
||||
JUCE_CATCH_EXCEPTION
|
||||
|
||||
// avoid getting stuck in a loop if a timer callback repeatedly takes too long
|
||||
if (Time::getMillisecondCounter() > timeout)
|
||||
break;
|
||||
}
|
||||
|
||||
callbackArrived.signal();
|
||||
}
|
||||
|
||||
void callTimersSynchronously()
|
||||
{
|
||||
if (! isThreadRunning())
|
||||
{
|
||||
// (This is relied on by some plugins in cases where the MM has
|
||||
// had to restart and the async callback never started)
|
||||
cancelPendingUpdate();
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
callTimers();
|
||||
}
|
||||
|
||||
static void add (Timer* tim) noexcept
|
||||
{
|
||||
if (instance == nullptr)
|
||||
instance = new TimerThread();
|
||||
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
|
||||
static void remove (Timer* tim) noexcept
|
||||
{
|
||||
if (instance != nullptr)
|
||||
instance->removeTimer (tim);
|
||||
}
|
||||
|
||||
static void resetCounter (Timer* tim) noexcept
|
||||
{
|
||||
if (instance != nullptr)
|
||||
instance->resetTimerCounter (tim);
|
||||
}
|
||||
|
||||
static TimerThread* instance;
|
||||
static LockType lock;
|
||||
|
||||
private:
|
||||
struct TimerCountdown
|
||||
{
|
||||
Timer* timer;
|
||||
int countdownMs;
|
||||
};
|
||||
|
||||
std::vector<TimerCountdown> timers;
|
||||
|
||||
WaitableEvent callbackArrived;
|
||||
|
||||
struct CallTimersMessage : public MessageManager::MessageBase
|
||||
{
|
||||
CallTimersMessage() {}
|
||||
|
||||
void messageCallback() override
|
||||
{
|
||||
if (instance != nullptr)
|
||||
instance->callTimers();
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void addTimer (Timer* t)
|
||||
{
|
||||
// Trying to add a timer that's already here - shouldn't get to this point,
|
||||
// so if you get this assertion, let me know!
|
||||
jassert (std::find_if (timers.begin(), timers.end(),
|
||||
[t] (TimerCountdown i) { return i.timer == t; }) == timers.end());
|
||||
|
||||
auto pos = timers.size();
|
||||
|
||||
timers.push_back ({ t, t->timerPeriodMs });
|
||||
t->positionInQueue = pos;
|
||||
shuffleTimerForwardInQueue (pos);
|
||||
notify();
|
||||
}
|
||||
|
||||
void removeTimer (Timer* t)
|
||||
{
|
||||
auto pos = t->positionInQueue;
|
||||
auto lastIndex = timers.size() - 1;
|
||||
|
||||
jassert (pos <= lastIndex);
|
||||
jassert (timers[pos].timer == t);
|
||||
|
||||
for (auto i = pos; i < lastIndex; ++i)
|
||||
{
|
||||
timers[i] = timers[i + 1];
|
||||
timers[i].timer->positionInQueue = i;
|
||||
}
|
||||
|
||||
timers.pop_back();
|
||||
}
|
||||
|
||||
void resetTimerCounter (Timer* t) noexcept
|
||||
{
|
||||
auto pos = t->positionInQueue;
|
||||
|
||||
jassert (pos < timers.size());
|
||||
jassert (timers[pos].timer == t);
|
||||
|
||||
auto lastCountdown = timers[pos].countdownMs;
|
||||
auto newCountdown = t->timerPeriodMs;
|
||||
|
||||
if (newCountdown != lastCountdown)
|
||||
{
|
||||
timers[pos].countdownMs = newCountdown;
|
||||
|
||||
if (newCountdown > lastCountdown)
|
||||
shuffleTimerBackInQueue (pos);
|
||||
else
|
||||
shuffleTimerForwardInQueue (pos);
|
||||
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
void shuffleTimerBackInQueue (size_t pos)
|
||||
{
|
||||
auto numTimers = timers.size();
|
||||
|
||||
if (pos < numTimers - 1)
|
||||
{
|
||||
auto t = timers[pos];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
auto next = pos + 1;
|
||||
|
||||
if (next == numTimers || timers[next].countdownMs >= t.countdownMs)
|
||||
break;
|
||||
|
||||
timers[pos] = timers[next];
|
||||
timers[pos].timer->positionInQueue = pos;
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
timers[pos] = t;
|
||||
t.timer->positionInQueue = pos;
|
||||
}
|
||||
}
|
||||
|
||||
void shuffleTimerForwardInQueue (size_t pos)
|
||||
{
|
||||
if (pos > 0)
|
||||
{
|
||||
auto t = timers[pos];
|
||||
|
||||
while (pos > 0)
|
||||
{
|
||||
auto& prev = timers[(size_t) pos - 1];
|
||||
|
||||
if (prev.countdownMs <= t.countdownMs)
|
||||
break;
|
||||
|
||||
timers[pos] = prev;
|
||||
timers[pos].timer->positionInQueue = pos;
|
||||
|
||||
--pos;
|
||||
}
|
||||
|
||||
timers[pos] = t;
|
||||
t.timer->positionInQueue = pos;
|
||||
}
|
||||
}
|
||||
|
||||
int getTimeUntilFirstTimer (int numMillisecsElapsed)
|
||||
{
|
||||
const LockType::ScopedLockType sl (lock);
|
||||
|
||||
if (timers.empty())
|
||||
return 1000;
|
||||
|
||||
for (auto& t : timers)
|
||||
t.countdownMs -= numMillisecsElapsed;
|
||||
|
||||
return timers.front().countdownMs;
|
||||
}
|
||||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
startThread (7);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimerThread)
|
||||
};
|
||||
|
||||
Timer::TimerThread* Timer::TimerThread::instance = nullptr;
|
||||
Timer::TimerThread::LockType Timer::TimerThread::lock;
|
||||
|
||||
//==============================================================================
|
||||
Timer::Timer() noexcept {}
|
||||
Timer::Timer (const Timer&) noexcept {}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
// If you're destroying a timer on a background thread, make sure the timer has
|
||||
// been stopped before execution reaches this point. A simple way to achieve this
|
||||
// is to add a call to `stopTimer()` to the destructor of your class which inherits
|
||||
// from Timer.
|
||||
jassert (! isTimerRunning()
|
||||
|| MessageManager::getInstanceWithoutCreating() == nullptr
|
||||
|| MessageManager::getInstanceWithoutCreating()->currentThreadHasLockedMessageManager());
|
||||
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
void Timer::startTimer (int interval) noexcept
|
||||
{
|
||||
// If you're calling this before (or after) the MessageManager is
|
||||
// running, then you're not going to get any timer callbacks!
|
||||
JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
|
||||
|
||||
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
|
||||
|
||||
bool wasStopped = (timerPeriodMs == 0);
|
||||
timerPeriodMs = jmax (1, interval);
|
||||
|
||||
if (wasStopped)
|
||||
TimerThread::add (this);
|
||||
else
|
||||
TimerThread::resetCounter (this);
|
||||
}
|
||||
|
||||
void Timer::startTimerHz (int timerFrequencyHz) noexcept
|
||||
{
|
||||
if (timerFrequencyHz > 0)
|
||||
startTimer (1000 / timerFrequencyHz);
|
||||
else
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
void Timer::stopTimer() noexcept
|
||||
{
|
||||
const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
|
||||
|
||||
if (timerPeriodMs > 0)
|
||||
{
|
||||
TimerThread::remove (this);
|
||||
timerPeriodMs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE Timer::callPendingTimersSynchronously()
|
||||
{
|
||||
if (TimerThread::instance != nullptr)
|
||||
TimerThread::instance->callTimersSynchronously();
|
||||
}
|
||||
|
||||
struct LambdaInvoker : private Timer
|
||||
{
|
||||
LambdaInvoker (int milliseconds, std::function<void()> f) : function (f)
|
||||
{
|
||||
startTimer (milliseconds);
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
auto f = function;
|
||||
delete this;
|
||||
f();
|
||||
}
|
||||
|
||||
std::function<void()> function;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (LambdaInvoker)
|
||||
};
|
||||
|
||||
void JUCE_CALLTYPE Timer::callAfterDelay (int milliseconds, std::function<void()> f)
|
||||
{
|
||||
new LambdaInvoker (milliseconds, f);
|
||||
}
|
||||
|
||||
} // namespace juce
|
137
deps/juce/modules/juce_events/timers/juce_Timer.h
vendored
Normal file
137
deps/juce/modules/juce_events/timers/juce_Timer.h
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Makes repeated callbacks to a virtual method at a specified time interval.
|
||||
|
||||
A Timer's timerCallback() method will be repeatedly called at a given
|
||||
interval. When you create a Timer object, it will do nothing until the
|
||||
startTimer() method is called, which will cause the message thread to
|
||||
start making callbacks at the specified interval, until stopTimer() is called
|
||||
or the object is deleted.
|
||||
|
||||
The time interval isn't guaranteed to be precise to any more than maybe
|
||||
10-20ms, and the intervals may end up being much longer than requested if the
|
||||
system is busy. Because the callbacks are made by the main message thread,
|
||||
anything that blocks the message queue for a period of time will also prevent
|
||||
any timers from running until it can carry on.
|
||||
|
||||
If you need to have a single callback that is shared by multiple timers with
|
||||
different frequencies, then the MultiTimer class allows you to do that - its
|
||||
structure is very similar to the Timer class, but contains multiple timers
|
||||
internally, each one identified by an ID number.
|
||||
|
||||
@see HighResolutionTimer, MultiTimer
|
||||
|
||||
@tags{Events}
|
||||
*/
|
||||
class JUCE_API Timer
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates a Timer.
|
||||
When created, the timer is stopped, so use startTimer() to get it going.
|
||||
*/
|
||||
Timer() noexcept;
|
||||
|
||||
/** Creates a copy of another timer.
|
||||
|
||||
Note that this timer won't be started, even if the one you're copying
|
||||
is running.
|
||||
*/
|
||||
Timer (const Timer&) noexcept;
|
||||
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
virtual ~Timer();
|
||||
|
||||
//==============================================================================
|
||||
/** The user-defined callback routine that actually gets called periodically.
|
||||
|
||||
It's perfectly ok to call startTimer() or stopTimer() from within this
|
||||
callback to change the subsequent intervals.
|
||||
*/
|
||||
virtual void timerCallback() = 0;
|
||||
|
||||
//==============================================================================
|
||||
/** Starts the timer and sets the length of interval required.
|
||||
|
||||
If the timer is already started, this will reset it, so the
|
||||
time between calling this method and the next timer callback
|
||||
will not be less than the interval length passed in.
|
||||
|
||||
@param intervalInMilliseconds the interval to use (any value less
|
||||
than 1 will be rounded up to 1)
|
||||
*/
|
||||
void startTimer (int intervalInMilliseconds) noexcept;
|
||||
|
||||
/** Starts the timer with an interval specified in Hertz.
|
||||
This is effectively the same as calling startTimer (1000 / timerFrequencyHz).
|
||||
*/
|
||||
void startTimerHz (int timerFrequencyHz) noexcept;
|
||||
|
||||
/** Stops the timer.
|
||||
|
||||
No more timer callbacks will be triggered after this method returns.
|
||||
|
||||
Note that if you call this from a background thread while the message-thread
|
||||
is already in the middle of your callback, then this method will cancel any
|
||||
future timer callbacks, but it will return without waiting for the current one
|
||||
to finish. The current callback will continue, possibly still running some of
|
||||
your timer code after this method has returned.
|
||||
*/
|
||||
void stopTimer() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if the timer is currently running. */
|
||||
bool isTimerRunning() const noexcept { return timerPeriodMs > 0; }
|
||||
|
||||
/** Returns the timer's interval.
|
||||
@returns the timer's interval in milliseconds if it's running, or 0 if it's not.
|
||||
*/
|
||||
int getTimerInterval() const noexcept { return timerPeriodMs; }
|
||||
|
||||
//==============================================================================
|
||||
/** Invokes a lambda after a given number of milliseconds. */
|
||||
static void JUCE_CALLTYPE callAfterDelay (int milliseconds, std::function<void()> functionToCall);
|
||||
|
||||
//==============================================================================
|
||||
/** For internal use only: invokes any timers that need callbacks.
|
||||
Don't call this unless you really know what you're doing!
|
||||
*/
|
||||
static void JUCE_CALLTYPE callPendingTimersSynchronously();
|
||||
|
||||
private:
|
||||
class TimerThread;
|
||||
friend class TimerThread;
|
||||
size_t positionInQueue = (size_t) -1;
|
||||
int timerPeriodMs = 0;
|
||||
|
||||
Timer& operator= (const Timer&) = delete;
|
||||
};
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user