diff --git a/build/macosx/Juce.xcodeproj/project.pbxproj b/build/macosx/Juce.xcodeproj/project.pbxproj index e1aa05e2b1..11a29e15c7 100644 --- a/build/macosx/Juce.xcodeproj/project.pbxproj +++ b/build/macosx/Juce.xcodeproj/project.pbxproj @@ -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"; }; diff --git a/juce.h b/juce.h index 9b06d5c915..cbf0fd9f32 100644 --- a/juce.h +++ b/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 diff --git a/juce_Config.h b/juce_Config.h index d37eb8490c..7f9c2f7dc9 100644 --- a/juce_Config.h +++ b/juce_Config.h @@ -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. */ diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index fcd63197df..c4b0a0eb31 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -361,6 +361,7 @@ #include #include #include + #include #include #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 (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 * 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 * 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 (&variable)); } +int32 Atomic::incrementAndReturn (int32& variable) { return InterlockedIncrement (reinterpret_cast (&variable)); } +void Atomic::decrement (int32& variable) { InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::decrementAndReturn (int32& variable) { return InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return InterlockedCompareExchange (reinterpret_cast (&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]; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 9819d31103..b889ca2633 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -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 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 -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 (&variable)); } -inline int Atomic::incrementAndReturn (int& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } -inline void Atomic::decrement (int& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } -inline int Atomic::decrementAndReturn (int& variable) { return _InterlockedDecrement (reinterpret_cast (&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 (&variable)); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } +inline void Atomic::decrement (int32& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return _InterlockedCompareExchange (reinterpret_cast (&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 * choiceIDs = 0); ~ChoicePropertyComponent(); @@ -25240,7 +25123,7 @@ protected: private: ComboBox* comboBox; - void createComboBox(); + void createComboBox (const Array * 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 diff --git a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm index 4c0eb8718d..20c9f44911 100644 --- a/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm +++ b/src/audio/plugins/formats/juce_AudioUnitPluginFormat.mm @@ -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 diff --git a/src/containers/juce_MemoryBlock.cpp b/src/containers/juce_MemoryBlock.cpp index 80f1208e65..a14a28ef38 100644 --- a/src/containers/juce_MemoryBlock.cpp +++ b/src/containers/juce_MemoryBlock.cpp @@ -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, diff --git a/src/containers/juce_MemoryBlock.h b/src/containers/juce_MemoryBlock.h index ffb355ef90..a4cff3429e 100644 --- a/src/containers/juce_MemoryBlock.h +++ b/src/containers/juce_MemoryBlock.h @@ -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. diff --git a/src/core/juce_Atomic.h b/src/core/juce_Atomic.h index 51d9d9e585..4018bc19c4 100644 --- a/src/core/juce_Atomic.h +++ b/src/core/juce_Atomic.h @@ -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 -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 (&variable)); } -inline int Atomic::incrementAndReturn (int& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } -inline void Atomic::decrement (int& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } -inline int Atomic::decrementAndReturn (int& variable) { return _InterlockedDecrement (reinterpret_cast (&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 (&variable)); } +inline int32 Atomic::incrementAndReturn (int32& variable) { return _InterlockedIncrement (reinterpret_cast (&variable)); } +inline void Atomic::decrement (int32& variable) { _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::decrementAndReturn (int32& variable) { return _InterlockedDecrement (reinterpret_cast (&variable)); } +inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return _InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } #endif diff --git a/src/core/juce_SystemStats.cpp b/src/core/juce_SystemStats.cpp index ffd8e4fbc2..7205cbbc61 100644 --- a/src/core/juce_SystemStats.cpp +++ b/src/core/juce_SystemStats.cpp @@ -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(); diff --git a/src/events/juce_Timer.cpp b/src/events/juce_Timer.cpp index daa8c5197e..b6c1eed71f 100644 --- a/src/events/juce_Timer.cpp +++ b/src/events/juce_Timer.cpp @@ -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 (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; diff --git a/src/gui/components/filebrowser/juce_FileBrowserComponent.h b/src/gui/components/filebrowser/juce_FileBrowserComponent.h index b05aa4f566..ac569c7dc2 100644 --- a/src/gui/components/filebrowser/juce_FileBrowserComponent.h +++ b/src/gui/components/filebrowser/juce_FileBrowserComponent.h @@ -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(); diff --git a/src/gui/components/properties/juce_ChoicePropertyComponent.cpp b/src/gui/components/properties/juce_ChoicePropertyComponent.cpp index dd1808faf3..06ebec21c3 100644 --- a/src/gui/components/properties/juce_ChoicePropertyComponent.cpp +++ b/src/gui/components/properties/juce_ChoicePropertyComponent.cpp @@ -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 * 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 * 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); } diff --git a/src/gui/components/properties/juce_ChoicePropertyComponent.h b/src/gui/components/properties/juce_ChoicePropertyComponent.h index 1658caa7cd..56873c800b 100644 --- a/src/gui/components/properties/juce_ChoicePropertyComponent.h +++ b/src/gui/components/properties/juce_ChoicePropertyComponent.h @@ -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 * choiceIDs = 0); /** Destructor. */ ~ChoicePropertyComponent(); @@ -113,7 +121,7 @@ protected: private: ComboBox* comboBox; - void createComboBox(); + void createComboBox (const Array * choiceIDs); ChoicePropertyComponent (const ChoicePropertyComponent&); const ChoicePropertyComponent& operator= (const ChoicePropertyComponent&); diff --git a/src/native/windows/juce_win32_NativeIncludes.h b/src/native/windows/juce_win32_NativeIncludes.h index edc22f23f7..a121da5306 100644 --- a/src/native/windows/juce_win32_NativeIncludes.h +++ b/src/native/windows/juce_win32_NativeIncludes.h @@ -142,6 +142,7 @@ #include #include #include + #include #include #endif diff --git a/src/native/windows/juce_win32_Threads.cpp b/src/native/windows/juce_win32_Threads.cpp index fbb787437c..9553ff40dd 100644 --- a/src/native/windows/juce_win32_Threads.cpp +++ b/src/native/windows/juce_win32_Threads.cpp @@ -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 (&variable)); } +int32 Atomic::incrementAndReturn (int32& variable) { return InterlockedIncrement (reinterpret_cast (&variable)); } +void Atomic::decrement (int32& variable) { InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::decrementAndReturn (int32& variable) { return InterlockedDecrement (reinterpret_cast (&variable)); } +int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) + { return InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } +#endif //============================================================================== CriticalSection::CriticalSection() throw() diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index 25aa8b0ac8..c203606c4f 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -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]; diff --git a/src/native/windows/juce_win32_WebBrowserComponent.cpp b/src/native/windows/juce_win32_WebBrowserComponent.cpp index eb7aa69b55..efaed6f15f 100644 --- a/src/native/windows/juce_win32_WebBrowserComponent.cpp +++ b/src/native/windows/juce_win32_WebBrowserComponent.cpp @@ -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); } }