| @@ -1937,15 +1937,15 @@ bool juce_isHIViewCreatedByJuce (HIViewRef view) | |||
| && HIObjectIsOfClass ((HIObjectRef) view, juceHiViewClassNameCFString); | |||
| } | |||
| bool juce_isWindowCreatedByJuce (WindowRef window) | |||
| { | |||
| for (int i = ComponentPeer::getNumPeers(); --i >= 0;) | |||
| if (ComponentPeer::getPeer(i)->getNativeHandle() == window) | |||
| return true; | |||
| return false; | |||
| } | |||
| bool juce_isWindowCreatedByJuce (WindowRef window) | |||
| { | |||
| for (int i = ComponentPeer::getNumPeers(); --i >= 0;) | |||
| if (ComponentPeer::getPeer(i)->getNativeHandle() == window) | |||
| return true; | |||
| return false; | |||
| } | |||
| static void trackNextMouseEvent() | |||
| { | |||
| UInt32 mods; | |||
| @@ -8,11 +8,11 @@ Changelist for version 1.45 | |||
| - big new project in the "extras" folder - a basic audio plugin host! Currently it loads VSTs on PC/Mac, and lets you put them together in a filter graph, which it plays. Hosting functionality is very basic at the moment, but I'm laying down a good architecture to hopefully develop into a full cross-platform plugin host. | |||
| - audio plugins: I've simplified the processBlock() call in AudioFilterBase. It now just takes a single buffer for all input and output channels, and the accumulate parameter has gone. This will mean tweaking your plugin code, but will probably make it much less complicated. | |||
| - audio plugins: AudioFilterBase now requires a few extra methods to be implemented by your plugin: getInputChannelName, getOutputChannelName, isInputChannelStereoPair, isOutputChannelStereoPair. | |||
| - audio plugins: AudioFilterBase now requires a few extra methods to be implemented by your plugin: getInputChannelName, getOutputChannelName, isInputChannelStereoPair, isOutputChannelStereoPair, getLatencySamples (which supersedes the old macro for setting the latency) | |||
| - audio plugins: new method AudioFilterBase::updateHostDisplay() to tell the host that something about your plugin has changed and that it should refresh its display. | |||
| - audio plugins: new methods AudioFilterBase::beginParameterChangeGesture() and endParameterChangeGesture() let you tell the host when a parameter-change action starts and finishes. | |||
| - new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath. | |||
| - added a critical section option to ReferenceCountedArray | |||
| ============================================================================== | |||
| Changelist for version 1.44 | |||
| @@ -151,27 +151,28 @@ Compiling the juce demo RTAS on the PC: | |||
| - In Visual Studio, add all of this lot to your include path: | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\common | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\common\Platform | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\SADriver\Interfaces | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\DigiPublic\Interfaces | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\Fic\Interfaces\DAEClient | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\NewFileLibs\Cmn | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\NewFileLibs\DOA | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\AlturaSource\PPC_H | |||
| c:\yourdirectory\PT_711_SDK\AlturaPorts\AlturaSource\AppSupport | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\common | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\common\Platform | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\SADriver\Interfaces | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\DigiPublic\Interfaces | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\Fic\Interfaces\DAEClient | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\NewFileLibs\Cmn | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\NewFileLibs\DOA | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\AlturaSource\PPC_H | |||
| c:\yourdirectory\PT_73_SDK\AlturaPorts\AlturaSource\AppSupport | |||
| c:\yourdirectory\PT_73_SDK\AvidCode\AVX2sdk\AVX\avx2\avx2sdk\inc | |||
| - The Visual Studio juce_RTAS project contains a folder called "libs", with "debug" and | |||
| "release" subdirectories - these should contain links to the Digidesign lib files | |||
| @@ -180,6 +181,12 @@ Compiling the juce demo RTAS on the PC: | |||
| - Fingers crossed, this should now compile.. | |||
| - IMPORTANT NOTE! If you're using MSVC2005 to build your plugin, the users will need to | |||
| have the Microsoft VC8 Runtime installed on their machines, otherwise the DLL will | |||
| silently fail to load. You should probably add the runtime to your plugin's installer, | |||
| and you can get a copy of it here: | |||
| http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&DisplayLang=en | |||
| Creating a project for your own RTAS on the PC: | |||
| ================================================= | |||
| @@ -542,7 +542,7 @@ | |||
| Name="debug" | |||
| > | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\DAE.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\DAE.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Release|Win32" | |||
| @@ -554,7 +554,7 @@ | |||
| </FileConfiguration> | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\DigiExt.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\DigiExt.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Release|Win32" | |||
| @@ -566,7 +566,7 @@ | |||
| </FileConfiguration> | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\DSI.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\DSI.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Release|Win32" | |||
| @@ -578,7 +578,7 @@ | |||
| </FileConfiguration> | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\PlugInLib.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\PlugInLib.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Release|Win32" | |||
| @@ -594,7 +594,7 @@ | |||
| Name="release" | |||
| > | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\DAE.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\DAE.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Debug|Win32" | |||
| @@ -606,7 +606,7 @@ | |||
| </FileConfiguration> | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\DigiExt.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\DigiExt.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Debug|Win32" | |||
| @@ -618,7 +618,7 @@ | |||
| </FileConfiguration> | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\DSI.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\DSI.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Debug|Win32" | |||
| @@ -630,7 +630,7 @@ | |||
| </FileConfiguration> | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\PlugInLib.lib" | |||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\PlugInLib.lib" | |||
| > | |||
| <FileConfiguration | |||
| Name="Debug|Win32" | |||
| @@ -120,10 +120,6 @@ | |||
| #define JucePlugin_PreferredChannelConfigurations { 1, 1 }, { 2, 2 } | |||
| //============================================================================== | |||
| /** The plugin's internal latency, as a number of samples. | |||
| */ | |||
| #define JucePlugin_Latency 0 | |||
| /** Set this value to 1 if your plugin is a synth, or 0 if it isn't. | |||
| */ | |||
| #define JucePlugin_IsSynth 1 | |||
| @@ -300,7 +300,7 @@ public: | |||
| if (GetSampleRate() <= 0) | |||
| return 0.0; | |||
| return (JucePlugin_Latency) / GetSampleRate(); | |||
| return getLatencySamples() / GetSampleRate(); | |||
| } | |||
| //============================================================================== | |||
| @@ -435,6 +435,19 @@ public: | |||
| ComponentResult Initialize() | |||
| { | |||
| AUMIDIEffectBase::Initialize(); | |||
| const int numIns = GetInput(0) != 0 ? GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0; | |||
| const int numOuts = GetOutput(0) != 0 ? GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0; | |||
| bool isValidChannelConfig = false; | |||
| for (int i = 0; i < numChannelConfigs; ++i) | |||
| if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1]) | |||
| isValidChannelConfig = true; | |||
| if (! isValidChannelConfig) | |||
| return kAudioUnitErr_FormatNotSupported; | |||
| prepareToPlay(); | |||
| return noErr; | |||
| } | |||
| @@ -35,8 +35,16 @@ | |||
| // at the same time as the Digi headers) | |||
| #include <windows.h> | |||
| #ifdef _MSC_VER | |||
| #pragma pack (push, 8) | |||
| #endif | |||
| #include "../../juce_AudioFilterBase.h" | |||
| #include "../../juce_AudioFilterEditor.h" | |||
| #ifdef _MSC_VER | |||
| #pragma pack (pop) | |||
| #endif | |||
| //============================================================================== | |||
| @@ -79,9 +79,18 @@ | |||
| #include "CPluginControl_OnOff.h" | |||
| //============================================================================== | |||
| #ifdef _MSC_VER | |||
| #pragma pack (push, 8) | |||
| #endif | |||
| #include "../../juce_AudioFilterBase.h" | |||
| #include "../../juce_AudioFilterEditor.h" | |||
| #include "../../juce_IncludeCharacteristics.h" | |||
| #ifdef _MSC_VER | |||
| #pragma pack (pop) | |||
| #endif | |||
| #undef Component | |||
| //============================================================================== | |||
| @@ -526,7 +535,7 @@ protected: | |||
| ComponentResult GetDelaySamplesLong (long* aNumSamples) | |||
| { | |||
| if (aNumSamples != 0) | |||
| *aNumSamples = JucePlugin_Latency; | |||
| *aNumSamples = juceFilter != 0 ? juceFilter->getLatencySamples() : 0; | |||
| return noErr; | |||
| } | |||
| @@ -1,5 +1,3 @@ | |||
| EXPORTS | |||
| NewPlugIn @1 | |||
| _PI_GetRoutineDescriptor @2 | |||
| @@ -91,7 +91,16 @@ | |||
| #endif | |||
| //============================================================================== | |||
| #ifdef _MSC_VER | |||
| #pragma pack (push, 8) | |||
| #endif | |||
| #include "../../juce_AudioFilterBase.h" | |||
| #ifdef _MSC_VER | |||
| #pragma pack (pop) | |||
| #endif | |||
| #undef MemoryBlock | |||
| class JuceVSTWrapper; | |||
| @@ -349,7 +358,7 @@ public: | |||
| isSynth ((JucePlugin_IsSynth) != 0); | |||
| noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); | |||
| setInitialDelay (JucePlugin_Latency); | |||
| setInitialDelay (filter->getLatencySamples()); | |||
| programsAreChunks (true); | |||
| activePlugins.add (this); | |||
| @@ -669,6 +678,8 @@ public: | |||
| filter->prepareToPlay (rate, blockSize); | |||
| midiEvents.clear(); | |||
| setInitialDelay (filter->getLatencySamples()); | |||
| AudioEffectX::resume(); | |||
| #if JucePlugin_ProducesMidiOutput | |||
| @@ -40,6 +40,7 @@ AudioFilterBase::AudioFilterBase() | |||
| blockSize (0), | |||
| numInputChannels (0), | |||
| numOutputChannels (0), | |||
| latencySamples (0), | |||
| suspended (false) | |||
| { | |||
| } | |||
| @@ -71,6 +72,15 @@ void AudioFilterBase::setPlayConfigDetails (const int numIns, | |||
| blockSize = blockSize_; | |||
| } | |||
| void JUCE_CALLTYPE AudioFilterBase::setLatencySamples (const int newLatency) | |||
| { | |||
| if (latencySamples != newLatency) | |||
| { | |||
| latencySamples = newLatency; | |||
| updateHostDisplay(); | |||
| } | |||
| } | |||
| void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex, | |||
| const float newValue) | |||
| { | |||
| @@ -32,10 +32,6 @@ | |||
| #ifndef __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | |||
| #define __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | |||
| #ifdef _MSC_VER | |||
| #pragma pack (push, 8) | |||
| #endif | |||
| #include "../../../juce.h" | |||
| #include "juce_AudioFilterEditor.h" | |||
| #undef MemoryBlock | |||
| @@ -274,6 +270,21 @@ public: | |||
| /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ | |||
| virtual bool JUCE_CALLTYPE isOutputChannelStereoPair (int index) const = 0; | |||
| /** This returns the number of samples delay that the filter imposes on the audio | |||
| passing through it. | |||
| The host will call this to find the latency - the filter itself should set this value | |||
| by calling setLatencySamples() as soon as it can during its initialisation. | |||
| */ | |||
| int JUCE_CALLTYPE getLatencySamples() const throw() { return latencySamples; } | |||
| /** The filter should call this to set the number of samples delay that it introduces. | |||
| The filter should call this as soon as it can during initialisation, and can call it | |||
| later if the value changes. | |||
| */ | |||
| void JUCE_CALLTYPE setLatencySamples (const int newLatency); | |||
| //============================================================================== | |||
| /** This returns a critical section that will automatically be locked while the host | |||
| is calling the processBlock() method. | |||
| @@ -586,7 +597,7 @@ protected: | |||
| private: | |||
| AudioFilterEditor* activeEditor; | |||
| double sampleRate; | |||
| int blockSize, numInputChannels, numOutputChannels; | |||
| int blockSize, numInputChannels, numOutputChannels, latencySamples; | |||
| bool suspended; | |||
| CriticalSection callbackLock; | |||
| @@ -601,9 +612,5 @@ private: | |||
| */ | |||
| extern AudioFilterBase* JUCE_CALLTYPE createPluginFilter(); | |||
| #ifdef _MSC_VER | |||
| #pragma pack (pop) | |||
| #endif | |||
| #endif // __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | |||
| @@ -32,10 +32,6 @@ | |||
| #ifndef __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | |||
| #define __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | |||
| #ifdef _MSC_VER | |||
| #pragma pack (push, 8) | |||
| #endif | |||
| #include "../../../juce.h" | |||
| class AudioFilterBase; | |||
| @@ -72,8 +68,5 @@ private: | |||
| AudioFilterBase* const ownerFilter; | |||
| }; | |||
| #ifdef _MSC_VER | |||
| #pragma pack (pop) | |||
| #endif | |||
| #endif // __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | |||
| @@ -79,8 +79,8 @@ | |||
| #error "You need to define the JucePlugin_PreferredChannelConfigurations value in your JucePluginCharacteristics.h file!" | |||
| #endif | |||
| #ifndef JucePlugin_Latency | |||
| #error "You need to define the JucePlugin_Latency value in your JucePluginCharacteristics.h file!" | |||
| #ifdef JucePlugin_Latency | |||
| #error "JucePlugin_Latency is now deprecated - instead, call the AudioFilterBase::setLatencySamples() method if your plugin has a non-zero delay" | |||
| #endif | |||
| #ifndef JucePlugin_SilenceInProducesSilenceOut | |||
| @@ -46,9 +46,12 @@ | |||
| and takes care of incrementing and decrementing their ref counts when they | |||
| are added and removed from the array. | |||
| To make all the array's methods thread-safe, pass in "CriticalSection" as the templated | |||
| TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. | |||
| @see Array, OwnedArray, StringArray | |||
| */ | |||
| template <class ObjectClass> | |||
| template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection> | |||
| class ReferenceCountedArray : private ArrayAllocationBase <ObjectClass*> | |||
| { | |||
| public: | |||
| @@ -68,26 +71,32 @@ public: | |||
| } | |||
| /** Creates a copy of another array */ | |||
| ReferenceCountedArray (const ReferenceCountedArray<ObjectClass>& other) throw() | |||
| ReferenceCountedArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) throw() | |||
| : ArrayAllocationBase <ObjectClass*> (other.granularity), | |||
| numUsed (other.numUsed) | |||
| { | |||
| other.lockArray(); | |||
| this->setAllocatedSize (numUsed); | |||
| memcpy (this->elements, other.elements, numUsed * sizeof (ObjectClass*)); | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (this->elements[i] != 0) | |||
| this->elements[i]->incReferenceCount(); | |||
| other.unlockArray(); | |||
| } | |||
| /** Copies another array into this one. | |||
| Any existing objects in this array will first be released. | |||
| */ | |||
| const ReferenceCountedArray<ObjectClass>& operator= (const ReferenceCountedArray<ObjectClass>& other) throw() | |||
| const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) throw() | |||
| { | |||
| if (this != &other) | |||
| { | |||
| other.lockArray(); | |||
| lock.enter(); | |||
| clear(); | |||
| this->granularity = other.granularity; | |||
| @@ -99,6 +108,9 @@ public: | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (this->elements[i] != 0) | |||
| this->elements[i]->incReferenceCount(); | |||
| lock.exit(); | |||
| other.unlockArray(); | |||
| } | |||
| return *this; | |||
| @@ -120,12 +132,16 @@ public: | |||
| */ | |||
| void clear() | |||
| { | |||
| lock.enter(); | |||
| while (numUsed > 0) | |||
| if (this->elements [--numUsed] != 0) | |||
| this->elements [numUsed]->decReferenceCount(); | |||
| jassert (numUsed == 0); | |||
| this->setAllocatedSize (0); | |||
| lock.exit(); | |||
| } | |||
| /** Returns the current number of objects in the array. */ | |||
| @@ -144,8 +160,10 @@ public: | |||
| */ | |||
| inline ObjectClass* operator[] (const int index) const throw() | |||
| { | |||
| lock.enter(); | |||
| return (index >= 0 && index < numUsed) ? this->elements [index] | |||
| : (ObjectClass*) 0; | |||
| lock.exit(); | |||
| } | |||
| /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. | |||
| @@ -155,8 +173,10 @@ public: | |||
| */ | |||
| inline ObjectClass* getUnchecked (const int index) const throw() | |||
| { | |||
| lock.enter(); | |||
| jassert (index >= 0 && index < numUsed); | |||
| return this->elements [index]; | |||
| lock.exit(); | |||
| } | |||
| /** Returns a pointer to the first object in the array. | |||
| @@ -166,8 +186,12 @@ public: | |||
| */ | |||
| inline ObjectClass* getFirst() const throw() | |||
| { | |||
| return (numUsed > 0) ? this->elements [0] | |||
| : (ObjectClass*) 0; | |||
| lock.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? this->elements [0] | |||
| : (ObjectClass*) 0; | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| /** Returns a pointer to the last object in the array. | |||
| @@ -177,8 +201,12 @@ public: | |||
| */ | |||
| inline ObjectClass* getLast() const throw() | |||
| { | |||
| return (numUsed > 0) ? this->elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| lock.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? this->elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| //============================================================================== | |||
| @@ -189,17 +217,24 @@ public: | |||
| */ | |||
| int indexOf (const ObjectClass* const objectToLookFor) const throw() | |||
| { | |||
| int result = -1; | |||
| lock.enter(); | |||
| ObjectClass** e = this->elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (objectToLookFor == *e) | |||
| return (int) (e - this->elements); | |||
| { | |||
| result = (int) (e - this->elements); | |||
| break; | |||
| } | |||
| ++e; | |||
| } | |||
| return -1; | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| /** Returns true if the array contains a specified object. | |||
| @@ -209,16 +244,21 @@ public: | |||
| */ | |||
| bool contains (const ObjectClass* const objectToLookFor) const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass** e = this->elements; | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (objectToLookFor == *e) | |||
| { | |||
| lock.exit(); | |||
| return true; | |||
| } | |||
| ++e; | |||
| } | |||
| lock.exit(); | |||
| return false; | |||
| } | |||
| @@ -231,11 +271,14 @@ public: | |||
| */ | |||
| void add (ObjectClass* const newObject) throw() | |||
| { | |||
| lock.enter(); | |||
| this->ensureAllocatedSize (numUsed + 1); | |||
| this->elements [numUsed++] = newObject; | |||
| if (newObject != 0) | |||
| newObject->incReferenceCount(); | |||
| lock.exit(); | |||
| } | |||
| /** Inserts a new object into the array at the given index. | |||
| @@ -256,6 +299,7 @@ public: | |||
| { | |||
| if (indexToInsertAt >= 0) | |||
| { | |||
| lock.enter(); | |||
| if (indexToInsertAt > numUsed) | |||
| indexToInsertAt = numUsed; | |||
| @@ -273,6 +317,7 @@ public: | |||
| newObject->incReferenceCount(); | |||
| ++numUsed; | |||
| lock.exit(); | |||
| } | |||
| else | |||
| { | |||
| @@ -289,8 +334,12 @@ public: | |||
| */ | |||
| void addIfNotAlreadyThere (ObjectClass* const newObject) throw() | |||
| { | |||
| lock.enter(); | |||
| if (! contains (newObject)) | |||
| add (newObject); | |||
| lock.exit(); | |||
| } | |||
| /** Replaces an object in the array with a different one. | |||
| @@ -310,6 +359,8 @@ public: | |||
| { | |||
| if (indexToChange >= 0) | |||
| { | |||
| lock.enter(); | |||
| if (newObject != 0) | |||
| newObject->incReferenceCount(); | |||
| @@ -325,6 +376,8 @@ public: | |||
| this->ensureAllocatedSize (numUsed + 1); | |||
| this->elements [numUsed++] = newObject; | |||
| } | |||
| lock.exit(); | |||
| } | |||
| } | |||
| @@ -337,10 +390,13 @@ public: | |||
| all available elements will be copied. | |||
| @see add | |||
| */ | |||
| void addArray (const ReferenceCountedArray<ObjectClass>& arrayToAddFrom, | |||
| void addArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom, | |||
| int startIndex = 0, | |||
| int numElementsToAdd = -1) throw() | |||
| { | |||
| arrayToAddFrom.lockArray(); | |||
| lock.enter(); | |||
| if (startIndex < 0) | |||
| { | |||
| jassertfalse | |||
| @@ -357,6 +413,9 @@ public: | |||
| while (--numElementsToAdd >= 0) | |||
| add (arrayToAddFrom.getUnchecked (startIndex++)); | |||
| } | |||
| lock.exit(); | |||
| arrayToAddFrom.unlockArray(); | |||
| } | |||
| /** Inserts a new object into the array assuming that the array is sorted. | |||
| @@ -374,7 +433,9 @@ public: | |||
| void addSorted (ElementComparator& comparator, | |||
| ObjectClass* newObject) throw() | |||
| { | |||
| lock.enter(); | |||
| insert (findInsertIndexInSortedArray (comparator, this->elements, newObject, 0, numUsed), newObject); | |||
| lock.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -393,6 +454,8 @@ public: | |||
| */ | |||
| void remove (const int indexToRemove) | |||
| { | |||
| lock.enter(); | |||
| if (indexToRemove >= 0 && indexToRemove < numUsed) | |||
| { | |||
| ObjectClass** const e = this->elements + indexToRemove; | |||
| @@ -409,6 +472,8 @@ public: | |||
| if ((numUsed << 1) < this->numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| lock.exit(); | |||
| } | |||
| /** Removes the first occurrence of a specified object from the array. | |||
| @@ -421,7 +486,9 @@ public: | |||
| */ | |||
| void removeObject (ObjectClass* const objectToRemove) | |||
| { | |||
| lock.enter(); | |||
| remove (indexOf (objectToRemove)); | |||
| lock.exit(); | |||
| } | |||
| /** Removes a range of objects from the array. | |||
| @@ -442,6 +509,8 @@ public: | |||
| void removeRange (const int startIndex, | |||
| const int numberToRemove) | |||
| { | |||
| lock.enter(); | |||
| const int start = jlimit (0, numUsed, startIndex); | |||
| const int end = jlimit (0, numUsed, startIndex + numberToRemove); | |||
| @@ -471,6 +540,8 @@ public: | |||
| if ((numUsed << 1) < this->numAllocated) | |||
| minimiseStorageOverheads(); | |||
| } | |||
| lock.exit(); | |||
| } | |||
| /** Removes the last n objects from the array. | |||
| @@ -483,11 +554,15 @@ public: | |||
| */ | |||
| void removeLast (int howManyToRemove = 1) | |||
| { | |||
| lock.enter(); | |||
| if (howManyToRemove > numUsed) | |||
| howManyToRemove = numUsed; | |||
| while (--howManyToRemove >= 0) | |||
| remove (numUsed - 1); | |||
| lock.exit(); | |||
| } | |||
| /** Swaps a pair of objects in the array. | |||
| @@ -498,12 +573,16 @@ public: | |||
| void swap (const int index1, | |||
| const int index2) throw() | |||
| { | |||
| lock.enter(); | |||
| if (index1 >= 0 && index1 < numUsed | |||
| && index2 >= 0 && index2 < numUsed) | |||
| { | |||
| swapVariables (this->elements [index1], | |||
| this->elements [index2]); | |||
| } | |||
| lock.exit(); | |||
| } | |||
| /** Moves one of the objects to a different position. | |||
| @@ -524,6 +603,8 @@ public: | |||
| { | |||
| if (currentIndex != newIndex) | |||
| { | |||
| lock.enter(); | |||
| if (currentIndex >= 0 && currentIndex < numUsed) | |||
| { | |||
| if (newIndex < 0 || newIndex > numUsed - 1) | |||
| @@ -546,6 +627,8 @@ public: | |||
| this->elements [newIndex] = value; | |||
| } | |||
| lock.exit(); | |||
| } | |||
| } | |||
| @@ -554,23 +637,36 @@ public: | |||
| @returns true only if the other array contains the same objects in the same order | |||
| */ | |||
| bool operator== (const ReferenceCountedArray<ObjectClass>& other) const throw() | |||
| bool operator== (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const throw() | |||
| { | |||
| if (numUsed != other.numUsed) | |||
| return false; | |||
| other.lockArray(); | |||
| lock.enter(); | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (this->elements [i] != other.elements [i]) | |||
| return false; | |||
| bool result = numUsed == other.numUsed; | |||
| if (result) | |||
| { | |||
| for (int i = numUsed; --i >= 0;) | |||
| { | |||
| if (this->elements [i] != other.elements [i]) | |||
| { | |||
| result = false; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| return true; | |||
| lock.exit(); | |||
| other.unlockArray(); | |||
| return result; | |||
| } | |||
| /** Compares this array to another one. | |||
| @see operator== | |||
| */ | |||
| bool operator!= (const ReferenceCountedArray<ObjectClass>& other) const throw() | |||
| bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const throw() | |||
| { | |||
| return ! operator== (other); | |||
| } | |||
| @@ -608,7 +704,10 @@ public: | |||
| { | |||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | |||
| // avoids getting warning messages about the parameter being unused | |||
| lock.enter(); | |||
| sortArray (comparator, this->elements, 0, size() - 1, retainOrderOfEquivalentItems); | |||
| lock.exit(); | |||
| } | |||
| //============================================================================== | |||
| @@ -620,6 +719,8 @@ public: | |||
| */ | |||
| void minimiseStorageOverheads() throw() | |||
| { | |||
| lock.enter(); | |||
| if (numUsed == 0) | |||
| { | |||
| this->setAllocatedSize (0); | |||
| @@ -631,6 +732,33 @@ public: | |||
| if (newAllocation < this->numAllocated) | |||
| this->setAllocatedSize (newAllocation); | |||
| } | |||
| lock.exit(); | |||
| } | |||
| //============================================================================== | |||
| /** Locks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see unlockArray | |||
| */ | |||
| void lockArray() const throw() | |||
| { | |||
| lock.enter(); | |||
| } | |||
| /** Unlocks the array's CriticalSection. | |||
| Of course if the type of section used is a DummyCriticalSection, this won't | |||
| have any effect. | |||
| @see lockArray | |||
| */ | |||
| void unlockArray() const throw() | |||
| { | |||
| lock.exit(); | |||
| } | |||
| @@ -639,6 +767,7 @@ public: | |||
| private: | |||
| int numUsed; | |||
| TypeOfCriticalSectionToUse lock; | |||
| }; | |||
| @@ -178,10 +178,11 @@ public: | |||
| if (newObject != 0) | |||
| newObject->incReferenceCount(); | |||
| if (referencedObject != 0) | |||
| referencedObject->decReferenceCount(); | |||
| ReferenceCountedObjectClass* const oldObject = referencedObject; | |||
| referencedObject = newObject; | |||
| if (oldObject != 0) | |||
| oldObject->decReferenceCount(); | |||
| } | |||
| return *this; | |||
| @@ -199,10 +200,11 @@ public: | |||
| if (newObject != 0) | |||
| newObject->incReferenceCount(); | |||
| if (referencedObject != 0) | |||
| referencedObject->decReferenceCount(); | |||
| ReferenceCountedObjectClass* const oldObject = referencedObject; | |||
| referencedObject = newObject; | |||
| if (oldObject != 0) | |||
| oldObject->decReferenceCount(); | |||
| } | |||
| return *this; | |||