| @@ -421,16 +421,6 @@ public: | |||||
| bool open() | bool open() | ||||
| { | { | ||||
| #if JUCE_WINDOWS | |||||
| static bool timePeriodSet = false; | |||||
| if (! timePeriodSet) | |||||
| { | |||||
| timePeriodSet = true; | |||||
| timeBeginPeriod (2); | |||||
| } | |||||
| #endif | |||||
| pluginName = file.getFileNameWithoutExtension(); | pluginName = file.getFileNameWithoutExtension(); | ||||
| module.open (file.getFullPathName()); | module.open (file.getFullPathName()); | ||||
| @@ -80,6 +80,7 @@ | |||||
| #if JUCE_MAC || JUCE_IOS | #if JUCE_MAC || JUCE_IOS | ||||
| #include <xlocale.h> | #include <xlocale.h> | ||||
| #include <mach/mach.h> | |||||
| #endif | #endif | ||||
| #if JUCE_ANDROID | #if JUCE_ANDROID | ||||
| @@ -91,9 +92,6 @@ | |||||
| namespace juce | 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_AbstractFifo.cpp" | ||||
| #include "containers/juce_DynamicObject.cpp" | #include "containers/juce_DynamicObject.cpp" | ||||
| #include "containers/juce_NamedValueSet.cpp" | #include "containers/juce_NamedValueSet.cpp" | ||||
| @@ -148,7 +146,6 @@ namespace juce | |||||
| #include "zip/juce_GZIPDecompressorInputStream.cpp" | #include "zip/juce_GZIPDecompressorInputStream.cpp" | ||||
| #include "zip/juce_GZIPCompressorOutputStream.cpp" | #include "zip/juce_GZIPCompressorOutputStream.cpp" | ||||
| #include "zip/juce_ZipFile.cpp" | #include "zip/juce_ZipFile.cpp" | ||||
| // END_AUTOINCLUDE | |||||
| //============================================================================== | //============================================================================== | ||||
| #if JUCE_MAC || JUCE_IOS | #if JUCE_MAC || JUCE_IOS | ||||
| @@ -197,4 +194,7 @@ namespace juce | |||||
| #include "native/juce_android_Threads.cpp" | #include "native/juce_android_Threads.cpp" | ||||
| #endif | #endif | ||||
| #include "threads/juce_HighResolutionTimer.cpp" | |||||
| } | } | ||||
| @@ -376,6 +376,9 @@ namespace juce | |||||
| #ifndef __JUCE_DYNAMICLIBRARY_JUCEHEADER__ | #ifndef __JUCE_DYNAMICLIBRARY_JUCEHEADER__ | ||||
| #include "threads/juce_DynamicLibrary.h" | #include "threads/juce_DynamicLibrary.h" | ||||
| #endif | #endif | ||||
| #ifndef __JUCE_HIGHRESOLUTIONTIMER_JUCEHEADER__ | |||||
| #include "threads/juce_HighResolutionTimer.h" | |||||
| #endif | |||||
| #ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ | #ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ | ||||
| #include "threads/juce_InterProcessLock.h" | #include "threads/juce_InterProcessLock.h" | ||||
| #endif | #endif | ||||
| @@ -1119,3 +1119,140 @@ bool ChildProcess::kill() | |||||
| { | { | ||||
| return activeProcess == nullptr || activeProcess->killProcess(); | 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(); | 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__ | |||||