diff --git a/juce.h b/juce.h index cbf0fd9f32..623daa51c5 100644 --- a/juce.h +++ b/juce.h @@ -80,7 +80,7 @@ END_JUCE_NAMESPACE of 3rd party header files, you may need to use the juce_WithoutMacros.h file - see the comments in that file for more information. */ - #if JUCE_MAC && ! JUCE_DONT_DEFINE_MACROS + #if (JUCE_MAC || JUCE_IPHONE) && ! JUCE_DONT_DEFINE_MACROS #define Component JUCE_NAMESPACE::Component #define MemoryBlock JUCE_NAMESPACE::MemoryBlock #define Point JUCE_NAMESPACE::Point diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 1c6c41f817..f14ec7c458 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -3459,12 +3459,9 @@ XmlElement* PropertySet::createXml (const String& nodeName) const throw() for (int i = 0; i < properties.getAllKeys().size(); ++i) { - XmlElement* const e = new XmlElement (T("VALUE")); - + XmlElement* const e = xml->createNewChildElement ("VALUE"); e->setAttribute (T("name"), properties.getAllKeys()[i]); e->setAttribute (T("val"), properties.getAllValues()[i]); - - xml->addChildElement (e); } return xml; @@ -10414,12 +10411,6 @@ void juce_initialiseStrings() decimalPoint = String::fromUTF8 ((const uint8*) localeconv()->decimal_point) [0]; } -void String::deleteInternal() throw() -{ - if (Atomic::decrementAndReturn (text->refCount) == 0) - juce_free (text); -} - void String::createInternal (const int numChars) throw() { jassert (numChars > 0); @@ -10943,32 +10934,7 @@ int64 String::hashCode64() const throw() const String& String::operator= (const tchar* const otherText) throw() { - if (otherText != 0 && *otherText != 0) - { - const int otherLen = CharacterFunctions::length (otherText); - - if (otherLen > 0) - { - // avoid resizing the memory block if the string is - // shrinking.. - if (text->refCount > 1 - || otherLen > text->allocatedNumChars - || otherLen <= (text->allocatedNumChars >> 1)) - { - deleteInternal(); - createInternal (otherLen); - } - - memcpy (text->text, otherText, (otherLen + 1) * sizeof (tchar)); - - return *this; - } - } - - deleteInternal(); - text = &emptyString; - emptyString.refCount = safeEmptyStringRefCount; - + operator= (String (otherText)); return *this; } @@ -10976,12 +10942,14 @@ const String& String::operator= (const String& other) throw() { if (this != &other) { - Atomic::increment (other.text->refCount); + InternalRefCountedStringHolder* newText = other.text; + Atomic::increment (newText->refCount); - if (Atomic::decrementAndReturn (text->refCount) == 0) - juce_free (text); + InternalRefCountedStringHolder* oldText + = (InternalRefCountedStringHolder*) Atomic::swapPointers ((void* volatile*) &text, newText); - text = other.text; + if (Atomic::decrementAndReturn (oldText->refCount) == 0) + juce_free (oldText); } return *this; @@ -11625,47 +11593,36 @@ const String String::formatted (const tchar* const pf, ...) throw() void String::vprintf (const tchar* const pf, va_list& args) throw() { - tchar stackBuf [256]; - unsigned int bufSize = 256; - tchar* buf = stackBuf; - - deleteInternal(); + int bufferSize = 256; + String result (bufferSize, 0); do { #if JUCE_LINUX && JUCE_64BIT va_list tempArgs; va_copy (tempArgs, args); - const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, tempArgs); + const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, tempArgs); va_end (tempArgs); #else - const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, args); + const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, args); #endif if (num > 0) { - createInternal (num); - memcpy (text->text, buf, (num + 1) * sizeof (tchar)); + *this = result; break; } else if (num == 0) { - text = &emptyString; - emptyString.refCount = safeEmptyStringRefCount; + *this = String::empty; break; } - if (buf != stackBuf) - juce_free (buf); - - bufSize += 256; - buf = (tchar*) juce_malloc (bufSize * sizeof (tchar)); + bufferSize += 256; + result.preallocateStorage (bufferSize); } - while (bufSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly - // returns -1 because of an error rather than because it needs more space. - - if (buf != stackBuf) - juce_free (buf); + while (bufferSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly + // returns -1 because of an error rather than because it needs more space. } const String String::repeatedString (const tchar* const stringToRepeat, @@ -18196,7 +18153,7 @@ bool PropertiesFile::save() for (int i = 0; i < getAllProperties().size(); ++i) { - XmlElement* const e = new XmlElement (propertyTagName); + XmlElement* const e = doc.createNewChildElement (propertyTagName); e->setAttribute (T("name"), getAllProperties().getAllKeys() [i]); // if the value seems to contain xml, store it as such.. @@ -18207,8 +18164,6 @@ bool PropertiesFile::save() e->addChildElement (childElement); else e->setAttribute (T("val"), getAllProperties().getAllValues() [i]); - - doc.addChildElement (e); } return doc.writeToFile (file, String::empty); @@ -24556,32 +24511,30 @@ void AudioDeviceManager::restartLastAudioDevice() void AudioDeviceManager::updateXml() { - lastExplicitSettings = new XmlElement (T("DEVICESETUP")); + lastExplicitSettings = new XmlElement ("DEVICESETUP"); - lastExplicitSettings->setAttribute (T("deviceType"), currentDeviceType); - lastExplicitSettings->setAttribute (T("audioOutputDeviceName"), currentSetup.outputDeviceName); - lastExplicitSettings->setAttribute (T("audioInputDeviceName"), currentSetup.inputDeviceName); + lastExplicitSettings->setAttribute ("deviceType", currentDeviceType); + lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName); + lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName); if (currentAudioDevice != 0) { - lastExplicitSettings->setAttribute (T("audioDeviceRate"), currentAudioDevice->getCurrentSampleRate()); + lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate()); if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples()) - lastExplicitSettings->setAttribute (T("audioDeviceBufferSize"), currentAudioDevice->getCurrentBufferSizeSamples()); + lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples()); if (! currentSetup.useDefaultInputChannels) - lastExplicitSettings->setAttribute (T("audioDeviceInChans"), currentSetup.inputChannels.toString (2)); + lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2)); if (! currentSetup.useDefaultOutputChannels) - lastExplicitSettings->setAttribute (T("audioDeviceOutChans"), currentSetup.outputChannels.toString (2)); + lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2)); } for (int i = 0; i < enabledMidiInputs.size(); ++i) { - XmlElement* const m = new XmlElement (T("MIDIINPUT")); - m->setAttribute (T("name"), enabledMidiInputs[i]->getName()); - - lastExplicitSettings->addChildElement (m); + XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT"); + m->setAttribute ("name", enabledMidiInputs[i]->getName()); } if (midiInsFromXml.size() > 0) @@ -24594,16 +24547,14 @@ void AudioDeviceManager::updateXml() { if (! availableMidiDevices.contains (midiInsFromXml[i], true)) { - XmlElement* const m = new XmlElement (T("MIDIINPUT")); - m->setAttribute (T("name"), midiInsFromXml[i]); - - lastExplicitSettings->addChildElement (m); + XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT"); + m->setAttribute ("name", midiInsFromXml[i]); } } } if (defaultMidiOutputName.isNotEmpty()) - lastExplicitSettings->setAttribute (T("defaultMidiOutput"), defaultMidiOutputName); + lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputName); } void AudioDeviceManager::addAudioCallback (AudioIODeviceCallback* newCallback) @@ -50375,21 +50326,19 @@ const String TableHeaderComponent::toString() const { String s; - XmlElement doc (T("TABLELAYOUT")); + XmlElement doc ("TABLELAYOUT"); - doc.setAttribute (T("sortedCol"), getSortColumnId()); - doc.setAttribute (T("sortForwards"), isSortedForwards()); + doc.setAttribute ("sortedCol", getSortColumnId()); + doc.setAttribute ("sortForwards", isSortedForwards()); for (int i = 0; i < columns.size(); ++i) { const ColumnInfo* const ci = columns.getUnchecked (i); - XmlElement* const e = new XmlElement (T("COLUMN")); - doc.addChildElement (e); - - e->setAttribute (T("id"), ci->id); - e->setAttribute (T("visible"), ci->isVisible()); - e->setAttribute (T("width"), ci->width); + XmlElement* const e = doc.createNewChildElement ("COLUMN"); + e->setAttribute ("id", ci->id); + e->setAttribute ("visible", ci->isVisible()); + e->setAttribute ("width", ci->width); } return doc.createDocument (String::empty, true, false); @@ -50402,19 +50351,19 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion) int index = 0; - if (storedXml != 0 && storedXml->hasTagName (T("TABLELAYOUT"))) + if (storedXml != 0 && storedXml->hasTagName ("TABLELAYOUT")) { forEachXmlChildElement (*storedXml, col) { - const int tabId = col->getIntAttribute (T("id")); + const int tabId = col->getIntAttribute ("id"); ColumnInfo* const ci = getInfoForId (tabId); if (ci != 0) { columns.move (columns.indexOf (ci), index); - ci->width = col->getIntAttribute (T("width")); - setColumnVisible (tabId, col->getBoolAttribute (T("visible"))); + ci->width = col->getIntAttribute ("width"); + setColumnVisible (tabId, col->getBoolAttribute ("visible")); } ++index; @@ -50423,8 +50372,8 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion) columnsResized = true; sendColumnsChanged(); - setSortColumnId (storedXml->getIntAttribute (T("sortedCol")), - storedXml->getBoolAttribute (T("sortForwards"), true)); + setSortColumnId (storedXml->getIntAttribute ("sortedCol"), + storedXml->getBoolAttribute ("sortForwards", true)); } } @@ -60336,13 +60285,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault if (defaultSet == 0 || ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j))) { - XmlElement* const map = new XmlElement (T("MAPPING")); + XmlElement* const map = doc->createNewChildElement ("MAPPING"); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); - - doc->addChildElement (map); } } } @@ -60357,13 +60304,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault { if (! containsMapping (cm->commandID, cm->keypresses.getReference (j))) { - XmlElement* const map = new XmlElement (T("UNMAPPING")); + XmlElement* const map = doc->createNewChildElement ("UNMAPPING"); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); - - doc->addChildElement (map); } } } @@ -71423,10 +71368,9 @@ XmlElement* PropertyPanel::getOpennessState() const { if (sections[i].isNotEmpty()) { - XmlElement* const e = new XmlElement (T("SECTION")); - e->setAttribute (T("name"), sections[i]); - e->setAttribute (T("open"), isSectionOpen (i) ? 1 : 0); - xml->addChildElement (e); + XmlElement* const e = xml->createNewChildElement ("SECTION"); + e->setAttribute ("name", sections[i]); + e->setAttribute ("open", isSectionOpen (i) ? 1 : 0); } } @@ -212236,6 +212180,8 @@ int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldV { return InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } #endif +void* Atomic::swapPointers (void* volatile* value1, void* volatile value2) { return InterlockedExchangePointer (value1, value2); } + CriticalSection::CriticalSection() throw() { // (just to check the MS haven't changed this structure and broken things...) @@ -213949,7 +213895,7 @@ static HKEY findKeyForPath (String name, if (createForWriting) { - if (RegCreateKeyEx (rootKey, name, 0, L"", REG_OPTION_NON_VOLATILE, + if (RegCreateKeyEx (rootKey, name, 0, 0, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS) return key; } @@ -226510,7 +226456,7 @@ static void wasapi_copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX class WASAPIDeviceBase { public: - WASAPIDeviceBase (const ComSmartPtr & device_) + WASAPIDeviceBase (const ComSmartPtr & device_, const bool useExclusiveMode_) : device (device_), sampleRate (0), numChannels (0), @@ -226518,7 +226464,8 @@ public: defaultSampleRate (0), minBufferSize (0), defaultBufferSize (0), - latencySamples (0) + latencySamples (0), + useExclusiveMode (useExclusiveMode_) { clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); @@ -226555,7 +226502,8 @@ public: format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]); - if (SUCCEEDED (tempClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, 0))) + if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + (WAVEFORMATEX*) &format, 0))) if (! rates.contains (ratesToTest[i])) rates.addSorted (comparator, ratesToTest[i]); } @@ -226616,6 +226564,7 @@ public: double sampleRate, defaultSampleRate; int numChannels, actualNumChannels; int minBufferSize, defaultBufferSize, latencySamples; + const bool useExclusiveMode; Array rates; HANDLE clientEvent; BitArray channels; @@ -226673,7 +226622,8 @@ private: WAVEFORMATEXTENSIBLE* nearestFormat = 0; - HRESULT hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, (WAVEFORMATEX**) &nearestFormat); + HRESULT hr = client->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + (WAVEFORMATEX*) &format, useExclusiveMode ? 0 : (WAVEFORMATEX**) &nearestFormat); logFailure (hr); if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) @@ -226684,10 +226634,15 @@ private: CoTaskMemFree (nearestFormat); + REFERENCE_TIME defaultPeriod = 0, minPeriod = 0; + if (useExclusiveMode) + OK (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); + GUID session; if (hr == S_OK - && OK (client->Initialize (AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - 0, 0, (WAVEFORMATEX*) &format, &session))) + && OK (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) { actualNumChannels = format.Format.nChannels; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; @@ -226706,8 +226661,8 @@ private: class WASAPIInputDevice : public WASAPIDeviceBase { public: - WASAPIInputDevice (const ComSmartPtr & device_) - : WASAPIDeviceBase (device_), + WASAPIInputDevice (const ComSmartPtr & device_, const bool useExclusiveMode_) + : WASAPIDeviceBase (device_, useExclusiveMode_), reservoir (1, 1) { } @@ -226851,8 +226806,8 @@ public: class WASAPIOutputDevice : public WASAPIDeviceBase { public: - WASAPIOutputDevice (const ComSmartPtr & device_) - : WASAPIDeviceBase (device_) + WASAPIOutputDevice (const ComSmartPtr & device_, const bool useExclusiveMode_) + : WASAPIDeviceBase (device_, useExclusiveMode_) { } @@ -226886,7 +226841,8 @@ public: if (! OK (client->GetCurrentPadding (&padding))) return; - const int samplesToDo = jmin ((int) (actualBufferSize - padding), bufferSize); + int samplesToDo = useExclusiveMode ? bufferSize + : jmin ((int) (actualBufferSize - padding), bufferSize); if (samplesToDo <= 0) { @@ -226944,7 +226900,8 @@ class WASAPIAudioIODevice : public AudioIODevice, public: WASAPIAudioIODevice (const String& deviceName, const String& outputDeviceId_, - const String& inputDeviceId_) + const String& inputDeviceId_, + const bool useExclusiveMode_) : AudioIODevice (deviceName, "Windows Audio"), Thread ("Juce WASAPI"), isOpen_ (false), @@ -226953,6 +226910,7 @@ public: outputDeviceId (outputDeviceId_), inputDevice (0), inputDeviceId (inputDeviceId_), + useExclusiveMode (useExclusiveMode_), currentBufferSizeSamples (0), currentSampleRate (0), callback (0) @@ -227205,8 +227163,8 @@ public: while (! threadShouldExit()) { - const DWORD result = WaitForMultipleObjects (numEvents, events, true, 1000); - + const DWORD result = useExclusiveMode ? WaitForSingleObject (inputDevice->clientEvent, 1000) + : WaitForMultipleObjects (numEvents, events, true, 1000); if (result == WAIT_TIMEOUT) continue; @@ -227238,6 +227196,9 @@ public: } } + if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT) + continue; + if (outputDevice != 0) outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this); } @@ -227252,6 +227213,7 @@ private: // Device stats... WASAPIInputDevice* inputDevice; WASAPIOutputDevice* outputDevice; + const bool useExclusiveMode; double defaultSampleRate; int minBufferSize, defaultBufferSize; int latencyIn, latencyOut; @@ -227293,9 +227255,9 @@ private: const EDataFlow flow = wasapi_getDataFlow (device); if (deviceId == inputDeviceId && flow == eCapture) - inputDevice = new WASAPIInputDevice (device); + inputDevice = new WASAPIInputDevice (device, useExclusiveMode); else if (deviceId == outputDeviceId && flow == eRender) - outputDevice = new WASAPIOutputDevice (device); + outputDevice = new WASAPIOutputDevice (device, useExclusiveMode); } return (outputDeviceId.isEmpty() || (outputDevice != 0 && outputDevice->isOk())) @@ -227421,6 +227383,7 @@ public: { jassert (hasScanned); // need to call scanForDevices() before doing this + const bool useExclusiveMode = false; WASAPIAudioIODevice* d = 0; const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); @@ -227431,7 +227394,8 @@ public: d = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName : inputDeviceName, outputDeviceIds [outputIndex], - inputDeviceIds [inputIndex]); + inputDeviceIds [inputIndex], + useExclusiveMode); if (! d->initialise()) deleteAndZero (d); @@ -239295,7 +239259,7 @@ bool Desktop::isScreenSaverEnabled() throw() return ! [[UIApplication sharedApplication] isIdleTimerDisabled]; } -void juce_updateMultiMonitorInfo (Array & monitorCoords, const bool clipToWorkArea) +void juce_updateMultiMonitorInfo (Array >& monitorCoords, const bool clipToWorkArea) { const ScopedAutoReleasePool pool; monitorCoords.clear(); @@ -239611,7 +239575,7 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() #define SUPPORT_10_4_FONTS 1 #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0) - #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) || JUCE_PPC #define SUPPORT_ONLY_10_4_FONTS 1 #endif @@ -241952,13 +241916,13 @@ using namespace JUCE_NAMESPACE; - (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename { - const String fname (nsStringToJuce (filename)); + const File f (nsStringToJuce (filename)); for (int i = filters->size(); --i >= 0;) - if (fname.matchesWildcard ((*filters)[i], true)) + if (f.getFileName().matchesWildcard ((*filters)[i], true)) return true; - return File (fname).isDirectory(); + return f.isDirectory(); } @end @@ -244046,7 +244010,7 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) #define SUPPORT_10_4_FONTS 1 #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0) - #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) || JUCE_PPC #define SUPPORT_ONLY_10_4_FONTS 1 #endif @@ -248173,13 +248137,13 @@ using namespace JUCE_NAMESPACE; - (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename { - const String fname (nsStringToJuce (filename)); + const File f (nsStringToJuce (filename)); for (int i = filters->size(); --i >= 0;) - if (fname.matchesWildcard ((*filters)[i], true)) + if (f.getFileName().matchesWildcard ((*filters)[i], true)) return true; - return File (fname).isDirectory(); + return f.isDirectory(); } @end diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 34ad1e3b4c..618956619e 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -1424,7 +1424,6 @@ private: // internal constructor that preallocates a certain amount of memory String (const int numChars, const int dummyVariable) throw(); - void deleteInternal() throw(); void createInternal (const int numChars) throw(); void createInternal (const tchar* const text, const tchar* const textEnd) throw(); void appendInternal (const tchar* const text, const int numExtraChars) throw(); @@ -3144,6 +3143,8 @@ public: static int32 decrementAndReturn (int32& variable); static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); + + static void* swapPointers (void* volatile* value1, void* value2); }; #if (JUCE_MAC || JUCE_IPHONE) // Mac and iPhone... @@ -3154,6 +3155,12 @@ inline void Atomic::decrement (int32& variable) { OSAtomicDecrement32 ((int32_ inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); } inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (int32_t*) &destination); } +inline void* Atomic::swapPointers (void* volatile* value1, void* volatile value2) +{ + void* currentVal = *value1; + while (! OSAtomicCompareAndSwapPtr (currentVal, value2, value1)) { currentVal = *value1; } + return currentVal; +} #elif JUCE_LINUX // Linux... @@ -3163,6 +3170,12 @@ inline void Atomic::decrement (int32& variable) { __sync_add_and_fetch (&varia 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::swapPointers (void* volatile* value1, void* volatile value2) +{ + void* currentVal = *value1; + while (! __sync_bool_compare_and_swap (&value1, currentVal, value2)) { currentVal = *value1; } + return currentVal; +} #elif JUCE_USE_INTRINSICS // Windows... @@ -6692,6 +6705,22 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI(); void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI(); +class ScopedJuceInitialiser_NonGUI +{ +public: + ScopedJuceInitialiser_NonGUI() { initialiseJuce_NonGUI(); } + + ~ScopedJuceInitialiser_NonGUI() { shutdownJuce_NonGUI(); } +}; + +class ScopedJuceInitialiser_GUI +{ +public: + ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); } + + ~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); } +}; + #endif // __JUCE_INITIALISATION_JUCEHEADER__ /*** End of inlined file: juce_Initialisation.h ***/ @@ -28181,7 +28210,7 @@ END_JUCE_NAMESPACE // defining DONT_SET_USING_JUCE_NAMESPACE, in case there are conflicts. using namespace JUCE_NAMESPACE; - #if JUCE_MAC && ! JUCE_DONT_DEFINE_MACROS + #if (JUCE_MAC || JUCE_IPHONE) && ! JUCE_DONT_DEFINE_MACROS #define Component JUCE_NAMESPACE::Component #define MemoryBlock JUCE_NAMESPACE::MemoryBlock #define Point JUCE_NAMESPACE::Point diff --git a/src/audio/devices/juce_AudioDeviceManager.cpp b/src/audio/devices/juce_AudioDeviceManager.cpp index 5b3b4c85f6..09c1597b34 100644 --- a/src/audio/devices/juce_AudioDeviceManager.cpp +++ b/src/audio/devices/juce_AudioDeviceManager.cpp @@ -548,32 +548,30 @@ void AudioDeviceManager::restartLastAudioDevice() void AudioDeviceManager::updateXml() { - lastExplicitSettings = new XmlElement (T("DEVICESETUP")); + lastExplicitSettings = new XmlElement ("DEVICESETUP"); - lastExplicitSettings->setAttribute (T("deviceType"), currentDeviceType); - lastExplicitSettings->setAttribute (T("audioOutputDeviceName"), currentSetup.outputDeviceName); - lastExplicitSettings->setAttribute (T("audioInputDeviceName"), currentSetup.inputDeviceName); + lastExplicitSettings->setAttribute ("deviceType", currentDeviceType); + lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName); + lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName); if (currentAudioDevice != 0) { - lastExplicitSettings->setAttribute (T("audioDeviceRate"), currentAudioDevice->getCurrentSampleRate()); + lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate()); if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples()) - lastExplicitSettings->setAttribute (T("audioDeviceBufferSize"), currentAudioDevice->getCurrentBufferSizeSamples()); + lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples()); if (! currentSetup.useDefaultInputChannels) - lastExplicitSettings->setAttribute (T("audioDeviceInChans"), currentSetup.inputChannels.toString (2)); + lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2)); if (! currentSetup.useDefaultOutputChannels) - lastExplicitSettings->setAttribute (T("audioDeviceOutChans"), currentSetup.outputChannels.toString (2)); + lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2)); } for (int i = 0; i < enabledMidiInputs.size(); ++i) { - XmlElement* const m = new XmlElement (T("MIDIINPUT")); - m->setAttribute (T("name"), enabledMidiInputs[i]->getName()); - - lastExplicitSettings->addChildElement (m); + XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT"); + m->setAttribute ("name", enabledMidiInputs[i]->getName()); } if (midiInsFromXml.size() > 0) @@ -586,16 +584,14 @@ void AudioDeviceManager::updateXml() { if (! availableMidiDevices.contains (midiInsFromXml[i], true)) { - XmlElement* const m = new XmlElement (T("MIDIINPUT")); - m->setAttribute (T("name"), midiInsFromXml[i]); - - lastExplicitSettings->addChildElement (m); + XmlElement* const m = lastExplicitSettings->createNewChildElement ("MIDIINPUT"); + m->setAttribute ("name", midiInsFromXml[i]); } } } if (defaultMidiOutputName.isNotEmpty()) - lastExplicitSettings->setAttribute (T("defaultMidiOutput"), defaultMidiOutputName); + lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputName); } //============================================================================== diff --git a/src/containers/juce_PropertySet.cpp b/src/containers/juce_PropertySet.cpp index c84bb29699..ee2ae6db72 100644 --- a/src/containers/juce_PropertySet.cpp +++ b/src/containers/juce_PropertySet.cpp @@ -212,12 +212,9 @@ XmlElement* PropertySet::createXml (const String& nodeName) const throw() for (int i = 0; i < properties.getAllKeys().size(); ++i) { - XmlElement* const e = new XmlElement (T("VALUE")); - + XmlElement* const e = xml->createNewChildElement ("VALUE"); e->setAttribute (T("name"), properties.getAllKeys()[i]); e->setAttribute (T("val"), properties.getAllValues()[i]); - - xml->addChildElement (e); } return xml; diff --git a/src/core/juce_Atomic.h b/src/core/juce_Atomic.h index 12a61fd9be..9480943933 100644 --- a/src/core/juce_Atomic.h +++ b/src/core/juce_Atomic.h @@ -50,6 +50,9 @@ public: @returns the new value of destination */ static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); + + /** This atomically sets *value1 to be value2, and returns the previous value of *value1. */ + static void* swapPointers (void* volatile* value1, void* value2); }; @@ -62,6 +65,12 @@ inline void Atomic::decrement (int32& variable) { OSAtomicDecrem inline int32 Atomic::decrementAndReturn (int32& variable) { return OSAtomicDecrement32 ((int32_t*) &variable); } inline int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldValue) { return OSAtomicCompareAndSwap32Barrier (oldValue, newValue, (int32_t*) &destination); } +inline void* Atomic::swapPointers (void* volatile* value1, void* volatile value2) +{ + void* currentVal = *value1; + while (! OSAtomicCompareAndSwapPtr (currentVal, value2, value1)) { currentVal = *value1; } + return currentVal; +} #elif JUCE_LINUX // Linux... @@ -72,6 +81,12 @@ inline void Atomic::decrement (int32& variable) { __sync_add_and 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::swapPointers (void* volatile* value1, void* volatile value2) +{ + void* currentVal = *value1; + while (! __sync_bool_compare_and_swap (&value1, currentVal, value2)) { currentVal = *value1; } + return currentVal; +} //============================================================================== #elif JUCE_USE_INTRINSICS // Windows... diff --git a/src/core/juce_Initialisation.h b/src/core/juce_Initialisation.h index b4e6715c0c..1e68bcd1cc 100644 --- a/src/core/juce_Initialisation.h +++ b/src/core/juce_Initialisation.h @@ -76,5 +76,55 @@ void JUCE_PUBLIC_FUNCTION initialiseJuce_NonGUI(); void JUCE_PUBLIC_FUNCTION shutdownJuce_NonGUI(); +//============================================================================== +/** A utility object that helps you initialise and shutdown Juce correctly + using an RAII pattern. + + When an instance of this class is created, it calls initialiseJuce_NonGUI(), + and when it's deleted, it calls shutdownJuce_NonGUI(), which lets you easily + make sure that these functions are matched correctly. + + This class is particularly handy to use at the beginning of a console app's + main() function, because it'll take care of shutting down whenever you return + from the main() call. + + @see ScopedJuceInitialiser_GUI +*/ +class ScopedJuceInitialiser_NonGUI +{ +public: + /** The constructor simply calls initialiseJuce_NonGUI(). */ + ScopedJuceInitialiser_NonGUI() { initialiseJuce_NonGUI(); } + + /** The destructor simply calls shutdownJuce_NonGUI(). */ + ~ScopedJuceInitialiser_NonGUI() { shutdownJuce_NonGUI(); } +}; + + +//============================================================================== +/** A utility object that helps you initialise and shutdown Juce correctly + using an RAII pattern. + + When an instance of this class is created, it calls initialiseJuce_GUI(), + and when it's deleted, it calls shutdownJuce_GUI(), which lets you easily + make sure that these functions are matched correctly. + + This class is particularly handy to use at the beginning of a console app's + main() function, because it'll take care of shutting down whenever you return + from the main() call. + + @see ScopedJuceInitialiser_NonGUI +*/ +class ScopedJuceInitialiser_GUI +{ +public: + /** The constructor simply calls initialiseJuce_GUI(). */ + ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); } + + /** The destructor simply calls shutdownJuce_GUI(). */ + ~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); } +}; + + #endif // __JUCE_INITIALISATION_JUCEHEADER__ diff --git a/src/gui/components/controls/juce_TableHeaderComponent.cpp b/src/gui/components/controls/juce_TableHeaderComponent.cpp index f463b62bbc..6de1b91bfa 100644 --- a/src/gui/components/controls/juce_TableHeaderComponent.cpp +++ b/src/gui/components/controls/juce_TableHeaderComponent.cpp @@ -439,21 +439,19 @@ const String TableHeaderComponent::toString() const { String s; - XmlElement doc (T("TABLELAYOUT")); + XmlElement doc ("TABLELAYOUT"); - doc.setAttribute (T("sortedCol"), getSortColumnId()); - doc.setAttribute (T("sortForwards"), isSortedForwards()); + doc.setAttribute ("sortedCol", getSortColumnId()); + doc.setAttribute ("sortForwards", isSortedForwards()); for (int i = 0; i < columns.size(); ++i) { const ColumnInfo* const ci = columns.getUnchecked (i); - XmlElement* const e = new XmlElement (T("COLUMN")); - doc.addChildElement (e); - - e->setAttribute (T("id"), ci->id); - e->setAttribute (T("visible"), ci->isVisible()); - e->setAttribute (T("width"), ci->width); + XmlElement* const e = doc.createNewChildElement ("COLUMN"); + e->setAttribute ("id", ci->id); + e->setAttribute ("visible", ci->isVisible()); + e->setAttribute ("width", ci->width); } return doc.createDocument (String::empty, true, false); @@ -466,19 +464,19 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion) int index = 0; - if (storedXml != 0 && storedXml->hasTagName (T("TABLELAYOUT"))) + if (storedXml != 0 && storedXml->hasTagName ("TABLELAYOUT")) { forEachXmlChildElement (*storedXml, col) { - const int tabId = col->getIntAttribute (T("id")); + const int tabId = col->getIntAttribute ("id"); ColumnInfo* const ci = getInfoForId (tabId); if (ci != 0) { columns.move (columns.indexOf (ci), index); - ci->width = col->getIntAttribute (T("width")); - setColumnVisible (tabId, col->getBoolAttribute (T("visible"))); + ci->width = col->getIntAttribute ("width"); + setColumnVisible (tabId, col->getBoolAttribute ("visible")); } ++index; @@ -487,8 +485,8 @@ void TableHeaderComponent::restoreFromString (const String& storedVersion) columnsResized = true; sendColumnsChanged(); - setSortColumnId (storedXml->getIntAttribute (T("sortedCol")), - storedXml->getBoolAttribute (T("sortForwards"), true)); + setSortColumnId (storedXml->getIntAttribute ("sortedCol"), + storedXml->getBoolAttribute ("sortForwards", true)); } } diff --git a/src/gui/components/keyboard/juce_KeyPressMappingSet.cpp b/src/gui/components/keyboard/juce_KeyPressMappingSet.cpp index ecc0f6c1f9..e591439a31 100644 --- a/src/gui/components/keyboard/juce_KeyPressMappingSet.cpp +++ b/src/gui/components/keyboard/juce_KeyPressMappingSet.cpp @@ -298,13 +298,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault if (defaultSet == 0 || ! defaultSet->containsMapping (cm->commandID, cm->keypresses.getReference (j))) { - XmlElement* const map = new XmlElement (T("MAPPING")); + XmlElement* const map = doc->createNewChildElement ("MAPPING"); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); - - doc->addChildElement (map); } } } @@ -319,13 +317,11 @@ XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefault { if (! containsMapping (cm->commandID, cm->keypresses.getReference (j))) { - XmlElement* const map = new XmlElement (T("UNMAPPING")); + XmlElement* const map = doc->createNewChildElement ("UNMAPPING"); map->setAttribute (T("commandId"), String::toHexString ((int) cm->commandID)); map->setAttribute (T("description"), commandManager->getDescriptionOfCommand (cm->commandID)); map->setAttribute (T("key"), cm->keypresses.getReference (j).getTextDescription()); - - doc->addChildElement (map); } } } diff --git a/src/gui/components/properties/juce_PropertyPanel.cpp b/src/gui/components/properties/juce_PropertyPanel.cpp index d1d4b5ea70..7934679c24 100644 --- a/src/gui/components/properties/juce_PropertyPanel.cpp +++ b/src/gui/components/properties/juce_PropertyPanel.cpp @@ -395,10 +395,9 @@ XmlElement* PropertyPanel::getOpennessState() const { if (sections[i].isNotEmpty()) { - XmlElement* const e = new XmlElement (T("SECTION")); - e->setAttribute (T("name"), sections[i]); - e->setAttribute (T("open"), isSectionOpen (i) ? 1 : 0); - xml->addChildElement (e); + XmlElement* const e = xml->createNewChildElement ("SECTION"); + e->setAttribute ("name", sections[i]); + e->setAttribute ("open", isSectionOpen (i) ? 1 : 0); } } diff --git a/src/native/mac/juce_iphone_MiscUtilities.mm b/src/native/mac/juce_iphone_MiscUtilities.mm index 090d754cb2..5953095dca 100644 --- a/src/native/mac/juce_iphone_MiscUtilities.mm +++ b/src/native/mac/juce_iphone_MiscUtilities.mm @@ -181,7 +181,7 @@ bool Desktop::isScreenSaverEnabled() throw() //============================================================================== -void juce_updateMultiMonitorInfo (Array & monitorCoords, const bool clipToWorkArea) +void juce_updateMultiMonitorInfo (Array >& monitorCoords, const bool clipToWorkArea) { const ScopedAutoReleasePool pool; monitorCoords.clear(); diff --git a/src/native/mac/juce_mac_FileChooser.mm b/src/native/mac/juce_mac_FileChooser.mm index 14210c0343..120f6f45c6 100644 --- a/src/native/mac/juce_mac_FileChooser.mm +++ b/src/native/mac/juce_mac_FileChooser.mm @@ -66,13 +66,13 @@ using namespace JUCE_NAMESPACE; - (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename { - const String fname (nsStringToJuce (filename)); + const File f (nsStringToJuce (filename)); for (int i = filters->size(); --i >= 0;) - if (fname.matchesWildcard ((*filters)[i], true)) + if (f.getFileName().matchesWildcard ((*filters)[i], true)) return true; - return File (fname).isDirectory(); + return f.isDirectory(); } @end diff --git a/src/native/mac/juce_mac_Fonts.mm b/src/native/mac/juce_mac_Fonts.mm index ef6dc52270..0c85ea0c0d 100644 --- a/src/native/mac/juce_mac_Fonts.mm +++ b/src/native/mac/juce_mac_Fonts.mm @@ -31,7 +31,7 @@ #define SUPPORT_10_4_FONTS 1 #define NEW_CGFONT_FUNCTIONS_UNAVAILABLE (CGFontCreateWithFontName == 0) - #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 + #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) || JUCE_PPC #define SUPPORT_ONLY_10_4_FONTS 1 #endif diff --git a/src/native/windows/juce_win32_PlatformUtils.cpp b/src/native/windows/juce_win32_PlatformUtils.cpp index 3765a19576..6ed854afc3 100644 --- a/src/native/windows/juce_win32_PlatformUtils.cpp +++ b/src/native/windows/juce_win32_PlatformUtils.cpp @@ -55,7 +55,7 @@ static HKEY findKeyForPath (String name, if (createForWriting) { - if (RegCreateKeyEx (rootKey, name, 0, L"", REG_OPTION_NON_VOLATILE, + if (RegCreateKeyEx (rootKey, name, 0, 0, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS) return key; } diff --git a/src/native/windows/juce_win32_Threads.cpp b/src/native/windows/juce_win32_Threads.cpp index 9553ff40dd..97c9f31f46 100644 --- a/src/native/windows/juce_win32_Threads.cpp +++ b/src/native/windows/juce_win32_Threads.cpp @@ -43,6 +43,8 @@ int32 Atomic::compareAndExchange (int32& destination, int32 newValue, int32 oldV { return InterlockedCompareExchange (reinterpret_cast (&destination), newValue, oldValue); } #endif +void* Atomic::swapPointers (void* volatile* value1, void* volatile value2) { return InterlockedExchangePointer (value1, value2); } + //============================================================================== CriticalSection::CriticalSection() throw() { diff --git a/src/native/windows/juce_win32_WASAPI.cpp b/src/native/windows/juce_win32_WASAPI.cpp index c203606c4f..75ecd05f99 100644 --- a/src/native/windows/juce_win32_WASAPI.cpp +++ b/src/native/windows/juce_win32_WASAPI.cpp @@ -121,7 +121,7 @@ static void wasapi_copyWavFormat (WAVEFORMATEXTENSIBLE& dest, const WAVEFORMATEX class WASAPIDeviceBase { public: - WASAPIDeviceBase (const ComSmartPtr & device_) + WASAPIDeviceBase (const ComSmartPtr & device_, const bool useExclusiveMode_) : device (device_), sampleRate (0), numChannels (0), @@ -129,7 +129,8 @@ public: defaultSampleRate (0), minBufferSize (0), defaultBufferSize (0), - latencySamples (0) + latencySamples (0), + useExclusiveMode (useExclusiveMode_) { clientEvent = CreateEvent (0, false, false, _T("JuceWASAPI")); @@ -166,7 +167,8 @@ public: format.Format.nSamplesPerSec = roundDoubleToInt (ratesToTest[i]); - if (SUCCEEDED (tempClient->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, 0))) + if (SUCCEEDED (tempClient->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + (WAVEFORMATEX*) &format, 0))) if (! rates.contains (ratesToTest[i])) rates.addSorted (comparator, ratesToTest[i]); } @@ -227,6 +229,7 @@ public: double sampleRate, defaultSampleRate; int numChannels, actualNumChannels; int minBufferSize, defaultBufferSize, latencySamples; + const bool useExclusiveMode; Array rates; HANDLE clientEvent; BitArray channels; @@ -284,7 +287,8 @@ private: WAVEFORMATEXTENSIBLE* nearestFormat = 0; - HRESULT hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, (WAVEFORMATEX**) &nearestFormat); + HRESULT hr = client->IsFormatSupported (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + (WAVEFORMATEX*) &format, useExclusiveMode ? 0 : (WAVEFORMATEX**) &nearestFormat); logFailure (hr); if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec) @@ -295,10 +299,15 @@ private: CoTaskMemFree (nearestFormat); + REFERENCE_TIME defaultPeriod = 0, minPeriod = 0; + if (useExclusiveMode) + OK (client->GetDevicePeriod (&defaultPeriod, &minPeriod)); + GUID session; if (hr == S_OK - && OK (client->Initialize (AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - 0, 0, (WAVEFORMATEX*) &format, &session))) + && OK (client->Initialize (useExclusiveMode ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + defaultPeriod, defaultPeriod, (WAVEFORMATEX*) &format, &session))) { actualNumChannels = format.Format.nChannels; const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; @@ -318,8 +327,8 @@ private: class WASAPIInputDevice : public WASAPIDeviceBase { public: - WASAPIInputDevice (const ComSmartPtr & device_) - : WASAPIDeviceBase (device_), + WASAPIInputDevice (const ComSmartPtr & device_, const bool useExclusiveMode_) + : WASAPIDeviceBase (device_, useExclusiveMode_), reservoir (1, 1) { } @@ -464,8 +473,8 @@ public: class WASAPIOutputDevice : public WASAPIDeviceBase { public: - WASAPIOutputDevice (const ComSmartPtr & device_) - : WASAPIDeviceBase (device_) + WASAPIOutputDevice (const ComSmartPtr & device_, const bool useExclusiveMode_) + : WASAPIDeviceBase (device_, useExclusiveMode_) { } @@ -499,7 +508,8 @@ public: if (! OK (client->GetCurrentPadding (&padding))) return; - const int samplesToDo = jmin ((int) (actualBufferSize - padding), bufferSize); + int samplesToDo = useExclusiveMode ? bufferSize + : jmin ((int) (actualBufferSize - padding), bufferSize); if (samplesToDo <= 0) { @@ -558,7 +568,8 @@ class WASAPIAudioIODevice : public AudioIODevice, public: WASAPIAudioIODevice (const String& deviceName, const String& outputDeviceId_, - const String& inputDeviceId_) + const String& inputDeviceId_, + const bool useExclusiveMode_) : AudioIODevice (deviceName, "Windows Audio"), Thread ("Juce WASAPI"), isOpen_ (false), @@ -567,6 +578,7 @@ public: outputDeviceId (outputDeviceId_), inputDevice (0), inputDeviceId (inputDeviceId_), + useExclusiveMode (useExclusiveMode_), currentBufferSizeSamples (0), currentSampleRate (0), callback (0) @@ -820,8 +832,8 @@ public: while (! threadShouldExit()) { - const DWORD result = WaitForMultipleObjects (numEvents, events, true, 1000); - + const DWORD result = useExclusiveMode ? WaitForSingleObject (inputDevice->clientEvent, 1000) + : WaitForMultipleObjects (numEvents, events, true, 1000); if (result == WAIT_TIMEOUT) continue; @@ -853,6 +865,9 @@ public: } } + if (useExclusiveMode && WaitForSingleObject (outputDevice->clientEvent, 1000) == WAIT_TIMEOUT) + continue; + if (outputDevice != 0) outputDevice->copyBuffers ((const float**) outputBuffers, numOutputBuffers, bufferSize, *this); } @@ -869,6 +884,7 @@ private: // Device stats... WASAPIInputDevice* inputDevice; WASAPIOutputDevice* outputDevice; + const bool useExclusiveMode; double defaultSampleRate; int minBufferSize, defaultBufferSize; int latencyIn, latencyOut; @@ -911,9 +927,9 @@ private: const EDataFlow flow = wasapi_getDataFlow (device); if (deviceId == inputDeviceId && flow == eCapture) - inputDevice = new WASAPIInputDevice (device); + inputDevice = new WASAPIInputDevice (device, useExclusiveMode); else if (deviceId == outputDeviceId && flow == eRender) - outputDevice = new WASAPIOutputDevice (device); + outputDevice = new WASAPIOutputDevice (device, useExclusiveMode); } return (outputDeviceId.isEmpty() || (outputDevice != 0 && outputDevice->isOk())) @@ -1043,6 +1059,7 @@ public: { jassert (hasScanned); // need to call scanForDevices() before doing this + const bool useExclusiveMode = false; WASAPIAudioIODevice* d = 0; const int outputIndex = outputDeviceNames.indexOf (outputDeviceName); @@ -1053,7 +1070,8 @@ public: d = new WASAPIAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName : inputDeviceName, outputDeviceIds [outputIndex], - inputDeviceIds [inputIndex]); + inputDeviceIds [inputIndex], + useExclusiveMode); if (! d->initialise()) deleteAndZero (d); diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index d991812953..920c4d082d 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -56,12 +56,6 @@ void juce_initialiseStrings() } //============================================================================== -void String::deleteInternal() throw() -{ - if (Atomic::decrementAndReturn (text->refCount) == 0) - juce_free (text); -} - void String::createInternal (const int numChars) throw() { jassert (numChars > 0); @@ -592,32 +586,7 @@ int64 String::hashCode64() const throw() //============================================================================== const String& String::operator= (const tchar* const otherText) throw() { - if (otherText != 0 && *otherText != 0) - { - const int otherLen = CharacterFunctions::length (otherText); - - if (otherLen > 0) - { - // avoid resizing the memory block if the string is - // shrinking.. - if (text->refCount > 1 - || otherLen > text->allocatedNumChars - || otherLen <= (text->allocatedNumChars >> 1)) - { - deleteInternal(); - createInternal (otherLen); - } - - memcpy (text->text, otherText, (otherLen + 1) * sizeof (tchar)); - - return *this; - } - } - - deleteInternal(); - text = &emptyString; - emptyString.refCount = safeEmptyStringRefCount; - + operator= (String (otherText)); return *this; } @@ -625,12 +594,14 @@ const String& String::operator= (const String& other) throw() { if (this != &other) { - Atomic::increment (other.text->refCount); + InternalRefCountedStringHolder* newText = other.text; + Atomic::increment (newText->refCount); - if (Atomic::decrementAndReturn (text->refCount) == 0) - juce_free (text); + InternalRefCountedStringHolder* oldText + = (InternalRefCountedStringHolder*) Atomic::swapPointers ((void* volatile*) &text, newText); - text = other.text; + if (Atomic::decrementAndReturn (oldText->refCount) == 0) + juce_free (oldText); } return *this; @@ -1282,47 +1253,36 @@ const String String::formatted (const tchar* const pf, ...) throw() //============================================================================== void String::vprintf (const tchar* const pf, va_list& args) throw() { - tchar stackBuf [256]; - unsigned int bufSize = 256; - tchar* buf = stackBuf; - - deleteInternal(); + int bufferSize = 256; + String result (bufferSize, 0); do { #if JUCE_LINUX && JUCE_64BIT va_list tempArgs; va_copy (tempArgs, args); - const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, tempArgs); + const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, tempArgs); va_end (tempArgs); #else - const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, args); + const int num = CharacterFunctions::vprintf (result.text->text, bufferSize - 1, pf, args); #endif if (num > 0) { - createInternal (num); - memcpy (text->text, buf, (num + 1) * sizeof (tchar)); + *this = result; break; } else if (num == 0) { - text = &emptyString; - emptyString.refCount = safeEmptyStringRefCount; + *this = String::empty; break; } - if (buf != stackBuf) - juce_free (buf); - - bufSize += 256; - buf = (tchar*) juce_malloc (bufSize * sizeof (tchar)); + bufferSize += 256; + result.preallocateStorage (bufferSize); } - while (bufSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly - // returns -1 because of an error rather than because it needs more space. - - if (buf != stackBuf) - juce_free (buf); + while (bufferSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly + // returns -1 because of an error rather than because it needs more space. } //============================================================================== diff --git a/src/text/juce_String.h b/src/text/juce_String.h index 4940142bc1..ffbe87f2d3 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -1117,7 +1117,6 @@ private: // internal constructor that preallocates a certain amount of memory String (const int numChars, const int dummyVariable) throw(); - void deleteInternal() throw(); void createInternal (const int numChars) throw(); void createInternal (const tchar* const text, const tchar* const textEnd) throw(); void appendInternal (const tchar* const text, const int numExtraChars) throw(); diff --git a/src/utilities/juce_PropertiesFile.cpp b/src/utilities/juce_PropertiesFile.cpp index e1da8f3430..5853667836 100644 --- a/src/utilities/juce_PropertiesFile.cpp +++ b/src/utilities/juce_PropertiesFile.cpp @@ -164,7 +164,7 @@ bool PropertiesFile::save() for (int i = 0; i < getAllProperties().size(); ++i) { - XmlElement* const e = new XmlElement (propertyTagName); + XmlElement* const e = doc.createNewChildElement (propertyTagName); e->setAttribute (T("name"), getAllProperties().getAllKeys() [i]); // if the value seems to contain xml, store it as such.. @@ -175,8 +175,6 @@ bool PropertiesFile::save() e->addChildElement (childElement); else e->setAttribute (T("val"), getAllProperties().getAllValues() [i]); - - doc.addChildElement (e); } return doc.writeToFile (file, String::empty);