| @@ -421,16 +421,6 @@ public: | |||
| bool open() | |||
| { | |||
| #if JUCE_WINDOWS | |||
| static bool timePeriodSet = false; | |||
| if (! timePeriodSet) | |||
| { | |||
| timePeriodSet = true; | |||
| timeBeginPeriod (2); | |||
| } | |||
| #endif | |||
| pluginName = file.getFileNameWithoutExtension(); | |||
| module.open (file.getFullPathName()); | |||
| @@ -80,6 +80,7 @@ | |||
| #if JUCE_MAC || JUCE_IOS | |||
| #include <xlocale.h> | |||
| #include <mach/mach.h> | |||
| #endif | |||
| #if JUCE_ANDROID | |||
| @@ -91,9 +92,6 @@ | |||
| namespace juce | |||
| { | |||
| // START_AUTOINCLUDE containers/*.cpp, files/*.cpp, json/*.cpp, logging/*.cpp, maths/*.cpp, | |||
| // memory/*.cpp, misc/*.cpp, network/*.cpp, streams/*.cpp, system/*.cpp, text/*.cpp, threads/*.cpp, | |||
| // time/*.cpp, unit_tests/*.cpp, xml/*.cpp, zip/juce_GZIPD*.cpp, zip/juce_GZIPC*.cpp, zip/juce_Zip*.cpp | |||
| #include "containers/juce_AbstractFifo.cpp" | |||
| #include "containers/juce_DynamicObject.cpp" | |||
| #include "containers/juce_NamedValueSet.cpp" | |||
| @@ -148,7 +146,6 @@ namespace juce | |||
| #include "zip/juce_GZIPDecompressorInputStream.cpp" | |||
| #include "zip/juce_GZIPCompressorOutputStream.cpp" | |||
| #include "zip/juce_ZipFile.cpp" | |||
| // END_AUTOINCLUDE | |||
| //============================================================================== | |||
| #if JUCE_MAC || JUCE_IOS | |||
| @@ -197,4 +194,7 @@ namespace juce | |||
| #include "native/juce_android_Threads.cpp" | |||
| #endif | |||
| #include "threads/juce_HighResolutionTimer.cpp" | |||
| } | |||
| @@ -376,6 +376,9 @@ namespace juce | |||
| #ifndef __JUCE_DYNAMICLIBRARY_JUCEHEADER__ | |||
| #include "threads/juce_DynamicLibrary.h" | |||
| #endif | |||
| #ifndef __JUCE_HIGHRESOLUTIONTIMER_JUCEHEADER__ | |||
| #include "threads/juce_HighResolutionTimer.h" | |||
| #endif | |||
| #ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ | |||
| #include "threads/juce_InterProcessLock.h" | |||
| #endif | |||
| @@ -1119,3 +1119,140 @@ bool ChildProcess::kill() | |||
| { | |||
| return activeProcess == nullptr || activeProcess->killProcess(); | |||
| } | |||
| //============================================================================== | |||
| struct HighResolutionTimer::Pimpl | |||
| { | |||
| Pimpl (HighResolutionTimer& t) : owner (t), thread (0), shouldStop (false) | |||
| { | |||
| } | |||
| ~Pimpl() | |||
| { | |||
| jassert (thread == 0); | |||
| } | |||
| void start (int newPeriod) | |||
| { | |||
| periodMs = newPeriod; | |||
| if (thread == 0) | |||
| { | |||
| shouldStop = false; | |||
| if (pthread_create (&thread, nullptr, timerThread, this) == 0) | |||
| setThreadToRealtime (thread, newPeriod); | |||
| else | |||
| jassertfalse; | |||
| } | |||
| } | |||
| void stop() | |||
| { | |||
| if (thread != 0) | |||
| { | |||
| shouldStop = true; | |||
| while (thread != 0 && thread != pthread_self()) | |||
| Thread::yield(); | |||
| } | |||
| } | |||
| HighResolutionTimer& owner; | |||
| int volatile periodMs; | |||
| private: | |||
| pthread_t thread; | |||
| bool volatile shouldStop; | |||
| static void* timerThread (void* param) | |||
| { | |||
| int dummy; | |||
| pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &dummy); | |||
| reinterpret_cast<Pimpl*> (param)->timerThread(); | |||
| return nullptr; | |||
| } | |||
| void timerThread() | |||
| { | |||
| Clock clock (periodMs); | |||
| while (! shouldStop) | |||
| { | |||
| clock.wait(); | |||
| owner.hiResTimerCallback(); | |||
| } | |||
| periodMs = 0; | |||
| thread = 0; | |||
| } | |||
| struct Clock | |||
| { | |||
| #if JUCE_MAC || JUCE_IOS | |||
| Clock (double millis) | |||
| { | |||
| mach_timebase_info_data_t timebase; | |||
| (void) mach_timebase_info (&timebase); | |||
| delta = (((uint64_t) (millis * 1000000.0)) * timebase.numer) / timebase.denom; | |||
| time = mach_absolute_time(); | |||
| } | |||
| void wait() | |||
| { | |||
| time += delta; | |||
| mach_wait_until (time); | |||
| } | |||
| uint64_t time, delta; | |||
| #else | |||
| Clock (double millis) | |||
| : delta ((int64) (millis * 1000000)) | |||
| { | |||
| struct timespec t; | |||
| clock_gettime (CLOCK_MONOTONIC, &t); | |||
| time = 1000000000 * (int64) t.tv_sec + t.tv_nsec; | |||
| } | |||
| void wait() | |||
| { | |||
| time += delta; | |||
| struct timespec t; | |||
| t.tv_sec = (time_t) (time / 1000000000); | |||
| t.tv_nsec = (long) (time % 1000000000); | |||
| clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &t, nullptr); | |||
| } | |||
| int64 time, delta; | |||
| #endif | |||
| }; | |||
| static bool setThreadToRealtime (pthread_t thread, uint64 periodMs) | |||
| { | |||
| #if JUCE_MAC || JUCE_IOS | |||
| thread_time_constraint_policy_data_t policy; | |||
| policy.period = (uint32_t) (periodMs * 1000000); | |||
| policy.computation = 50000; | |||
| policy.constraint = policy.period; | |||
| policy.preemptible = true; | |||
| return thread_policy_set (pthread_mach_thread_np (thread), | |||
| THREAD_TIME_CONSTRAINT_POLICY, | |||
| (thread_policy_t) &policy, | |||
| THREAD_TIME_CONSTRAINT_POLICY_COUNT) == KERN_SUCCESS; | |||
| #else | |||
| (void) periodMs; | |||
| struct sched_param param; | |||
| param.sched_priority = sched_get_priority_max (SCHED_RR); | |||
| return pthread_setschedparam (thread, SCHED_RR, ¶m) == 0; | |||
| #endif | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE (Pimpl) | |||
| }; | |||
| @@ -582,3 +582,55 @@ bool ChildProcess::kill() | |||
| { | |||
| return activeProcess == nullptr || activeProcess->killProcess(); | |||
| } | |||
| //============================================================================== | |||
| struct HighResolutionTimer::Pimpl | |||
| { | |||
| Pimpl (HighResolutionTimer& t) noexcept : owner (t), periodMs (0) | |||
| { | |||
| } | |||
| ~Pimpl() | |||
| { | |||
| jassert (periodMs == 0); | |||
| } | |||
| void start (int newPeriod) | |||
| { | |||
| if (newPeriod != periodMs) | |||
| { | |||
| stop(); | |||
| periodMs = newPeriod; | |||
| TIMECAPS tc; | |||
| if (timeGetDevCaps (&tc, sizeof (tc)) == TIMERR_NOERROR) | |||
| { | |||
| const int actualPeriod = jlimit ((int) tc.wPeriodMin, (int) tc.wPeriodMax, newPeriod); | |||
| timerID = timeSetEvent (actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this, | |||
| TIME_PERIODIC | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS); | |||
| } | |||
| } | |||
| } | |||
| void stop() | |||
| { | |||
| periodMs = 0; | |||
| timeKillEvent (timerID); | |||
| } | |||
| HighResolutionTimer& owner; | |||
| int periodMs; | |||
| private: | |||
| unsigned int timerID; | |||
| static void __stdcall callbackFunction (UINT, UINT, DWORD_PTR userInfo, DWORD_PTR, DWORD_PTR) | |||
| { | |||
| if (Pimpl* const timer = reinterpret_cast<Pimpl*> (userInfo)) | |||
| if (timer->periodMs != 0) | |||
| timer->owner.hiResTimerCallback(); | |||
| } | |||
| JUCE_DECLARE_NON_COPYABLE (Pimpl) | |||
| }; | |||
| @@ -0,0 +1,33 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-11 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| HighResolutionTimer::HighResolutionTimer() { pimpl = new Pimpl (*this); } | |||
| HighResolutionTimer::~HighResolutionTimer() { stopTimer(); } | |||
| void HighResolutionTimer::startTimer (int periodMs) { pimpl->start (jmax (1, periodMs)); } | |||
| void HighResolutionTimer::stopTimer() { pimpl->stop(); } | |||
| bool HighResolutionTimer::isTimerRunning() const noexcept { return pimpl->periodMs != 0; } | |||
| int HighResolutionTimer::getTimerInterval() const noexcept { return pimpl->periodMs; } | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-11 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_HIGHRESOLUTIONTIMER_JUCEHEADER__ | |||
| #define __JUCE_HIGHRESOLUTIONTIMER_JUCEHEADER__ | |||
| class JUCE_API HighResolutionTimer | |||
| { | |||
| protected: | |||
| /** Creates a HighResolutionTimer. | |||
| When created, the timer is stopped, so use startTimer() to get it going. | |||
| */ | |||
| HighResolutionTimer(); | |||
| public: | |||
| /** Destructor. */ | |||
| virtual ~HighResolutionTimer(); | |||
| //============================================================================== | |||
| /** The user-defined callback routine that actually gets called periodically. | |||
| This will be called on a dedicated timer thread, so make sure your | |||
| implementation is thread-safe! | |||
| It's perfectly ok to call startTimer() or stopTimer() from within this | |||
| callback to change the subsequent intervals. | |||
| */ | |||
| virtual void hiResTimerCallback() = 0; | |||
| //============================================================================== | |||
| /** Starts the timer and sets the length of interval required. | |||
| If the timer is already started, this will reset its counter, 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 values less than 1 will be | |||
| rounded up to 1) | |||
| */ | |||
| void startTimer (int intervalInMilliseconds); | |||
| /** Stops the timer. | |||
| This method may block while it waits for pending callbacks to complete. Once it | |||
| returns, no more callbacks will be made. If it is called from the timer's own thread, | |||
| it will cancel the timer after the current callback returns. | |||
| */ | |||
| void stopTimer(); | |||
| /** Checks if the timer has been started. | |||
| @returns true if the timer is running. | |||
| */ | |||
| bool isTimerRunning() const noexcept; | |||
| /** 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; | |||
| private: | |||
| struct Pimpl; | |||
| friend struct Pimpl; | |||
| friend class ScopedPointer<Pimpl>; | |||
| ScopedPointer<Pimpl> pimpl; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HighResolutionTimer) | |||
| }; | |||
| #endif // __JUCE_HIGHRESOLUTIONTIMER_JUCEHEADER__ | |||