mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Updated Timer code to avoid a rare messaging problem. Fixed a couple of minor build errors. Rearranged the atomic functions and added a new compare-and-swap operation. Added a thread-priority tweak to WASAPI. Removed MS-specific classes from the web browser component.
This commit is contained in:
parent
c86c7a8011
commit
35a4b5085f
18 changed files with 559 additions and 640 deletions
|
|
@ -4214,6 +4214,7 @@
|
|||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_VERSION = 4.2;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = iphoneos3.0;
|
||||
|
|
@ -4226,6 +4227,7 @@
|
|||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = iphoneos3.0;
|
||||
ZERO_LINK = NO;
|
||||
|
|
@ -4235,6 +4237,7 @@
|
|||
84A487F808A22DD800752A2B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.4;
|
||||
|
|
@ -4245,6 +4248,7 @@
|
|||
84A487F908A22DD800752A2B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
STRIP_STYLE = "non-global";
|
||||
};
|
||||
|
|
|
|||
8
juce.h
8
juce.h
|
|
@ -47,10 +47,6 @@ BEGIN_JUCE_NAMESPACE
|
|||
#pragma warning (disable: 4786) // (old vc6 warning about long class names)
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC || JUCE_IPHONE
|
||||
#pragma align=natural
|
||||
#endif
|
||||
|
||||
// this is where all the class header files get brought in..
|
||||
#include "src/juce_core_includes.h"
|
||||
|
||||
|
|
@ -65,10 +61,6 @@ BEGIN_JUCE_NAMESPACE
|
|||
#pragma pack (pop)
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC || JUCE_IPHONE
|
||||
#pragma align=reset
|
||||
#endif
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
//=============================================================================
|
||||
/** JUCE_FORCE_DEBUG: Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and
|
||||
project settings, but if you define this value, you can override this can force
|
||||
project settings, but if you define this value, you can override this to force
|
||||
it to be true or false.
|
||||
*/
|
||||
#ifndef JUCE_FORCE_DEBUG
|
||||
|
|
@ -123,7 +123,7 @@
|
|||
#define JUCE_USE_FLAC 1
|
||||
#endif
|
||||
|
||||
/** JUCE_USE_OGGBORBIS: Enables the Ogg-Vorbis audio codec classes (available on all platforms).
|
||||
/** JUCE_USE_OGGVORBIS: Enables the Ogg-Vorbis audio codec classes (available on all platforms).
|
||||
If your app doesn't need to read Ogg-Vorbis files, you might want to disable this to
|
||||
reduce the size of your codebase and build time.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -361,6 +361,7 @@
|
|||
#include <MMReg.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <Audioclient.h>
|
||||
#include <Avrt.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -1350,12 +1351,6 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI()
|
|||
jassert (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
|
||||
jassert (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
|
||||
|
||||
// quick test to make sure the run-time lib doesn't crash on freeing a null-pointer.
|
||||
SystemStats* nullPointer = 0;
|
||||
juce_free (nullPointer);
|
||||
delete[] nullPointer;
|
||||
delete nullPointer;
|
||||
|
||||
// Some quick stream tests..
|
||||
int randomInt = Random::getSystemRandom().nextInt();
|
||||
int64 randomInt64 = Random::getSystemRandom().nextInt64();
|
||||
|
|
@ -2937,8 +2932,7 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other) throw()
|
|||
|
||||
bool MemoryBlock::operator== (const MemoryBlock& other) const throw()
|
||||
{
|
||||
return (size == other.size)
|
||||
&& (memcmp (data, other.data, size) == 0);
|
||||
return matches (other.data, other.size);
|
||||
}
|
||||
|
||||
bool MemoryBlock::operator!= (const MemoryBlock& other) const throw()
|
||||
|
|
@ -2946,6 +2940,12 @@ bool MemoryBlock::operator!= (const MemoryBlock& other) const throw()
|
|||
return ! operator== (other);
|
||||
}
|
||||
|
||||
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const throw()
|
||||
{
|
||||
return size == dataSize
|
||||
&& memcmp (data, dataToCompare, size) == 0;
|
||||
}
|
||||
|
||||
// this will resize the block to this size
|
||||
void MemoryBlock::setSize (const size_t newSize,
|
||||
const bool initialiseToZero) throw()
|
||||
|
|
@ -30191,8 +30191,8 @@ private:
|
|||
{
|
||||
for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i)
|
||||
{
|
||||
numIns = jmax (numIns, supportedChannels[i].inChannels);
|
||||
numOuts = jmax (numOuts, supportedChannels[i].outChannels);
|
||||
numIns = jmax (numIns, (int) supportedChannels[i].inChannels);
|
||||
numOuts = jmax (numOuts, (int) supportedChannels[i].outChannels);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -38011,16 +38011,168 @@ class InternalTimerThread : private Thread,
|
|||
private DeletedAtShutdown,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
InternalTimerThread()
|
||||
: Thread ("Juce Timer"),
|
||||
firstTimer (0),
|
||||
callbackNeeded (false)
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
~InternalTimerThread() throw()
|
||||
{
|
||||
stopThread (4000);
|
||||
|
||||
jassert (instance == this || instance == 0);
|
||||
if (instance == this)
|
||||
instance = 0;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
uint32 lastTime = Time::getMillisecondCounter();
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
const uint32 now = Time::getMillisecondCounter();
|
||||
|
||||
if (now <= lastTime)
|
||||
{
|
||||
wait (2);
|
||||
continue;
|
||||
}
|
||||
|
||||
const int elapsed = now - lastTime;
|
||||
lastTime = now;
|
||||
|
||||
lock.enter();
|
||||
decrementAllCounters (elapsed);
|
||||
const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs
|
||||
: 1000;
|
||||
lock.exit();
|
||||
|
||||
if (timeUntilFirstTimer <= 0)
|
||||
{
|
||||
if (callbackNeeded.set (true))
|
||||
{
|
||||
postMessage (new Message());
|
||||
|
||||
const uint32 messageDeliveryTimeout = now + 2000;
|
||||
|
||||
while (callbackNeeded.get())
|
||||
{
|
||||
wait (4);
|
||||
|
||||
if (threadShouldExit())
|
||||
return;
|
||||
|
||||
if (Time::getMillisecondCounter() > messageDeliveryTimeout)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't wait for too long because running this loop also helps keep the
|
||||
// Time::getApproximateMillisecondTimer value stay up-to-date
|
||||
wait (jlimit (1, 50, timeUntilFirstTimer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleMessage (const Message&)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
while (firstTimer != 0 && firstTimer->countdownMs <= 0)
|
||||
{
|
||||
Timer* const t = firstTimer;
|
||||
t->countdownMs = t->periodMs;
|
||||
|
||||
removeTimer (t);
|
||||
addTimer (t);
|
||||
|
||||
const ScopedUnlock ul (lock);
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
t->timerCallback();
|
||||
}
|
||||
JUCE_CATCH_EXCEPTION
|
||||
}
|
||||
|
||||
callbackNeeded.set (false);
|
||||
}
|
||||
|
||||
static void callAnyTimersSynchronously()
|
||||
{
|
||||
if (InternalTimerThread::instance != 0)
|
||||
{
|
||||
const Message m;
|
||||
InternalTimerThread::instance->handleMessage (m);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void add (Timer* const tim) throw()
|
||||
{
|
||||
if (instance == 0)
|
||||
instance = new InternalTimerThread();
|
||||
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
|
||||
static inline void remove (Timer* const tim) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void resetCounter (Timer* const tim,
|
||||
const int newCounter) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
tim->countdownMs = newCounter;
|
||||
tim->periodMs = newCounter;
|
||||
|
||||
if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs)
|
||||
|| (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs))
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Timer;
|
||||
static InternalTimerThread* instance;
|
||||
static CriticalSection lock;
|
||||
|
||||
Timer* volatile firstTimer;
|
||||
bool volatile callbackNeeded;
|
||||
|
||||
InternalTimerThread (const InternalTimerThread&);
|
||||
const InternalTimerThread& operator= (const InternalTimerThread&);
|
||||
class AtomicBool
|
||||
{
|
||||
public:
|
||||
AtomicBool (const bool value) throw() : value (static_cast<int32> (value)) {}
|
||||
~AtomicBool() throw() {}
|
||||
|
||||
bool get() const throw() { return value != 0; }
|
||||
bool set (const bool newValue) { return Atomic::compareAndExchange (value, newValue ? 1 : 0, value) != 0; }
|
||||
|
||||
private:
|
||||
int32 value;
|
||||
|
||||
AtomicBool (const AtomicBool&);
|
||||
AtomicBool& operator= (const AtomicBool&);
|
||||
};
|
||||
|
||||
AtomicBool callbackNeeded;
|
||||
|
||||
void addTimer (Timer* const t) throw()
|
||||
{
|
||||
|
|
@ -38123,146 +38275,8 @@ private:
|
|||
startThread (7);
|
||||
}
|
||||
|
||||
public:
|
||||
InternalTimerThread()
|
||||
: Thread ("Juce Timer"),
|
||||
firstTimer (0),
|
||||
callbackNeeded (false)
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
~InternalTimerThread() throw()
|
||||
{
|
||||
stopThread (4000);
|
||||
|
||||
jassert (instance == this || instance == 0);
|
||||
if (instance == this)
|
||||
instance = 0;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
uint32 lastTime = Time::getMillisecondCounter();
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
uint32 now = Time::getMillisecondCounter();
|
||||
|
||||
if (now <= lastTime)
|
||||
{
|
||||
wait (2);
|
||||
continue;
|
||||
}
|
||||
|
||||
const int elapsed = now - lastTime;
|
||||
lastTime = now;
|
||||
|
||||
lock.enter();
|
||||
decrementAllCounters (elapsed);
|
||||
const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs
|
||||
: 1000;
|
||||
lock.exit();
|
||||
|
||||
if (timeUntilFirstTimer <= 0)
|
||||
{
|
||||
callbackNeeded = true;
|
||||
postMessage (new Message());
|
||||
|
||||
// sometimes, our message could get discarded by the OS (particularly 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.
|
||||
const uint32 messageDeliveryTimeout = now + 2000;
|
||||
|
||||
while (callbackNeeded)
|
||||
{
|
||||
wait (4);
|
||||
|
||||
if (threadShouldExit())
|
||||
return;
|
||||
|
||||
now = Time::getMillisecondCounter();
|
||||
|
||||
if (now > messageDeliveryTimeout)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't wait for too long because running this loop also helps keep the
|
||||
// Time::getApproximateMillisecondTimer value stay up-to-date
|
||||
wait (jlimit (1, 50, timeUntilFirstTimer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleMessage (const Message&)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
while (firstTimer != 0 && firstTimer->countdownMs <= 0)
|
||||
{
|
||||
Timer* const t = firstTimer;
|
||||
t->countdownMs = t->periodMs;
|
||||
|
||||
removeTimer (t);
|
||||
addTimer (t);
|
||||
|
||||
const ScopedUnlock ul (lock);
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
t->timerCallback();
|
||||
}
|
||||
JUCE_CATCH_EXCEPTION
|
||||
}
|
||||
|
||||
callbackNeeded = false;
|
||||
}
|
||||
|
||||
static void callAnyTimersSynchronously()
|
||||
{
|
||||
if (InternalTimerThread::instance != 0)
|
||||
{
|
||||
const Message m;
|
||||
InternalTimerThread::instance->handleMessage (m);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void add (Timer* const tim) throw()
|
||||
{
|
||||
if (instance == 0)
|
||||
instance = new InternalTimerThread();
|
||||
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
|
||||
static inline void remove (Timer* const tim) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void resetCounter (Timer* const tim,
|
||||
const int newCounter) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
tim->countdownMs = newCounter;
|
||||
tim->periodMs = newCounter;
|
||||
|
||||
if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs)
|
||||
|| (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs))
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
}
|
||||
}
|
||||
InternalTimerThread (const InternalTimerThread&);
|
||||
InternalTimerThread& operator= (const InternalTimerThread&);
|
||||
};
|
||||
|
||||
InternalTimerThread* InternalTimerThread::instance = 0;
|
||||
|
|
@ -70888,12 +70902,13 @@ ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
|
|||
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& name,
|
||||
const StringArray& choices_)
|
||||
const StringArray& choices_,
|
||||
const Array <int>* choiceIDs)
|
||||
: PropertyComponent (name),
|
||||
choices (choices_),
|
||||
comboBox (0)
|
||||
{
|
||||
createComboBox();
|
||||
createComboBox (choiceIDs);
|
||||
|
||||
comboBox->getSelectedIdAsValue().referTo (valueToControl);
|
||||
}
|
||||
|
|
@ -70903,14 +70918,18 @@ ChoicePropertyComponent::~ChoicePropertyComponent()
|
|||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void ChoicePropertyComponent::createComboBox()
|
||||
void ChoicePropertyComponent::createComboBox (const Array <int>* choiceIDs)
|
||||
{
|
||||
// The array of IDs must contain the same number of values as the choices list!
|
||||
jassert (choiceIDs == 0 || choiceIDs->size() == choices.size());
|
||||
|
||||
addAndMakeVisible (comboBox = new ComboBox (String::empty));
|
||||
|
||||
for (int i = 0; i < choices.size(); ++i)
|
||||
{
|
||||
if (choices[i].isNotEmpty())
|
||||
comboBox->addItem (choices[i], i + 1);
|
||||
comboBox->addItem (choices[i], choiceIDs == 0 ? (i + 1)
|
||||
: ((*choiceIDs)[i]));
|
||||
else
|
||||
comboBox->addSeparator();
|
||||
}
|
||||
|
|
@ -70937,7 +70956,7 @@ void ChoicePropertyComponent::refresh()
|
|||
{
|
||||
if (comboBox == 0)
|
||||
{
|
||||
createComboBox();
|
||||
createComboBox (0);
|
||||
comboBox->addListener (this);
|
||||
}
|
||||
|
||||
|
|
@ -212362,6 +212381,17 @@ int SystemStats::getPageSize() throw()
|
|||
extern HWND juce_messageWindowHandle;
|
||||
#endif
|
||||
|
||||
#if ! JUCE_USE_INTRINSICS
|
||||
// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
|
||||
// older ones we have to actually call the ops as win32 functions..
|
||||
void Atomic::increment (int32& variable) { InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
int32 Atomic::incrementAndReturn (int32& variable) { return InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
void Atomic::decrement (int32& variable) { InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
int32 Atomic::decrementAndReturn (int32& variable) { return InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); }
|
||||
#endif
|
||||
|
||||
CriticalSection::CriticalSection() throw()
|
||||
{
|
||||
// (just to check the MS haven't changed this structure and broken things...)
|
||||
|
|
@ -219239,10 +219269,18 @@ public:
|
|||
if (browser != 0)
|
||||
{
|
||||
LPSAFEARRAY sa = 0;
|
||||
_variant_t flags, frame, postDataVar, headersVar;
|
||||
|
||||
VARIANT flags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)
|
||||
VariantInit (&flags);
|
||||
VariantInit (&frame);
|
||||
VariantInit (&postDataVar);
|
||||
VariantInit (&headersVar);
|
||||
|
||||
if (headers != 0)
|
||||
headersVar = (const tchar*) headers->joinIntoString ("\r\n");
|
||||
{
|
||||
V_VT (&headersVar) = VT_BSTR;
|
||||
V_BSTR (&headersVar) = SysAllocString ((const tchar*) headers->joinIntoString ("\r\n"));
|
||||
}
|
||||
|
||||
if (postData != 0 && postData->getSize() > 0)
|
||||
{
|
||||
|
|
@ -219275,6 +219313,11 @@ public:
|
|||
|
||||
if (sa != 0)
|
||||
SafeArrayDestroy (sa);
|
||||
|
||||
VariantClear (&flags);
|
||||
VariantClear (&frame);
|
||||
VariantClear (&postDataVar);
|
||||
VariantClear (&headersVar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227197,8 +227240,26 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setMMThreadPriority()
|
||||
{
|
||||
DynamicLibraryLoader dll ("avrt.dll");
|
||||
DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD))
|
||||
DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY))
|
||||
|
||||
if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0)
|
||||
{
|
||||
DWORD dummy = 0;
|
||||
HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy);
|
||||
|
||||
if (h != 0)
|
||||
avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
setMMThreadPriority();
|
||||
|
||||
const int bufferSize = currentBufferSizeSamples;
|
||||
|
||||
HANDLE events[2];
|
||||
|
|
|
|||
|
|
@ -1445,10 +1445,6 @@ BEGIN_JUCE_NAMESPACE
|
|||
#pragma warning (disable: 4786) // (old vc6 warning about long class names)
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC || JUCE_IPHONE
|
||||
#pragma align=natural
|
||||
#endif
|
||||
|
||||
// this is where all the class header files get brought in..
|
||||
|
||||
/********* Start of inlined file: juce_core_includes.h *********/
|
||||
|
|
@ -2701,6 +2697,8 @@ public:
|
|||
|
||||
bool operator!= (const MemoryBlock& other) const throw();
|
||||
|
||||
bool matches (const void* data, size_t dataSize) const throw();
|
||||
|
||||
template <class DataType>
|
||||
operator DataType*() const throw() { return (DataType*) data; }
|
||||
|
||||
|
|
@ -4364,165 +4362,49 @@ private:
|
|||
class JUCE_API Atomic
|
||||
{
|
||||
public:
|
||||
static void increment (int& variable);
|
||||
static void increment (int32& variable);
|
||||
|
||||
static int incrementAndReturn (int& variable);
|
||||
static int32 incrementAndReturn (int32& variable);
|
||||
|
||||
static void decrement (int& variable);
|
||||
static void decrement (int32& variable);
|
||||
|
||||
static int decrementAndReturn (int& variable);
|
||||
static int32 decrementAndReturn (int32& variable);
|
||||
|
||||
static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue);
|
||||
};
|
||||
|
||||
#if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone...
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
inline void Atomic::increment (int& variable) { OSAtomicIncrement32 ((int32_t*) &variable); }
|
||||
inline int Atomic::incrementAndReturn (int& variable) { return OSAtomicIncrement32 ((int32_t*) &variable); }
|
||||
inline void Atomic::decrement (int& variable) { OSAtomicDecrement32 ((int32_t*) &variable); }
|
||||
inline int Atomic::decrementAndReturn (int& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); }
|
||||
inline void Atomic::increment (int32& variable) { OSAtomicIncrement32 ((volatile int32_t*) &variable); }
|
||||
inline int32 Atomic::incrementAndReturn (int32& variable) { return OSAtomicIncrement32 ((volatile int32_t*) &variable); }
|
||||
inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 ((volatile int32_t*) &variable); }
|
||||
inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((volatile int32_t*) &variable); }
|
||||
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (volatile int32_t*) &destination); }
|
||||
|
||||
#elif JUCE_GCC
|
||||
#elif JUCE_GCC // Linux...
|
||||
|
||||
#if JUCE_USE_GCC_ATOMIC_INTRINSICS // Linux with intrinsics...
|
||||
inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); }
|
||||
inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); }
|
||||
inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); }
|
||||
inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); }
|
||||
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return __sync_val_compare_and_swap (&destination, oldValue, newValue); }
|
||||
|
||||
inline void Atomic::increment (int& variable) { __sync_add_and_fetch (&variable, 1); }
|
||||
inline int Atomic::incrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, 1); }
|
||||
inline void Atomic::decrement (int& variable) { __sync_add_and_fetch (&variable, -1); }
|
||||
inline int Atomic::decrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, -1); }
|
||||
|
||||
#else // Linux without intrinsics...
|
||||
|
||||
inline void Atomic::increment (int& variable)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock incl (%%rax)"
|
||||
:
|
||||
: "a" (&variable)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock incl %0"
|
||||
: "=m" (variable)
|
||||
: "m" (variable));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int Atomic::incrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock xaddl %%ebx, (%%rax) \n\
|
||||
incl %%ebx"
|
||||
: "=b" (result)
|
||||
: "a" (&variable), "b" (1)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock xaddl %%eax, (%%ecx) \n\
|
||||
incl %%eax"
|
||||
: "=a" (result)
|
||||
: "c" (&variable), "a" (1)
|
||||
: "memory");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void Atomic::decrement (int& variable)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock decl (%%rax)"
|
||||
:
|
||||
: "a" (&variable)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock decl %0"
|
||||
: "=m" (variable)
|
||||
: "m" (variable));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int Atomic::decrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock xaddl %%ebx, (%%rax) \n\
|
||||
decl %%ebx"
|
||||
: "=b" (result)
|
||||
: "a" (&variable), "b" (-1)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock xaddl %%eax, (%%ecx) \n\
|
||||
decl %%eax"
|
||||
: "=a" (result)
|
||||
: "c" (&variable), "a" (-1)
|
||||
: "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif JUCE_USE_INTRINSICS // Windows with intrinsics...
|
||||
#elif JUCE_USE_INTRINSICS // Windows...
|
||||
|
||||
// (If JUCE_USE_INTRINSICS isn't enabled, a fallback version of these methods is
|
||||
// declared in juce_win32_Threads.cpp)
|
||||
#pragma intrinsic (_InterlockedIncrement)
|
||||
#pragma intrinsic (_InterlockedDecrement)
|
||||
#pragma intrinsic (_InterlockedCompareExchange)
|
||||
|
||||
inline void Atomic::increment (int& variable) { _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int Atomic::incrementAndReturn (int& variable) { return _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline void Atomic::decrement (int& variable) { _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int Atomic::decrementAndReturn (int& variable) { return _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
|
||||
#else // Windows without intrinsics...
|
||||
|
||||
inline void Atomic::increment (int& variable)
|
||||
{
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
lock inc dword ptr [ecx]
|
||||
}
|
||||
}
|
||||
|
||||
inline int Atomic::incrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
mov eax, 1
|
||||
lock xadd dword ptr [ecx], eax
|
||||
inc eax
|
||||
mov result, eax
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void Atomic::decrement (int& variable)
|
||||
{
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
lock dec dword ptr [ecx]
|
||||
}
|
||||
}
|
||||
|
||||
inline int Atomic::decrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
mov eax, -1
|
||||
lock xadd dword ptr [ecx], eax
|
||||
dec eax
|
||||
mov result, eax
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
inline void Atomic::increment (int32& variable) { _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int32 Atomic::incrementAndReturn (int32& variable) { return _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline void Atomic::decrement (int32& variable) { _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int32 Atomic::decrementAndReturn (int32& variable) { return _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return _InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -5118,7 +5000,7 @@ public:
|
|||
// avoids getting warning messages about the parameter being unused
|
||||
|
||||
lock.enter();
|
||||
sortArray (comparator, (ObjectClass*) data.elements, 0, size() - 1, retainOrderOfEquivalentItems);
|
||||
sortArray (comparator, (ObjectClass**) data.elements, 0, size() - 1, retainOrderOfEquivalentItems);
|
||||
lock.exit();
|
||||
}
|
||||
|
||||
|
|
@ -25219,7 +25101,8 @@ protected:
|
|||
public:
|
||||
ChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices);
|
||||
const StringArray& choices,
|
||||
const Array <int>* choiceIDs = 0);
|
||||
|
||||
~ChoicePropertyComponent();
|
||||
|
||||
|
|
@ -25240,7 +25123,7 @@ protected:
|
|||
private:
|
||||
ComboBox* comboBox;
|
||||
|
||||
void createComboBox();
|
||||
void createComboBox (const Array <int>* choiceIDs);
|
||||
|
||||
ChoicePropertyComponent (const ChoicePropertyComponent&);
|
||||
const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&);
|
||||
|
|
@ -27620,10 +27503,6 @@ public:
|
|||
#pragma pack (pop)
|
||||
#endif
|
||||
|
||||
#if JUCE_MAC || JUCE_IPHONE
|
||||
#pragma align=reset
|
||||
#endif
|
||||
|
||||
END_JUCE_NAMESPACE
|
||||
|
||||
#ifndef DONT_SET_USING_JUCE_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -351,8 +351,8 @@ private:
|
|||
{
|
||||
for (int i = 0; i < supportedChannelsSize / sizeof (AUChannelInfo); ++i)
|
||||
{
|
||||
numIns = jmax (numIns, supportedChannels[i].inChannels);
|
||||
numOuts = jmax (numOuts, supportedChannels[i].outChannels);
|
||||
numIns = jmax (numIns, (int) supportedChannels[i].inChannels);
|
||||
numOuts = jmax (numOuts, (int) supportedChannels[i].outChannels);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -98,8 +98,7 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other) throw()
|
|||
//==============================================================================
|
||||
bool MemoryBlock::operator== (const MemoryBlock& other) const throw()
|
||||
{
|
||||
return (size == other.size)
|
||||
&& (memcmp (data, other.data, size) == 0);
|
||||
return matches (other.data, other.size);
|
||||
}
|
||||
|
||||
bool MemoryBlock::operator!= (const MemoryBlock& other) const throw()
|
||||
|
|
@ -107,6 +106,12 @@ bool MemoryBlock::operator!= (const MemoryBlock& other) const throw()
|
|||
return ! operator== (other);
|
||||
}
|
||||
|
||||
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const throw()
|
||||
{
|
||||
return size == dataSize
|
||||
&& memcmp (data, dataToCompare, size) == 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// this will resize the block to this size
|
||||
void MemoryBlock::setSize (const size_t newSize,
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@ public:
|
|||
*/
|
||||
bool operator!= (const MemoryBlock& other) const throw();
|
||||
|
||||
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in.
|
||||
*/
|
||||
bool matches (const void* data, size_t dataSize) const throw();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a pointer to the data, casting it to any type of primitive data required.
|
||||
|
||||
|
|
|
|||
|
|
@ -34,174 +34,60 @@ class JUCE_API Atomic
|
|||
{
|
||||
public:
|
||||
/** Increments an integer in a thread-safe way. */
|
||||
static void increment (int& variable);
|
||||
static void increment (int32& variable);
|
||||
|
||||
/** Increments an integer in a thread-safe way and returns its new value. */
|
||||
static int incrementAndReturn (int& variable);
|
||||
static int32 incrementAndReturn (int32& variable);
|
||||
|
||||
/** Decrements an integer in a thread-safe way. */
|
||||
static void decrement (int& variable);
|
||||
static void decrement (int32& variable);
|
||||
|
||||
/** Decrements an integer in a thread-safe way and returns its new value. */
|
||||
static int decrementAndReturn (int& variable);
|
||||
static int32 decrementAndReturn (int32& variable);
|
||||
|
||||
/** If the current value of destination is equal to requiredCurrentValue, this
|
||||
will set it to newValue; otherwise, it will leave it unchanged.
|
||||
@returns the new value of destination
|
||||
*/
|
||||
static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue);
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
#if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone...
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
inline void Atomic::increment (int& variable) { OSAtomicIncrement32 ((int32_t*) &variable); }
|
||||
inline int Atomic::incrementAndReturn (int& variable) { return OSAtomicIncrement32 ((int32_t*) &variable); }
|
||||
inline void Atomic::decrement (int& variable) { OSAtomicDecrement32 ((int32_t*) &variable); }
|
||||
inline int Atomic::decrementAndReturn (int& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); }
|
||||
inline void Atomic::increment (int32& variable) { OSAtomicIncrement32 ((volatile int32_t*) &variable); }
|
||||
inline int32 Atomic::incrementAndReturn (int32& variable) { return OSAtomicIncrement32 ((volatile int32_t*) &variable); }
|
||||
inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 ((volatile int32_t*) &variable); }
|
||||
inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((volatile int32_t*) &variable); }
|
||||
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (volatile int32_t*) &destination); }
|
||||
|
||||
#elif JUCE_GCC
|
||||
#elif JUCE_GCC // Linux...
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_USE_GCC_ATOMIC_INTRINSICS // Linux with intrinsics...
|
||||
|
||||
inline void Atomic::increment (int& variable) { __sync_add_and_fetch (&variable, 1); }
|
||||
inline int Atomic::incrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, 1); }
|
||||
inline void Atomic::decrement (int& variable) { __sync_add_and_fetch (&variable, -1); }
|
||||
inline int Atomic::decrementAndReturn (int& variable) { return __sync_add_and_fetch (&variable, -1); }
|
||||
inline void Atomic::increment (int32& variable) { __sync_add_and_fetch (&variable, 1); }
|
||||
inline int32 Atomic::incrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, 1); }
|
||||
inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&variable, -1); }
|
||||
inline int32 Atomic::decrementAndReturn (int32& variable) { return __sync_add_and_fetch (&variable, -1); }
|
||||
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return __sync_val_compare_and_swap (&destination, oldValue, newValue); }
|
||||
|
||||
//==============================================================================
|
||||
#else // Linux without intrinsics...
|
||||
|
||||
inline void Atomic::increment (int& variable)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock incl (%%rax)"
|
||||
:
|
||||
: "a" (&variable)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock incl %0"
|
||||
: "=m" (variable)
|
||||
: "m" (variable));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int Atomic::incrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock xaddl %%ebx, (%%rax) \n\
|
||||
incl %%ebx"
|
||||
: "=b" (result)
|
||||
: "a" (&variable), "b" (1)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock xaddl %%eax, (%%ecx) \n\
|
||||
incl %%eax"
|
||||
: "=a" (result)
|
||||
: "c" (&variable), "a" (1)
|
||||
: "memory");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void Atomic::decrement (int& variable)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock decl (%%rax)"
|
||||
:
|
||||
: "a" (&variable)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock decl %0"
|
||||
: "=m" (variable)
|
||||
: "m" (variable));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int Atomic::decrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
#if JUCE_64BIT
|
||||
"lock xaddl %%ebx, (%%rax) \n\
|
||||
decl %%ebx"
|
||||
: "=b" (result)
|
||||
: "a" (&variable), "b" (-1)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
"lock xaddl %%eax, (%%ecx) \n\
|
||||
decl %%eax"
|
||||
: "=a" (result)
|
||||
: "c" (&variable), "a" (-1)
|
||||
: "memory");
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_USE_INTRINSICS // Windows with intrinsics...
|
||||
#elif JUCE_USE_INTRINSICS // Windows...
|
||||
|
||||
// (If JUCE_USE_INTRINSICS isn't enabled, a fallback version of these methods is
|
||||
// declared in juce_win32_Threads.cpp)
|
||||
#pragma intrinsic (_InterlockedIncrement)
|
||||
#pragma intrinsic (_InterlockedDecrement)
|
||||
#pragma intrinsic (_InterlockedCompareExchange)
|
||||
|
||||
inline void Atomic::increment (int& variable) { _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int Atomic::incrementAndReturn (int& variable) { return _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline void Atomic::decrement (int& variable) { _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int Atomic::decrementAndReturn (int& variable) { return _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
|
||||
//==============================================================================
|
||||
#else // Windows without intrinsics...
|
||||
|
||||
inline void Atomic::increment (int& variable)
|
||||
{
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
lock inc dword ptr [ecx]
|
||||
}
|
||||
}
|
||||
|
||||
inline int Atomic::incrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
mov eax, 1
|
||||
lock xadd dword ptr [ecx], eax
|
||||
inc eax
|
||||
mov result, eax
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void Atomic::decrement (int& variable)
|
||||
{
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
lock dec dword ptr [ecx]
|
||||
}
|
||||
}
|
||||
|
||||
inline int Atomic::decrementAndReturn (int& variable)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm {
|
||||
mov ecx, dword ptr [variable]
|
||||
mov eax, -1
|
||||
lock xadd dword ptr [ecx], eax
|
||||
dec eax
|
||||
mov result, eax
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
inline void Atomic::increment (int32& variable) { _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int32 Atomic::incrementAndReturn (int32& variable) { return _InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline void Atomic::decrement (int32& variable) { _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int32 Atomic::decrementAndReturn (int32& variable) { return _InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return _InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -79,12 +79,6 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI()
|
|||
jassert (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
|
||||
jassert (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
|
||||
|
||||
// quick test to make sure the run-time lib doesn't crash on freeing a null-pointer.
|
||||
SystemStats* nullPointer = 0;
|
||||
juce_free (nullPointer);
|
||||
delete[] nullPointer;
|
||||
delete nullPointer;
|
||||
|
||||
// Some quick stream tests..
|
||||
int randomInt = Random::getSystemRandom().nextInt();
|
||||
int64 randomInt64 = Random::getSystemRandom().nextInt64();
|
||||
|
|
|
|||
|
|
@ -44,17 +44,193 @@ class InternalTimerThread : private Thread,
|
|||
private DeletedAtShutdown,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
InternalTimerThread()
|
||||
: Thread ("Juce Timer"),
|
||||
firstTimer (0),
|
||||
callbackNeeded (false)
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
~InternalTimerThread() throw()
|
||||
{
|
||||
stopThread (4000);
|
||||
|
||||
jassert (instance == this || instance == 0);
|
||||
if (instance == this)
|
||||
instance = 0;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
uint32 lastTime = Time::getMillisecondCounter();
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
const uint32 now = Time::getMillisecondCounter();
|
||||
|
||||
if (now <= lastTime)
|
||||
{
|
||||
wait (2);
|
||||
continue;
|
||||
}
|
||||
|
||||
const int elapsed = now - lastTime;
|
||||
lastTime = now;
|
||||
|
||||
lock.enter();
|
||||
decrementAllCounters (elapsed);
|
||||
const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs
|
||||
: 1000;
|
||||
lock.exit();
|
||||
|
||||
if (timeUntilFirstTimer <= 0)
|
||||
{
|
||||
/* If we managed to set the atomic boolean to true then send a message, this is needed
|
||||
as a memory barrier so the message won't be sent before callbackNeeded is set to true,
|
||||
but if it fails it means the message-thread changed the value from under us so at least
|
||||
some processing is happenening and we can just loop around and try again
|
||||
*/
|
||||
if (callbackNeeded.set (true))
|
||||
{
|
||||
postMessage (new Message());
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
const uint32 messageDeliveryTimeout = now + 2000;
|
||||
|
||||
while (callbackNeeded.get())
|
||||
{
|
||||
wait (4);
|
||||
|
||||
if (threadShouldExit())
|
||||
return;
|
||||
|
||||
if (Time::getMillisecondCounter() > messageDeliveryTimeout)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't wait for too long because running this loop also helps keep the
|
||||
// Time::getApproximateMillisecondTimer value stay up-to-date
|
||||
wait (jlimit (1, 50, timeUntilFirstTimer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleMessage (const Message&)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
while (firstTimer != 0 && firstTimer->countdownMs <= 0)
|
||||
{
|
||||
Timer* const t = firstTimer;
|
||||
t->countdownMs = t->periodMs;
|
||||
|
||||
removeTimer (t);
|
||||
addTimer (t);
|
||||
|
||||
const ScopedUnlock ul (lock);
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
t->timerCallback();
|
||||
}
|
||||
JUCE_CATCH_EXCEPTION
|
||||
}
|
||||
|
||||
/* This is needed as a memory barrier to make sure all processing of current timers is done
|
||||
before the boolean is set. This set should never fail since if it was false in the first place,
|
||||
we wouldn't get a message (so it can't be changed from false to true from under us), and if we
|
||||
get a message then the value is true and the other thread can only set it to true again and
|
||||
we will get another callback to set it to false.
|
||||
*/
|
||||
callbackNeeded.set (false);
|
||||
}
|
||||
|
||||
static void callAnyTimersSynchronously()
|
||||
{
|
||||
if (InternalTimerThread::instance != 0)
|
||||
{
|
||||
const Message m;
|
||||
InternalTimerThread::instance->handleMessage (m);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void add (Timer* const tim) throw()
|
||||
{
|
||||
if (instance == 0)
|
||||
instance = new InternalTimerThread();
|
||||
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
|
||||
static inline void remove (Timer* const tim) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void resetCounter (Timer* const tim,
|
||||
const int newCounter) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
tim->countdownMs = newCounter;
|
||||
tim->periodMs = newCounter;
|
||||
|
||||
if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs)
|
||||
|| (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs))
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Timer;
|
||||
static InternalTimerThread* instance;
|
||||
static CriticalSection lock;
|
||||
|
||||
Timer* volatile firstTimer;
|
||||
bool volatile callbackNeeded;
|
||||
|
||||
InternalTimerThread (const InternalTimerThread&);
|
||||
const InternalTimerThread& operator= (const InternalTimerThread&);
|
||||
//==============================================================================
|
||||
class AtomicBool
|
||||
{
|
||||
public:
|
||||
AtomicBool (const bool value) throw() : value (static_cast<int32> (value)) {}
|
||||
~AtomicBool() throw() {}
|
||||
|
||||
bool get() const throw() { return value != 0; }
|
||||
bool set (const bool newValue) { return Atomic::compareAndExchange (value, newValue ? 1 : 0, value) != 0; }
|
||||
|
||||
/*bool setIfNotAlreadyThisValue (const bool newValue)
|
||||
{
|
||||
int32 valueNew = newValue ? 1 : 0;
|
||||
int32 valueCurrent = 1 - valueNew;
|
||||
return Atomic::compareAndExchange (value, valueNew, valueCurrent);
|
||||
}*/
|
||||
|
||||
private:
|
||||
int32 value;
|
||||
|
||||
AtomicBool (const AtomicBool&);
|
||||
AtomicBool& operator= (const AtomicBool&);
|
||||
};
|
||||
|
||||
AtomicBool callbackNeeded;
|
||||
|
||||
//==============================================================================
|
||||
void addTimer (Timer* const t) throw()
|
||||
{
|
||||
#ifdef JUCE_DEBUG
|
||||
|
|
@ -156,146 +332,8 @@ private:
|
|||
startThread (7);
|
||||
}
|
||||
|
||||
public:
|
||||
InternalTimerThread()
|
||||
: Thread ("Juce Timer"),
|
||||
firstTimer (0),
|
||||
callbackNeeded (false)
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
~InternalTimerThread() throw()
|
||||
{
|
||||
stopThread (4000);
|
||||
|
||||
jassert (instance == this || instance == 0);
|
||||
if (instance == this)
|
||||
instance = 0;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
uint32 lastTime = Time::getMillisecondCounter();
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
uint32 now = Time::getMillisecondCounter();
|
||||
|
||||
if (now <= lastTime)
|
||||
{
|
||||
wait (2);
|
||||
continue;
|
||||
}
|
||||
|
||||
const int elapsed = now - lastTime;
|
||||
lastTime = now;
|
||||
|
||||
lock.enter();
|
||||
decrementAllCounters (elapsed);
|
||||
const int timeUntilFirstTimer = (firstTimer != 0) ? firstTimer->countdownMs
|
||||
: 1000;
|
||||
lock.exit();
|
||||
|
||||
if (timeUntilFirstTimer <= 0)
|
||||
{
|
||||
callbackNeeded = true;
|
||||
postMessage (new Message());
|
||||
|
||||
// sometimes, our message could get discarded by the OS (particularly 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.
|
||||
const uint32 messageDeliveryTimeout = now + 2000;
|
||||
|
||||
while (callbackNeeded)
|
||||
{
|
||||
wait (4);
|
||||
|
||||
if (threadShouldExit())
|
||||
return;
|
||||
|
||||
now = Time::getMillisecondCounter();
|
||||
|
||||
if (now > messageDeliveryTimeout)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't wait for too long because running this loop also helps keep the
|
||||
// Time::getApproximateMillisecondTimer value stay up-to-date
|
||||
wait (jlimit (1, 50, timeUntilFirstTimer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleMessage (const Message&)
|
||||
{
|
||||
const ScopedLock sl (lock);
|
||||
|
||||
while (firstTimer != 0 && firstTimer->countdownMs <= 0)
|
||||
{
|
||||
Timer* const t = firstTimer;
|
||||
t->countdownMs = t->periodMs;
|
||||
|
||||
removeTimer (t);
|
||||
addTimer (t);
|
||||
|
||||
const ScopedUnlock ul (lock);
|
||||
|
||||
JUCE_TRY
|
||||
{
|
||||
t->timerCallback();
|
||||
}
|
||||
JUCE_CATCH_EXCEPTION
|
||||
}
|
||||
|
||||
callbackNeeded = false;
|
||||
}
|
||||
|
||||
static void callAnyTimersSynchronously()
|
||||
{
|
||||
if (InternalTimerThread::instance != 0)
|
||||
{
|
||||
const Message m;
|
||||
InternalTimerThread::instance->handleMessage (m);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void add (Timer* const tim) throw()
|
||||
{
|
||||
if (instance == 0)
|
||||
instance = new InternalTimerThread();
|
||||
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
|
||||
static inline void remove (Timer* const tim) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void resetCounter (Timer* const tim,
|
||||
const int newCounter) throw()
|
||||
{
|
||||
if (instance != 0)
|
||||
{
|
||||
tim->countdownMs = newCounter;
|
||||
tim->periodMs = newCounter;
|
||||
|
||||
if ((tim->next != 0 && tim->next->countdownMs < tim->countdownMs)
|
||||
|| (tim->previous != 0 && tim->previous->countdownMs > tim->countdownMs))
|
||||
{
|
||||
const ScopedLock sl (instance->lock);
|
||||
instance->removeTimer (tim);
|
||||
instance->addTimer (tim);
|
||||
}
|
||||
}
|
||||
}
|
||||
InternalTimerThread (const InternalTimerThread&);
|
||||
InternalTimerThread& operator= (const InternalTimerThread&);
|
||||
};
|
||||
|
||||
InternalTimerThread* InternalTimerThread::instance = 0;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ public:
|
|||
This may be different from getCurrentFile(), which returns the value
|
||||
that is shown in the filename box, and if there are multiple selections,
|
||||
this will only return one of them.
|
||||
@see getCurrentFile
|
||||
@see getSelectedFile
|
||||
*/
|
||||
const File getHighlightedFile() const throw();
|
||||
|
||||
|
|
|
|||
|
|
@ -39,12 +39,13 @@ ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
|
|||
|
||||
ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& name,
|
||||
const StringArray& choices_)
|
||||
const StringArray& choices_,
|
||||
const Array <int>* choiceIDs)
|
||||
: PropertyComponent (name),
|
||||
choices (choices_),
|
||||
comboBox (0)
|
||||
{
|
||||
createComboBox();
|
||||
createComboBox (choiceIDs);
|
||||
|
||||
comboBox->getSelectedIdAsValue().referTo (valueToControl);
|
||||
}
|
||||
|
|
@ -55,14 +56,18 @@ ChoicePropertyComponent::~ChoicePropertyComponent()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void ChoicePropertyComponent::createComboBox()
|
||||
void ChoicePropertyComponent::createComboBox (const Array <int>* choiceIDs)
|
||||
{
|
||||
// The array of IDs must contain the same number of values as the choices list!
|
||||
jassert (choiceIDs == 0 || choiceIDs->size() == choices.size());
|
||||
|
||||
addAndMakeVisible (comboBox = new ComboBox (String::empty));
|
||||
|
||||
for (int i = 0; i < choices.size(); ++i)
|
||||
{
|
||||
if (choices[i].isNotEmpty())
|
||||
comboBox->addItem (choices[i], i + 1);
|
||||
comboBox->addItem (choices[i], choiceIDs == 0 ? (i + 1)
|
||||
: ((*choiceIDs)[i]));
|
||||
else
|
||||
comboBox->addSeparator();
|
||||
}
|
||||
|
|
@ -90,7 +95,7 @@ void ChoicePropertyComponent::refresh()
|
|||
{
|
||||
if (comboBox == 0)
|
||||
{
|
||||
createComboBox();
|
||||
createComboBox (0);
|
||||
comboBox->addListener (this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,12 +63,20 @@ protected:
|
|||
public:
|
||||
/** Creates the component.
|
||||
|
||||
Your subclass's constructor must add a list of options to the choices
|
||||
member variable.
|
||||
@param valueToControl the value that the combo box will read and control
|
||||
@param propertyName the name of the property
|
||||
@param choices the list of possible values that the user can choose between
|
||||
@param choiceIDs if this is 0, then the value corresponding to each item in the
|
||||
'choices' StringArray is simply its index + 1. But if the
|
||||
choiceIDs parameter is specified, it lets you provide a set
|
||||
of IDs for each item in the choices list. If you use this
|
||||
parameter, it must contain the same number of elements as
|
||||
the choices list.
|
||||
*/
|
||||
ChoicePropertyComponent (const Value& valueToControl,
|
||||
const String& propertyName,
|
||||
const StringArray& choices);
|
||||
const StringArray& choices,
|
||||
const Array <int>* choiceIDs = 0);
|
||||
|
||||
/** Destructor. */
|
||||
~ChoicePropertyComponent();
|
||||
|
|
@ -113,7 +121,7 @@ protected:
|
|||
private:
|
||||
ComboBox* comboBox;
|
||||
|
||||
void createComboBox();
|
||||
void createComboBox (const Array <int>* choiceIDs);
|
||||
|
||||
ChoicePropertyComponent (const ChoicePropertyComponent&);
|
||||
const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&);
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@
|
|||
#include <MMReg.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <Audioclient.h>
|
||||
#include <Avrt.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,17 @@
|
|||
extern HWND juce_messageWindowHandle;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#if ! JUCE_USE_INTRINSICS
|
||||
// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
|
||||
// older ones we have to actually call the ops as win32 functions..
|
||||
void Atomic::increment (int32& variable) { InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
int32 Atomic::incrementAndReturn (int32& variable) { return InterlockedIncrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
void Atomic::decrement (int32& variable) { InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
int32 Atomic::decrementAndReturn (int32& variable) { return InterlockedDecrement (reinterpret_cast <volatile long*> (&variable)); }
|
||||
int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue)
|
||||
{ return InterlockedCompareExchange (reinterpret_cast <volatile long*> (&destination), newValue, oldValue); }
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
CriticalSection::CriticalSection() throw()
|
||||
|
|
|
|||
|
|
@ -780,8 +780,26 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setMMThreadPriority()
|
||||
{
|
||||
DynamicLibraryLoader dll ("avrt.dll");
|
||||
DynamicLibraryImport (AvSetMmThreadCharacteristics, avSetMmThreadCharacteristics, HANDLE, dll, (LPCTSTR, LPDWORD))
|
||||
DynamicLibraryImport (AvSetMmThreadPriority, avSetMmThreadPriority, HANDLE, dll, (HANDLE, AVRT_PRIORITY))
|
||||
|
||||
if (avSetMmThreadCharacteristics != 0 && avSetMmThreadPriority != 0)
|
||||
{
|
||||
DWORD dummy = 0;
|
||||
HANDLE h = avSetMmThreadCharacteristics (_T("Pro Audio"), &dummy);
|
||||
|
||||
if (h != 0)
|
||||
avSetMmThreadPriority (h, AVRT_PRIORITY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
setMMThreadPriority();
|
||||
|
||||
const int bufferSize = currentBufferSizeSamples;
|
||||
|
||||
HANDLE events[2];
|
||||
|
|
|
|||
|
|
@ -79,10 +79,18 @@ public:
|
|||
if (browser != 0)
|
||||
{
|
||||
LPSAFEARRAY sa = 0;
|
||||
_variant_t flags, frame, postDataVar, headersVar;
|
||||
|
||||
VARIANT flags, frame, postDataVar, headersVar; // (_variant_t isn't available in all compilers)
|
||||
VariantInit (&flags);
|
||||
VariantInit (&frame);
|
||||
VariantInit (&postDataVar);
|
||||
VariantInit (&headersVar);
|
||||
|
||||
if (headers != 0)
|
||||
headersVar = (const tchar*) headers->joinIntoString ("\r\n");
|
||||
{
|
||||
V_VT (&headersVar) = VT_BSTR;
|
||||
V_BSTR (&headersVar) = SysAllocString ((const tchar*) headers->joinIntoString ("\r\n"));
|
||||
}
|
||||
|
||||
if (postData != 0 && postData->getSize() > 0)
|
||||
{
|
||||
|
|
@ -115,6 +123,11 @@ public:
|
|||
|
||||
if (sa != 0)
|
||||
SafeArrayDestroy (sa);
|
||||
|
||||
VariantClear (&flags);
|
||||
VariantClear (&frame);
|
||||
VariantClear (&postDataVar);
|
||||
VariantClear (&headersVar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue