| @@ -1937,15 +1937,15 @@ bool juce_isHIViewCreatedByJuce (HIViewRef view) | |||||
| && HIObjectIsOfClass ((HIObjectRef) view, juceHiViewClassNameCFString); | && 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() | static void trackNextMouseEvent() | ||||
| { | { | ||||
| UInt32 mods; | 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. | - 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: 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 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. | - 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. | - new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath. | ||||
| - added a critical section option to ReferenceCountedArray | |||||
| ============================================================================== | ============================================================================== | ||||
| Changelist for version 1.44 | 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: | - 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 | - 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 | "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.. | - 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: | Creating a project for your own RTAS on the PC: | ||||
| ================================================= | ================================================= | ||||
| @@ -542,7 +542,7 @@ | |||||
| Name="debug" | Name="debug" | ||||
| > | > | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\DAE.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\DAE.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Release|Win32" | Name="Release|Win32" | ||||
| @@ -554,7 +554,7 @@ | |||||
| </FileConfiguration> | </FileConfiguration> | ||||
| </File> | </File> | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\DigiExt.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\DigiExt.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Release|Win32" | Name="Release|Win32" | ||||
| @@ -566,7 +566,7 @@ | |||||
| </FileConfiguration> | </FileConfiguration> | ||||
| </File> | </File> | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\DSI.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\DSI.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Release|Win32" | Name="Release|Win32" | ||||
| @@ -578,7 +578,7 @@ | |||||
| </FileConfiguration> | </FileConfiguration> | ||||
| </File> | </File> | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Debug\lib\PlugInLib.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Debug\lib\PlugInLib.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Release|Win32" | Name="Release|Win32" | ||||
| @@ -594,7 +594,7 @@ | |||||
| Name="release" | Name="release" | ||||
| > | > | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\DAE.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\DAE.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Debug|Win32" | Name="Debug|Win32" | ||||
| @@ -606,7 +606,7 @@ | |||||
| </FileConfiguration> | </FileConfiguration> | ||||
| </File> | </File> | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\DigiExt.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\DigiExt.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Debug|Win32" | Name="Debug|Win32" | ||||
| @@ -618,7 +618,7 @@ | |||||
| </FileConfiguration> | </FileConfiguration> | ||||
| </File> | </File> | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\DSI.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\DSI.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Debug|Win32" | Name="Debug|Win32" | ||||
| @@ -630,7 +630,7 @@ | |||||
| </FileConfiguration> | </FileConfiguration> | ||||
| </File> | </File> | ||||
| <File | <File | ||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_711_SDK\WinBag\Release\lib\PlugInLib.lib" | |||||
| RelativePath="..\..\..\..\..\..\..\essentials\PT_73_SDK\WinBag\Release\lib\PlugInLib.lib" | |||||
| > | > | ||||
| <FileConfiguration | <FileConfiguration | ||||
| Name="Debug|Win32" | Name="Debug|Win32" | ||||
| @@ -120,10 +120,6 @@ | |||||
| #define JucePlugin_PreferredChannelConfigurations { 1, 1 }, { 2, 2 } | #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. | /** Set this value to 1 if your plugin is a synth, or 0 if it isn't. | ||||
| */ | */ | ||||
| #define JucePlugin_IsSynth 1 | #define JucePlugin_IsSynth 1 | ||||
| @@ -300,7 +300,7 @@ public: | |||||
| if (GetSampleRate() <= 0) | if (GetSampleRate() <= 0) | ||||
| return 0.0; | return 0.0; | ||||
| return (JucePlugin_Latency) / GetSampleRate(); | |||||
| return getLatencySamples() / GetSampleRate(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -435,6 +435,19 @@ public: | |||||
| ComponentResult Initialize() | ComponentResult Initialize() | ||||
| { | { | ||||
| AUMIDIEffectBase::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(); | prepareToPlay(); | ||||
| return noErr; | return noErr; | ||||
| } | } | ||||
| @@ -35,8 +35,16 @@ | |||||
| // at the same time as the Digi headers) | // at the same time as the Digi headers) | ||||
| #include <windows.h> | #include <windows.h> | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (push, 8) | |||||
| #endif | |||||
| #include "../../juce_AudioFilterBase.h" | #include "../../juce_AudioFilterBase.h" | ||||
| #include "../../juce_AudioFilterEditor.h" | |||||
| #ifdef _MSC_VER | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| @@ -79,9 +79,18 @@ | |||||
| #include "CPluginControl_OnOff.h" | #include "CPluginControl_OnOff.h" | ||||
| //============================================================================== | //============================================================================== | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (push, 8) | |||||
| #endif | |||||
| #include "../../juce_AudioFilterBase.h" | #include "../../juce_AudioFilterBase.h" | ||||
| #include "../../juce_AudioFilterEditor.h" | #include "../../juce_AudioFilterEditor.h" | ||||
| #include "../../juce_IncludeCharacteristics.h" | #include "../../juce_IncludeCharacteristics.h" | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| #undef Component | #undef Component | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -526,7 +535,7 @@ protected: | |||||
| ComponentResult GetDelaySamplesLong (long* aNumSamples) | ComponentResult GetDelaySamplesLong (long* aNumSamples) | ||||
| { | { | ||||
| if (aNumSamples != 0) | if (aNumSamples != 0) | ||||
| *aNumSamples = JucePlugin_Latency; | |||||
| *aNumSamples = juceFilter != 0 ? juceFilter->getLatencySamples() : 0; | |||||
| return noErr; | return noErr; | ||||
| } | } | ||||
| @@ -1,5 +1,3 @@ | |||||
| EXPORTS | EXPORTS | ||||
| NewPlugIn @1 | NewPlugIn @1 | ||||
| _PI_GetRoutineDescriptor @2 | _PI_GetRoutineDescriptor @2 | ||||
| @@ -91,7 +91,16 @@ | |||||
| #endif | #endif | ||||
| //============================================================================== | //============================================================================== | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (push, 8) | |||||
| #endif | |||||
| #include "../../juce_AudioFilterBase.h" | #include "../../juce_AudioFilterBase.h" | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| #undef MemoryBlock | #undef MemoryBlock | ||||
| class JuceVSTWrapper; | class JuceVSTWrapper; | ||||
| @@ -349,7 +358,7 @@ public: | |||||
| isSynth ((JucePlugin_IsSynth) != 0); | isSynth ((JucePlugin_IsSynth) != 0); | ||||
| noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); | noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0); | ||||
| setInitialDelay (JucePlugin_Latency); | |||||
| setInitialDelay (filter->getLatencySamples()); | |||||
| programsAreChunks (true); | programsAreChunks (true); | ||||
| activePlugins.add (this); | activePlugins.add (this); | ||||
| @@ -669,6 +678,8 @@ public: | |||||
| filter->prepareToPlay (rate, blockSize); | filter->prepareToPlay (rate, blockSize); | ||||
| midiEvents.clear(); | midiEvents.clear(); | ||||
| setInitialDelay (filter->getLatencySamples()); | |||||
| AudioEffectX::resume(); | AudioEffectX::resume(); | ||||
| #if JucePlugin_ProducesMidiOutput | #if JucePlugin_ProducesMidiOutput | ||||
| @@ -40,6 +40,7 @@ AudioFilterBase::AudioFilterBase() | |||||
| blockSize (0), | blockSize (0), | ||||
| numInputChannels (0), | numInputChannels (0), | ||||
| numOutputChannels (0), | numOutputChannels (0), | ||||
| latencySamples (0), | |||||
| suspended (false) | suspended (false) | ||||
| { | { | ||||
| } | } | ||||
| @@ -71,6 +72,15 @@ void AudioFilterBase::setPlayConfigDetails (const int numIns, | |||||
| blockSize = blockSize_; | blockSize = blockSize_; | ||||
| } | } | ||||
| void JUCE_CALLTYPE AudioFilterBase::setLatencySamples (const int newLatency) | |||||
| { | |||||
| if (latencySamples != newLatency) | |||||
| { | |||||
| latencySamples = newLatency; | |||||
| updateHostDisplay(); | |||||
| } | |||||
| } | |||||
| void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex, | void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex, | ||||
| const float newValue) | const float newValue) | ||||
| { | { | ||||
| @@ -32,10 +32,6 @@ | |||||
| #ifndef __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | #ifndef __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | ||||
| #define __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | #define __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (push, 8) | |||||
| #endif | |||||
| #include "../../../juce.h" | #include "../../../juce.h" | ||||
| #include "juce_AudioFilterEditor.h" | #include "juce_AudioFilterEditor.h" | ||||
| #undef MemoryBlock | #undef MemoryBlock | ||||
| @@ -274,6 +270,21 @@ public: | |||||
| /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ | /** Returns true if the specified channel is part of a stereo pair with its neighbour. */ | ||||
| virtual bool JUCE_CALLTYPE isOutputChannelStereoPair (int index) const = 0; | 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 | /** This returns a critical section that will automatically be locked while the host | ||||
| is calling the processBlock() method. | is calling the processBlock() method. | ||||
| @@ -586,7 +597,7 @@ protected: | |||||
| private: | private: | ||||
| AudioFilterEditor* activeEditor; | AudioFilterEditor* activeEditor; | ||||
| double sampleRate; | double sampleRate; | ||||
| int blockSize, numInputChannels, numOutputChannels; | |||||
| int blockSize, numInputChannels, numOutputChannels, latencySamples; | |||||
| bool suspended; | bool suspended; | ||||
| CriticalSection callbackLock; | CriticalSection callbackLock; | ||||
| @@ -601,9 +612,5 @@ private: | |||||
| */ | */ | ||||
| extern AudioFilterBase* JUCE_CALLTYPE createPluginFilter(); | extern AudioFilterBase* JUCE_CALLTYPE createPluginFilter(); | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| #endif // __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | #endif // __JUCE_AUDIOFILTERBASE_JUCEHEADER__ | ||||
| @@ -32,10 +32,6 @@ | |||||
| #ifndef __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | #ifndef __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | ||||
| #define __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | #define __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (push, 8) | |||||
| #endif | |||||
| #include "../../../juce.h" | #include "../../../juce.h" | ||||
| class AudioFilterBase; | class AudioFilterBase; | ||||
| @@ -72,8 +68,5 @@ private: | |||||
| AudioFilterBase* const ownerFilter; | AudioFilterBase* const ownerFilter; | ||||
| }; | }; | ||||
| #ifdef _MSC_VER | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| #endif // __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | #endif // __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__ | ||||
| @@ -79,8 +79,8 @@ | |||||
| #error "You need to define the JucePlugin_PreferredChannelConfigurations value in your JucePluginCharacteristics.h file!" | #error "You need to define the JucePlugin_PreferredChannelConfigurations value in your JucePluginCharacteristics.h file!" | ||||
| #endif | #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 | #endif | ||||
| #ifndef JucePlugin_SilenceInProducesSilenceOut | #ifndef JucePlugin_SilenceInProducesSilenceOut | ||||
| @@ -46,9 +46,12 @@ | |||||
| and takes care of incrementing and decrementing their ref counts when they | and takes care of incrementing and decrementing their ref counts when they | ||||
| are added and removed from the array. | 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 | @see Array, OwnedArray, StringArray | ||||
| */ | */ | ||||
| template <class ObjectClass> | |||||
| template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection> | |||||
| class ReferenceCountedArray : private ArrayAllocationBase <ObjectClass*> | class ReferenceCountedArray : private ArrayAllocationBase <ObjectClass*> | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -68,26 +71,32 @@ public: | |||||
| } | } | ||||
| /** Creates a copy of another array */ | /** Creates a copy of another array */ | ||||
| ReferenceCountedArray (const ReferenceCountedArray<ObjectClass>& other) throw() | |||||
| ReferenceCountedArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) throw() | |||||
| : ArrayAllocationBase <ObjectClass*> (other.granularity), | : ArrayAllocationBase <ObjectClass*> (other.granularity), | ||||
| numUsed (other.numUsed) | numUsed (other.numUsed) | ||||
| { | { | ||||
| other.lockArray(); | |||||
| this->setAllocatedSize (numUsed); | this->setAllocatedSize (numUsed); | ||||
| memcpy (this->elements, other.elements, numUsed * sizeof (ObjectClass*)); | memcpy (this->elements, other.elements, numUsed * sizeof (ObjectClass*)); | ||||
| for (int i = numUsed; --i >= 0;) | for (int i = numUsed; --i >= 0;) | ||||
| if (this->elements[i] != 0) | if (this->elements[i] != 0) | ||||
| this->elements[i]->incReferenceCount(); | this->elements[i]->incReferenceCount(); | ||||
| other.unlockArray(); | |||||
| } | } | ||||
| /** Copies another array into this one. | /** Copies another array into this one. | ||||
| Any existing objects in this array will first be released. | 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) | if (this != &other) | ||||
| { | { | ||||
| other.lockArray(); | |||||
| lock.enter(); | |||||
| clear(); | clear(); | ||||
| this->granularity = other.granularity; | this->granularity = other.granularity; | ||||
| @@ -99,6 +108,9 @@ public: | |||||
| for (int i = numUsed; --i >= 0;) | for (int i = numUsed; --i >= 0;) | ||||
| if (this->elements[i] != 0) | if (this->elements[i] != 0) | ||||
| this->elements[i]->incReferenceCount(); | this->elements[i]->incReferenceCount(); | ||||
| lock.exit(); | |||||
| other.unlockArray(); | |||||
| } | } | ||||
| return *this; | return *this; | ||||
| @@ -120,12 +132,16 @@ public: | |||||
| */ | */ | ||||
| void clear() | void clear() | ||||
| { | { | ||||
| lock.enter(); | |||||
| while (numUsed > 0) | while (numUsed > 0) | ||||
| if (this->elements [--numUsed] != 0) | if (this->elements [--numUsed] != 0) | ||||
| this->elements [numUsed]->decReferenceCount(); | this->elements [numUsed]->decReferenceCount(); | ||||
| jassert (numUsed == 0); | jassert (numUsed == 0); | ||||
| this->setAllocatedSize (0); | this->setAllocatedSize (0); | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Returns the current number of objects in the array. */ | /** Returns the current number of objects in the array. */ | ||||
| @@ -144,8 +160,10 @@ public: | |||||
| */ | */ | ||||
| inline ObjectClass* operator[] (const int index) const throw() | inline ObjectClass* operator[] (const int index) const throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| return (index >= 0 && index < numUsed) ? this->elements [index] | return (index >= 0 && index < numUsed) ? this->elements [index] | ||||
| : (ObjectClass*) 0; | : (ObjectClass*) 0; | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. | /** 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() | inline ObjectClass* getUnchecked (const int index) const throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| jassert (index >= 0 && index < numUsed); | jassert (index >= 0 && index < numUsed); | ||||
| return this->elements [index]; | return this->elements [index]; | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Returns a pointer to the first object in the array. | /** Returns a pointer to the first object in the array. | ||||
| @@ -166,8 +186,12 @@ public: | |||||
| */ | */ | ||||
| inline ObjectClass* getFirst() const throw() | 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. | /** Returns a pointer to the last object in the array. | ||||
| @@ -177,8 +201,12 @@ public: | |||||
| */ | */ | ||||
| inline ObjectClass* getLast() const throw() | 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 indexOf (const ObjectClass* const objectToLookFor) const throw() | ||||
| { | { | ||||
| int result = -1; | |||||
| lock.enter(); | |||||
| ObjectClass** e = this->elements; | ObjectClass** e = this->elements; | ||||
| for (int i = numUsed; --i >= 0;) | for (int i = numUsed; --i >= 0;) | ||||
| { | { | ||||
| if (objectToLookFor == *e) | if (objectToLookFor == *e) | ||||
| return (int) (e - this->elements); | |||||
| { | |||||
| result = (int) (e - this->elements); | |||||
| break; | |||||
| } | |||||
| ++e; | ++e; | ||||
| } | } | ||||
| return -1; | |||||
| lock.exit(); | |||||
| return result; | |||||
| } | } | ||||
| /** Returns true if the array contains a specified object. | /** Returns true if the array contains a specified object. | ||||
| @@ -209,16 +244,21 @@ public: | |||||
| */ | */ | ||||
| bool contains (const ObjectClass* const objectToLookFor) const throw() | bool contains (const ObjectClass* const objectToLookFor) const throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| ObjectClass** e = this->elements; | ObjectClass** e = this->elements; | ||||
| for (int i = numUsed; --i >= 0;) | for (int i = numUsed; --i >= 0;) | ||||
| { | { | ||||
| if (objectToLookFor == *e) | if (objectToLookFor == *e) | ||||
| { | |||||
| lock.exit(); | |||||
| return true; | return true; | ||||
| } | |||||
| ++e; | ++e; | ||||
| } | } | ||||
| lock.exit(); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -231,11 +271,14 @@ public: | |||||
| */ | */ | ||||
| void add (ObjectClass* const newObject) throw() | void add (ObjectClass* const newObject) throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| this->ensureAllocatedSize (numUsed + 1); | this->ensureAllocatedSize (numUsed + 1); | ||||
| this->elements [numUsed++] = newObject; | this->elements [numUsed++] = newObject; | ||||
| if (newObject != 0) | if (newObject != 0) | ||||
| newObject->incReferenceCount(); | newObject->incReferenceCount(); | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Inserts a new object into the array at the given index. | /** Inserts a new object into the array at the given index. | ||||
| @@ -256,6 +299,7 @@ public: | |||||
| { | { | ||||
| if (indexToInsertAt >= 0) | if (indexToInsertAt >= 0) | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (indexToInsertAt > numUsed) | if (indexToInsertAt > numUsed) | ||||
| indexToInsertAt = numUsed; | indexToInsertAt = numUsed; | ||||
| @@ -273,6 +317,7 @@ public: | |||||
| newObject->incReferenceCount(); | newObject->incReferenceCount(); | ||||
| ++numUsed; | ++numUsed; | ||||
| lock.exit(); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -289,8 +334,12 @@ public: | |||||
| */ | */ | ||||
| void addIfNotAlreadyThere (ObjectClass* const newObject) throw() | void addIfNotAlreadyThere (ObjectClass* const newObject) throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (! contains (newObject)) | if (! contains (newObject)) | ||||
| add (newObject); | add (newObject); | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Replaces an object in the array with a different one. | /** Replaces an object in the array with a different one. | ||||
| @@ -310,6 +359,8 @@ public: | |||||
| { | { | ||||
| if (indexToChange >= 0) | if (indexToChange >= 0) | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (newObject != 0) | if (newObject != 0) | ||||
| newObject->incReferenceCount(); | newObject->incReferenceCount(); | ||||
| @@ -325,6 +376,8 @@ public: | |||||
| this->ensureAllocatedSize (numUsed + 1); | this->ensureAllocatedSize (numUsed + 1); | ||||
| this->elements [numUsed++] = newObject; | this->elements [numUsed++] = newObject; | ||||
| } | } | ||||
| lock.exit(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -337,10 +390,13 @@ public: | |||||
| all available elements will be copied. | all available elements will be copied. | ||||
| @see add | @see add | ||||
| */ | */ | ||||
| void addArray (const ReferenceCountedArray<ObjectClass>& arrayToAddFrom, | |||||
| void addArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom, | |||||
| int startIndex = 0, | int startIndex = 0, | ||||
| int numElementsToAdd = -1) throw() | int numElementsToAdd = -1) throw() | ||||
| { | { | ||||
| arrayToAddFrom.lockArray(); | |||||
| lock.enter(); | |||||
| if (startIndex < 0) | if (startIndex < 0) | ||||
| { | { | ||||
| jassertfalse | jassertfalse | ||||
| @@ -357,6 +413,9 @@ public: | |||||
| while (--numElementsToAdd >= 0) | while (--numElementsToAdd >= 0) | ||||
| add (arrayToAddFrom.getUnchecked (startIndex++)); | add (arrayToAddFrom.getUnchecked (startIndex++)); | ||||
| } | } | ||||
| lock.exit(); | |||||
| arrayToAddFrom.unlockArray(); | |||||
| } | } | ||||
| /** Inserts a new object into the array assuming that the array is sorted. | /** Inserts a new object into the array assuming that the array is sorted. | ||||
| @@ -374,7 +433,9 @@ public: | |||||
| void addSorted (ElementComparator& comparator, | void addSorted (ElementComparator& comparator, | ||||
| ObjectClass* newObject) throw() | ObjectClass* newObject) throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| insert (findInsertIndexInSortedArray (comparator, this->elements, newObject, 0, numUsed), newObject); | insert (findInsertIndexInSortedArray (comparator, this->elements, newObject, 0, numUsed), newObject); | ||||
| lock.exit(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -393,6 +454,8 @@ public: | |||||
| */ | */ | ||||
| void remove (const int indexToRemove) | void remove (const int indexToRemove) | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (indexToRemove >= 0 && indexToRemove < numUsed) | if (indexToRemove >= 0 && indexToRemove < numUsed) | ||||
| { | { | ||||
| ObjectClass** const e = this->elements + indexToRemove; | ObjectClass** const e = this->elements + indexToRemove; | ||||
| @@ -409,6 +472,8 @@ public: | |||||
| if ((numUsed << 1) < this->numAllocated) | if ((numUsed << 1) < this->numAllocated) | ||||
| minimiseStorageOverheads(); | minimiseStorageOverheads(); | ||||
| } | } | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Removes the first occurrence of a specified object from the array. | /** Removes the first occurrence of a specified object from the array. | ||||
| @@ -421,7 +486,9 @@ public: | |||||
| */ | */ | ||||
| void removeObject (ObjectClass* const objectToRemove) | void removeObject (ObjectClass* const objectToRemove) | ||||
| { | { | ||||
| lock.enter(); | |||||
| remove (indexOf (objectToRemove)); | remove (indexOf (objectToRemove)); | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Removes a range of objects from the array. | /** Removes a range of objects from the array. | ||||
| @@ -442,6 +509,8 @@ public: | |||||
| void removeRange (const int startIndex, | void removeRange (const int startIndex, | ||||
| const int numberToRemove) | const int numberToRemove) | ||||
| { | { | ||||
| lock.enter(); | |||||
| const int start = jlimit (0, numUsed, startIndex); | const int start = jlimit (0, numUsed, startIndex); | ||||
| const int end = jlimit (0, numUsed, startIndex + numberToRemove); | const int end = jlimit (0, numUsed, startIndex + numberToRemove); | ||||
| @@ -471,6 +540,8 @@ public: | |||||
| if ((numUsed << 1) < this->numAllocated) | if ((numUsed << 1) < this->numAllocated) | ||||
| minimiseStorageOverheads(); | minimiseStorageOverheads(); | ||||
| } | } | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Removes the last n objects from the array. | /** Removes the last n objects from the array. | ||||
| @@ -483,11 +554,15 @@ public: | |||||
| */ | */ | ||||
| void removeLast (int howManyToRemove = 1) | void removeLast (int howManyToRemove = 1) | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (howManyToRemove > numUsed) | if (howManyToRemove > numUsed) | ||||
| howManyToRemove = numUsed; | howManyToRemove = numUsed; | ||||
| while (--howManyToRemove >= 0) | while (--howManyToRemove >= 0) | ||||
| remove (numUsed - 1); | remove (numUsed - 1); | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Swaps a pair of objects in the array. | /** Swaps a pair of objects in the array. | ||||
| @@ -498,12 +573,16 @@ public: | |||||
| void swap (const int index1, | void swap (const int index1, | ||||
| const int index2) throw() | const int index2) throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (index1 >= 0 && index1 < numUsed | if (index1 >= 0 && index1 < numUsed | ||||
| && index2 >= 0 && index2 < numUsed) | && index2 >= 0 && index2 < numUsed) | ||||
| { | { | ||||
| swapVariables (this->elements [index1], | swapVariables (this->elements [index1], | ||||
| this->elements [index2]); | this->elements [index2]); | ||||
| } | } | ||||
| lock.exit(); | |||||
| } | } | ||||
| /** Moves one of the objects to a different position. | /** Moves one of the objects to a different position. | ||||
| @@ -524,6 +603,8 @@ public: | |||||
| { | { | ||||
| if (currentIndex != newIndex) | if (currentIndex != newIndex) | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (currentIndex >= 0 && currentIndex < numUsed) | if (currentIndex >= 0 && currentIndex < numUsed) | ||||
| { | { | ||||
| if (newIndex < 0 || newIndex > numUsed - 1) | if (newIndex < 0 || newIndex > numUsed - 1) | ||||
| @@ -546,6 +627,8 @@ public: | |||||
| this->elements [newIndex] = value; | 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 | @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. | /** Compares this array to another one. | ||||
| @see operator== | @see operator== | ||||
| */ | */ | ||||
| bool operator!= (const ReferenceCountedArray<ObjectClass>& other) const throw() | |||||
| bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const throw() | |||||
| { | { | ||||
| return ! operator== (other); | return ! operator== (other); | ||||
| } | } | ||||
| @@ -608,7 +704,10 @@ public: | |||||
| { | { | ||||
| (void) comparator; // if you pass in an object with a static compareElements() method, this | (void) comparator; // if you pass in an object with a static compareElements() method, this | ||||
| // avoids getting warning messages about the parameter being unused | // avoids getting warning messages about the parameter being unused | ||||
| lock.enter(); | |||||
| sortArray (comparator, this->elements, 0, size() - 1, retainOrderOfEquivalentItems); | sortArray (comparator, this->elements, 0, size() - 1, retainOrderOfEquivalentItems); | ||||
| lock.exit(); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -620,6 +719,8 @@ public: | |||||
| */ | */ | ||||
| void minimiseStorageOverheads() throw() | void minimiseStorageOverheads() throw() | ||||
| { | { | ||||
| lock.enter(); | |||||
| if (numUsed == 0) | if (numUsed == 0) | ||||
| { | { | ||||
| this->setAllocatedSize (0); | this->setAllocatedSize (0); | ||||
| @@ -631,6 +732,33 @@ public: | |||||
| if (newAllocation < this->numAllocated) | if (newAllocation < this->numAllocated) | ||||
| this->setAllocatedSize (newAllocation); | 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: | private: | ||||
| int numUsed; | int numUsed; | ||||
| TypeOfCriticalSectionToUse lock; | |||||
| }; | }; | ||||
| @@ -178,10 +178,11 @@ public: | |||||
| if (newObject != 0) | if (newObject != 0) | ||||
| newObject->incReferenceCount(); | newObject->incReferenceCount(); | ||||
| if (referencedObject != 0) | |||||
| referencedObject->decReferenceCount(); | |||||
| ReferenceCountedObjectClass* const oldObject = referencedObject; | |||||
| referencedObject = newObject; | referencedObject = newObject; | ||||
| if (oldObject != 0) | |||||
| oldObject->decReferenceCount(); | |||||
| } | } | ||||
| return *this; | return *this; | ||||
| @@ -199,10 +200,11 @@ public: | |||||
| if (newObject != 0) | if (newObject != 0) | ||||
| newObject->incReferenceCount(); | newObject->incReferenceCount(); | ||||
| if (referencedObject != 0) | |||||
| referencedObject->decReferenceCount(); | |||||
| ReferenceCountedObjectClass* const oldObject = referencedObject; | |||||
| referencedObject = newObject; | referencedObject = newObject; | ||||
| if (oldObject != 0) | |||||
| oldObject->decReferenceCount(); | |||||
| } | } | ||||
| return *this; | return *this; | ||||