| @@ -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"; | |||
| }; | |||
| @@ -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,118 +38011,6 @@ class InternalTimerThread : private Thread, | |||
| private DeletedAtShutdown, | |||
| private AsyncUpdater | |||
| { | |||
| private: | |||
| friend class Timer; | |||
| static InternalTimerThread* instance; | |||
| static CriticalSection lock; | |||
| Timer* volatile firstTimer; | |||
| bool volatile callbackNeeded; | |||
| InternalTimerThread (const InternalTimerThread&); | |||
| const InternalTimerThread& operator= (const InternalTimerThread&); | |||
| void addTimer (Timer* const t) throw() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| while (tt != 0) | |||
| { | |||
| // 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 (tt != t); | |||
| tt = tt->next; | |||
| } | |||
| jassert (t->previous == 0 && t->next == 0); | |||
| #endif | |||
| Timer* i = firstTimer; | |||
| if (i == 0 || i->countdownMs > t->countdownMs) | |||
| { | |||
| t->next = firstTimer; | |||
| firstTimer = t; | |||
| } | |||
| else | |||
| { | |||
| while (i->next != 0 && i->next->countdownMs <= t->countdownMs) | |||
| i = i->next; | |||
| jassert (i != 0); | |||
| t->next = i->next; | |||
| t->previous = i; | |||
| i->next = t; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t; | |||
| jassert ((t->next == 0 || t->next->countdownMs >= t->countdownMs) | |||
| && (t->previous == 0 || t->previous->countdownMs <= t->countdownMs)); | |||
| notify(); | |||
| } | |||
| void removeTimer (Timer* const t) throw() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| bool found = false; | |||
| while (tt != 0) | |||
| { | |||
| if (tt == t) | |||
| { | |||
| found = true; | |||
| break; | |||
| } | |||
| tt = tt->next; | |||
| } | |||
| // trying to remove a timer that's not here - shouldn't get to this point, | |||
| // so if you get this assertion, let me know! | |||
| jassert (found); | |||
| #endif | |||
| if (t->previous != 0) | |||
| { | |||
| jassert (firstTimer != t); | |||
| t->previous->next = t->next; | |||
| } | |||
| else | |||
| { | |||
| jassert (firstTimer == t); | |||
| firstTimer = t->next; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t->previous; | |||
| t->next = 0; | |||
| t->previous = 0; | |||
| } | |||
| void decrementAllCounters (const int numMillisecs) const | |||
| { | |||
| Timer* t = firstTimer; | |||
| while (t != 0) | |||
| { | |||
| t->countdownMs -= numMillisecs; | |||
| t = t->next; | |||
| } | |||
| } | |||
| void handleAsyncUpdate() | |||
| { | |||
| startThread (7); | |||
| } | |||
| public: | |||
| InternalTimerThread() | |||
| : Thread ("Juce Timer"), | |||
| @@ -38147,7 +38035,7 @@ public: | |||
| while (! threadShouldExit()) | |||
| { | |||
| uint32 now = Time::getMillisecondCounter(); | |||
| const uint32 now = Time::getMillisecondCounter(); | |||
| if (now <= lastTime) | |||
| { | |||
| @@ -38166,24 +38054,22 @@ public: | |||
| 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) | |||
| if (callbackNeeded.set (true)) | |||
| { | |||
| wait (4); | |||
| postMessage (new Message()); | |||
| if (threadShouldExit()) | |||
| return; | |||
| const uint32 messageDeliveryTimeout = now + 2000; | |||
| now = Time::getMillisecondCounter(); | |||
| while (callbackNeeded.get()) | |||
| { | |||
| wait (4); | |||
| if (now > messageDeliveryTimeout) | |||
| break; | |||
| if (threadShouldExit()) | |||
| return; | |||
| if (Time::getMillisecondCounter() > messageDeliveryTimeout) | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| @@ -38216,7 +38102,7 @@ public: | |||
| JUCE_CATCH_EXCEPTION | |||
| } | |||
| callbackNeeded = false; | |||
| callbackNeeded.set (false); | |||
| } | |||
| static void callAnyTimersSynchronously() | |||
| @@ -38263,6 +38149,134 @@ public: | |||
| } | |||
| } | |||
| } | |||
| private: | |||
| friend class Timer; | |||
| static InternalTimerThread* instance; | |||
| static CriticalSection lock; | |||
| Timer* volatile firstTimer; | |||
| 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() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| while (tt != 0) | |||
| { | |||
| // 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 (tt != t); | |||
| tt = tt->next; | |||
| } | |||
| jassert (t->previous == 0 && t->next == 0); | |||
| #endif | |||
| Timer* i = firstTimer; | |||
| if (i == 0 || i->countdownMs > t->countdownMs) | |||
| { | |||
| t->next = firstTimer; | |||
| firstTimer = t; | |||
| } | |||
| else | |||
| { | |||
| while (i->next != 0 && i->next->countdownMs <= t->countdownMs) | |||
| i = i->next; | |||
| jassert (i != 0); | |||
| t->next = i->next; | |||
| t->previous = i; | |||
| i->next = t; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t; | |||
| jassert ((t->next == 0 || t->next->countdownMs >= t->countdownMs) | |||
| && (t->previous == 0 || t->previous->countdownMs <= t->countdownMs)); | |||
| notify(); | |||
| } | |||
| void removeTimer (Timer* const t) throw() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| bool found = false; | |||
| while (tt != 0) | |||
| { | |||
| if (tt == t) | |||
| { | |||
| found = true; | |||
| break; | |||
| } | |||
| tt = tt->next; | |||
| } | |||
| // trying to remove a timer that's not here - shouldn't get to this point, | |||
| // so if you get this assertion, let me know! | |||
| jassert (found); | |||
| #endif | |||
| if (t->previous != 0) | |||
| { | |||
| jassert (firstTimer != t); | |||
| t->previous->next = t->next; | |||
| } | |||
| else | |||
| { | |||
| jassert (firstTimer == t); | |||
| firstTimer = t->next; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t->previous; | |||
| t->next = 0; | |||
| t->previous = 0; | |||
| } | |||
| void decrementAllCounters (const int numMillisecs) const | |||
| { | |||
| Timer* t = firstTimer; | |||
| while (t != 0) | |||
| { | |||
| t->countdownMs -= numMillisecs; | |||
| t = t->next; | |||
| } | |||
| } | |||
| void handleAsyncUpdate() | |||
| { | |||
| startThread (7); | |||
| } | |||
| 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); } | |||
| #elif JUCE_GCC | |||
| #if JUCE_USE_GCC_ATOMIC_INTRINSICS // Linux with intrinsics... | |||
| 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); } | |||
| 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); } | |||
| #elif JUCE_GCC // Linux... | |||
| #else // Linux without 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) | |||
| { | |||
| __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); } | |||
| #elif JUCE_GCC | |||
| //============================================================================== | |||
| #if JUCE_USE_GCC_ATOMIC_INTRINSICS // Linux with intrinsics... | |||
| 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); } | |||
| 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); } | |||
| #elif JUCE_GCC // Linux... | |||
| //============================================================================== | |||
| #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 | |||
| 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); } | |||
| //============================================================================== | |||
| #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) | |||
| 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; | |||
| } | |||
| #pragma intrinsic (_InterlockedCompareExchange) | |||
| 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,118 +44,6 @@ class InternalTimerThread : private Thread, | |||
| private DeletedAtShutdown, | |||
| private AsyncUpdater | |||
| { | |||
| private: | |||
| friend class Timer; | |||
| static InternalTimerThread* instance; | |||
| static CriticalSection lock; | |||
| Timer* volatile firstTimer; | |||
| bool volatile callbackNeeded; | |||
| InternalTimerThread (const InternalTimerThread&); | |||
| const InternalTimerThread& operator= (const InternalTimerThread&); | |||
| void addTimer (Timer* const t) throw() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| while (tt != 0) | |||
| { | |||
| // 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 (tt != t); | |||
| tt = tt->next; | |||
| } | |||
| jassert (t->previous == 0 && t->next == 0); | |||
| #endif | |||
| Timer* i = firstTimer; | |||
| if (i == 0 || i->countdownMs > t->countdownMs) | |||
| { | |||
| t->next = firstTimer; | |||
| firstTimer = t; | |||
| } | |||
| else | |||
| { | |||
| while (i->next != 0 && i->next->countdownMs <= t->countdownMs) | |||
| i = i->next; | |||
| jassert (i != 0); | |||
| t->next = i->next; | |||
| t->previous = i; | |||
| i->next = t; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t; | |||
| jassert ((t->next == 0 || t->next->countdownMs >= t->countdownMs) | |||
| && (t->previous == 0 || t->previous->countdownMs <= t->countdownMs)); | |||
| notify(); | |||
| } | |||
| void removeTimer (Timer* const t) throw() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| bool found = false; | |||
| while (tt != 0) | |||
| { | |||
| if (tt == t) | |||
| { | |||
| found = true; | |||
| break; | |||
| } | |||
| tt = tt->next; | |||
| } | |||
| // trying to remove a timer that's not here - shouldn't get to this point, | |||
| // so if you get this assertion, let me know! | |||
| jassert (found); | |||
| #endif | |||
| if (t->previous != 0) | |||
| { | |||
| jassert (firstTimer != t); | |||
| t->previous->next = t->next; | |||
| } | |||
| else | |||
| { | |||
| jassert (firstTimer == t); | |||
| firstTimer = t->next; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t->previous; | |||
| t->next = 0; | |||
| t->previous = 0; | |||
| } | |||
| void decrementAllCounters (const int numMillisecs) const | |||
| { | |||
| Timer* t = firstTimer; | |||
| while (t != 0) | |||
| { | |||
| t->countdownMs -= numMillisecs; | |||
| t = t->next; | |||
| } | |||
| } | |||
| void handleAsyncUpdate() | |||
| { | |||
| startThread (7); | |||
| } | |||
| public: | |||
| InternalTimerThread() | |||
| : Thread ("Juce Timer"), | |||
| @@ -180,7 +68,7 @@ public: | |||
| while (! threadShouldExit()) | |||
| { | |||
| uint32 now = Time::getMillisecondCounter(); | |||
| const uint32 now = Time::getMillisecondCounter(); | |||
| if (now <= lastTime) | |||
| { | |||
| @@ -199,24 +87,31 @@ public: | |||
| 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) | |||
| /* 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)) | |||
| { | |||
| wait (4); | |||
| postMessage (new Message()); | |||
| if (threadShouldExit()) | |||
| return; | |||
| /* 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; | |||
| now = Time::getMillisecondCounter(); | |||
| while (callbackNeeded.get()) | |||
| { | |||
| wait (4); | |||
| if (now > messageDeliveryTimeout) | |||
| break; | |||
| if (threadShouldExit()) | |||
| return; | |||
| if (Time::getMillisecondCounter() > messageDeliveryTimeout) | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| @@ -249,7 +144,13 @@ public: | |||
| JUCE_CATCH_EXCEPTION | |||
| } | |||
| callbackNeeded = false; | |||
| /* 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() | |||
| @@ -296,6 +197,143 @@ public: | |||
| } | |||
| } | |||
| } | |||
| private: | |||
| friend class Timer; | |||
| static InternalTimerThread* instance; | |||
| static CriticalSection lock; | |||
| Timer* volatile firstTimer; | |||
| //============================================================================== | |||
| 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 | |||
| Timer* tt = firstTimer; | |||
| while (tt != 0) | |||
| { | |||
| // 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 (tt != t); | |||
| tt = tt->next; | |||
| } | |||
| jassert (t->previous == 0 && t->next == 0); | |||
| #endif | |||
| Timer* i = firstTimer; | |||
| if (i == 0 || i->countdownMs > t->countdownMs) | |||
| { | |||
| t->next = firstTimer; | |||
| firstTimer = t; | |||
| } | |||
| else | |||
| { | |||
| while (i->next != 0 && i->next->countdownMs <= t->countdownMs) | |||
| i = i->next; | |||
| jassert (i != 0); | |||
| t->next = i->next; | |||
| t->previous = i; | |||
| i->next = t; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t; | |||
| jassert ((t->next == 0 || t->next->countdownMs >= t->countdownMs) | |||
| && (t->previous == 0 || t->previous->countdownMs <= t->countdownMs)); | |||
| notify(); | |||
| } | |||
| void removeTimer (Timer* const t) throw() | |||
| { | |||
| #ifdef JUCE_DEBUG | |||
| Timer* tt = firstTimer; | |||
| bool found = false; | |||
| while (tt != 0) | |||
| { | |||
| if (tt == t) | |||
| { | |||
| found = true; | |||
| break; | |||
| } | |||
| tt = tt->next; | |||
| } | |||
| // trying to remove a timer that's not here - shouldn't get to this point, | |||
| // so if you get this assertion, let me know! | |||
| jassert (found); | |||
| #endif | |||
| if (t->previous != 0) | |||
| { | |||
| jassert (firstTimer != t); | |||
| t->previous->next = t->next; | |||
| } | |||
| else | |||
| { | |||
| jassert (firstTimer == t); | |||
| firstTimer = t->next; | |||
| } | |||
| if (t->next != 0) | |||
| t->next->previous = t->previous; | |||
| t->next = 0; | |||
| t->previous = 0; | |||
| } | |||
| void decrementAllCounters (const int numMillisecs) const | |||
| { | |||
| Timer* t = firstTimer; | |||
| while (t != 0) | |||
| { | |||
| t->countdownMs -= numMillisecs; | |||
| t = t->next; | |||
| } | |||
| } | |||
| void handleAsyncUpdate() | |||
| { | |||
| startThread (7); | |||
| } | |||
| 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); | |||
| } | |||
| } | |||