Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license/
  7. Permission to use, copy, modify, and/or distribute this software for any
  8. purpose with or without fee is hereby granted, provided that the above
  9. copyright notice and this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  11. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  13. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  14. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  16. OF THIS SOFTWARE.
  17. -----------------------------------------------------------------------------
  18. To release a closed-source product which uses other parts of JUCE not
  19. licensed under the ISC terms, commercial licenses are available: visit
  20. www.juce.com for more information.
  21. ==============================================================================
  22. */
  23. class Timer::TimerThread : private Thread,
  24. private DeletedAtShutdown,
  25. private AsyncUpdater
  26. {
  27. public:
  28. typedef CriticalSection LockType; // (mysteriously, using a SpinLock here causes problems on some XP machines..)
  29. TimerThread()
  30. : Thread ("Juce Timer"),
  31. firstTimer (nullptr)
  32. {
  33. triggerAsyncUpdate();
  34. }
  35. ~TimerThread() noexcept
  36. {
  37. signalThreadShouldExit();
  38. callbackArrived.signal();
  39. stopThread (4000);
  40. jassert (instance == this || instance == nullptr);
  41. if (instance == this)
  42. instance = nullptr;
  43. }
  44. void run() override
  45. {
  46. uint32 lastTime = Time::getMillisecondCounter();
  47. MessageManager::MessageBase::Ptr messageToSend (new CallTimersMessage());
  48. while (! threadShouldExit())
  49. {
  50. const uint32 now = Time::getMillisecondCounter();
  51. const int elapsed = (int) (now >= lastTime ? (now - lastTime)
  52. : (std::numeric_limits<uint32>::max() - (lastTime - now)));
  53. lastTime = now;
  54. const int timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed);
  55. if (timeUntilFirstTimer <= 0)
  56. {
  57. if (callbackArrived.wait (0))
  58. {
  59. // already a message in flight - do nothing..
  60. }
  61. else
  62. {
  63. messageToSend->post();
  64. if (! callbackArrived.wait (300))
  65. {
  66. // Sometimes our message can get discarded by the OS (e.g. when running as an RTAS
  67. // when the app has a modal loop), so this is how long to wait before assuming the
  68. // message has been lost and trying again.
  69. messageToSend->post();
  70. }
  71. continue;
  72. }
  73. }
  74. // don't wait for too long because running this loop also helps keep the
  75. // Time::getApproximateMillisecondTimer value stay up-to-date
  76. wait (jlimit (1, 100, timeUntilFirstTimer));
  77. }
  78. }
  79. void callTimers()
  80. {
  81. // avoid getting stuck in a loop if a timer callback repeatedly takes too long
  82. const uint32 timeout = Time::getMillisecondCounter() + 100;
  83. const LockType::ScopedLockType sl (lock);
  84. while (firstTimer != nullptr && firstTimer->timerCountdownMs <= 0)
  85. {
  86. Timer* const t = firstTimer;
  87. t->timerCountdownMs = t->timerPeriodMs;
  88. removeTimer (t);
  89. addTimer (t);
  90. const LockType::ScopedUnlockType ul (lock);
  91. JUCE_TRY
  92. {
  93. t->timerCallback();
  94. }
  95. JUCE_CATCH_EXCEPTION
  96. if (Time::getMillisecondCounter() > timeout)
  97. break;
  98. }
  99. callbackArrived.signal();
  100. }
  101. void callTimersSynchronously()
  102. {
  103. if (! isThreadRunning())
  104. {
  105. // (This is relied on by some plugins in cases where the MM has
  106. // had to restart and the async callback never started)
  107. cancelPendingUpdate();
  108. triggerAsyncUpdate();
  109. }
  110. callTimers();
  111. }
  112. static inline void add (Timer* const tim) noexcept
  113. {
  114. if (instance == nullptr)
  115. instance = new TimerThread();
  116. instance->addTimer (tim);
  117. }
  118. static inline void remove (Timer* const tim) noexcept
  119. {
  120. if (instance != nullptr)
  121. instance->removeTimer (tim);
  122. }
  123. static inline void resetCounter (Timer* const tim, const int newCounter) noexcept
  124. {
  125. if (instance != nullptr)
  126. {
  127. tim->timerCountdownMs = newCounter;
  128. tim->timerPeriodMs = newCounter;
  129. if ((tim->nextTimer != nullptr && tim->nextTimer->timerCountdownMs < tim->timerCountdownMs)
  130. || (tim->previousTimer != nullptr && tim->previousTimer->timerCountdownMs > tim->timerCountdownMs))
  131. {
  132. instance->removeTimer (tim);
  133. instance->addTimer (tim);
  134. }
  135. }
  136. }
  137. static TimerThread* instance;
  138. static LockType lock;
  139. private:
  140. Timer* volatile firstTimer;
  141. WaitableEvent callbackArrived;
  142. struct CallTimersMessage : public MessageManager::MessageBase
  143. {
  144. CallTimersMessage() {}
  145. void messageCallback() override
  146. {
  147. if (instance != nullptr)
  148. instance->callTimers();
  149. }
  150. };
  151. //==============================================================================
  152. void addTimer (Timer* const t) noexcept
  153. {
  154. #if JUCE_DEBUG
  155. // trying to add a timer that's already here - shouldn't get to this point,
  156. // so if you get this assertion, let me know!
  157. jassert (! timerExists (t));
  158. #endif
  159. Timer* i = firstTimer;
  160. if (i == nullptr || i->timerCountdownMs > t->timerCountdownMs)
  161. {
  162. t->nextTimer = firstTimer;
  163. firstTimer = t;
  164. }
  165. else
  166. {
  167. while (i->nextTimer != nullptr && i->nextTimer->timerCountdownMs <= t->timerCountdownMs)
  168. i = i->nextTimer;
  169. jassert (i != nullptr);
  170. t->nextTimer = i->nextTimer;
  171. t->previousTimer = i;
  172. i->nextTimer = t;
  173. }
  174. if (t->nextTimer != nullptr)
  175. t->nextTimer->previousTimer = t;
  176. jassert ((t->nextTimer == nullptr || t->nextTimer->timerCountdownMs >= t->timerCountdownMs)
  177. && (t->previousTimer == nullptr || t->previousTimer->timerCountdownMs <= t->timerCountdownMs));
  178. notify();
  179. }
  180. void removeTimer (Timer* const t) noexcept
  181. {
  182. #if JUCE_DEBUG
  183. // trying to remove a timer that's not here - shouldn't get to this point,
  184. // so if you get this assertion, let me know!
  185. jassert (timerExists (t));
  186. #endif
  187. if (t->previousTimer != nullptr)
  188. {
  189. jassert (firstTimer != t);
  190. t->previousTimer->nextTimer = t->nextTimer;
  191. }
  192. else
  193. {
  194. jassert (firstTimer == t);
  195. firstTimer = t->nextTimer;
  196. }
  197. if (t->nextTimer != nullptr)
  198. t->nextTimer->previousTimer = t->previousTimer;
  199. t->nextTimer = nullptr;
  200. t->previousTimer = nullptr;
  201. }
  202. int getTimeUntilFirstTimer (const int numMillisecsElapsed) const
  203. {
  204. const LockType::ScopedLockType sl (lock);
  205. for (Timer* t = firstTimer; t != nullptr; t = t->nextTimer)
  206. t->timerCountdownMs -= numMillisecsElapsed;
  207. return firstTimer != nullptr ? firstTimer->timerCountdownMs : 1000;
  208. }
  209. void handleAsyncUpdate() override
  210. {
  211. startThread (7);
  212. }
  213. #if JUCE_DEBUG
  214. bool timerExists (Timer* const t) const noexcept
  215. {
  216. for (Timer* tt = firstTimer; tt != nullptr; tt = tt->nextTimer)
  217. if (tt == t)
  218. return true;
  219. return false;
  220. }
  221. #endif
  222. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimerThread)
  223. };
  224. Timer::TimerThread* Timer::TimerThread::instance = nullptr;
  225. Timer::TimerThread::LockType Timer::TimerThread::lock;
  226. //==============================================================================
  227. Timer::Timer() noexcept
  228. : timerCountdownMs (0),
  229. timerPeriodMs (0),
  230. previousTimer (nullptr),
  231. nextTimer (nullptr)
  232. {
  233. }
  234. Timer::Timer (const Timer&) noexcept
  235. : timerCountdownMs (0),
  236. timerPeriodMs (0),
  237. previousTimer (nullptr),
  238. nextTimer (nullptr)
  239. {
  240. }
  241. Timer::~Timer()
  242. {
  243. stopTimer();
  244. }
  245. void Timer::startTimer (const int interval) noexcept
  246. {
  247. // If you're calling this before (or after) the MessageManager is
  248. // running, then you're not going to get any timer callbacks!
  249. jassert (MessageManager::getInstanceWithoutCreating() != nullptr);
  250. const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
  251. if (timerPeriodMs == 0)
  252. {
  253. timerCountdownMs = interval;
  254. timerPeriodMs = jmax (1, interval);
  255. TimerThread::add (this);
  256. }
  257. else
  258. {
  259. TimerThread::resetCounter (this, interval);
  260. }
  261. }
  262. void Timer::startTimerHz (int timerFrequencyHz) noexcept
  263. {
  264. if (timerFrequencyHz > 0)
  265. startTimer (1000 / timerFrequencyHz);
  266. else
  267. stopTimer();
  268. }
  269. void Timer::stopTimer() noexcept
  270. {
  271. const TimerThread::LockType::ScopedLockType sl (TimerThread::lock);
  272. if (timerPeriodMs > 0)
  273. {
  274. TimerThread::remove (this);
  275. timerPeriodMs = 0;
  276. }
  277. }
  278. void JUCE_CALLTYPE Timer::callPendingTimersSynchronously()
  279. {
  280. if (TimerThread::instance != nullptr)
  281. TimerThread::instance->callTimersSynchronously();
  282. }