| @@ -75,15 +75,19 @@ AudioProcessorGraph::Node::Ptr FilterGraph::getNodeForName (const String& name) | |||
| return nullptr; | |||
| } | |||
| void FilterGraph::addPlugin (const PluginDescription& desc, Point<double> p) | |||
| void FilterGraph::addPlugin (const PluginDescription& desc, Point<double> pos) | |||
| { | |||
| formatManager.createPluginInstanceAsync (desc, | |||
| graph.getSampleRate(), | |||
| graph.getBlockSize(), | |||
| new AsyncCallback (*this, p)); | |||
| [this, pos] (std::unique_ptr<AudioPluginInstance> instance, const String& error) | |||
| { | |||
| addPluginCallback (std::move (instance), error, pos); | |||
| }); | |||
| } | |||
| void FilterGraph::addFilterCallback (AudioPluginInstance* instance, const String& error, Point<double> pos) | |||
| void FilterGraph::addPluginCallback (std::unique_ptr<AudioPluginInstance> instance, | |||
| const String& error, Point<double> pos) | |||
| { | |||
| if (instance == nullptr) | |||
| { | |||
| @@ -95,7 +99,7 @@ void FilterGraph::addFilterCallback (AudioPluginInstance* instance, const String | |||
| { | |||
| instance->enableAllBuses(); | |||
| if (auto node = graph.addNode (instance)) | |||
| if (auto node = graph.addNode (std::move (instance))) | |||
| { | |||
| node->properties.set ("x", pos.x); | |||
| node->properties.set ("y", pos.y); | |||
| @@ -256,8 +260,8 @@ void FilterGraph::setLastDocumentOpened (const File& file) | |||
| } | |||
| //============================================================================== | |||
| static void readBusLayoutFromXml (AudioProcessor::BusesLayout& busesLayout, AudioProcessor* plugin, | |||
| const XmlElement& xml, const bool isInput) | |||
| static void readBusLayoutFromXml (AudioProcessor::BusesLayout& busesLayout, AudioProcessor& plugin, | |||
| const XmlElement& xml, bool isInput) | |||
| { | |||
| auto& targetBuses = (isInput ? busesLayout.inputBuses | |||
| : busesLayout.outputBuses); | |||
| @@ -272,12 +276,12 @@ static void readBusLayoutFromXml (AudioProcessor::BusesLayout& busesLayout, Audi | |||
| // the number of buses on busesLayout may not be in sync with the plugin after adding buses | |||
| // because adding an input bus could also add an output bus | |||
| for (int actualIdx = plugin->getBusCount (isInput) - 1; actualIdx < busIdx; ++actualIdx) | |||
| if (! plugin->addBus (isInput)) | |||
| for (int actualIdx = plugin.getBusCount (isInput) - 1; actualIdx < busIdx; ++actualIdx) | |||
| if (! plugin.addBus (isInput)) | |||
| return; | |||
| for (int actualIdx = targetBuses.size() - 1; actualIdx < busIdx; ++actualIdx) | |||
| targetBuses.add (plugin->getChannelLayoutOfBus (isInput, busIdx)); | |||
| targetBuses.add (plugin.getChannelLayoutOfBus (isInput, busIdx)); | |||
| auto layout = e->getStringAttribute ("layout"); | |||
| @@ -289,7 +293,7 @@ static void readBusLayoutFromXml (AudioProcessor::BusesLayout& busesLayout, Audi | |||
| // if the plugin has more buses than specified in the xml, then try to remove them! | |||
| while (maxNumBuses < targetBuses.size()) | |||
| { | |||
| if (! plugin->removeBus (isInput)) | |||
| if (! plugin.removeBus (isInput)) | |||
| return; | |||
| targetBuses.removeLast(); | |||
| @@ -374,20 +378,20 @@ void FilterGraph::createNodeFromXml (const XmlElement& xml) | |||
| String errorMessage; | |||
| if (auto* instance = formatManager.createPluginInstance (pd, graph.getSampleRate(), | |||
| graph.getBlockSize(), errorMessage)) | |||
| if (auto instance = formatManager.createPluginInstance (pd, graph.getSampleRate(), | |||
| graph.getBlockSize(), errorMessage)) | |||
| { | |||
| if (auto* layoutEntity = xml.getChildByName ("LAYOUT")) | |||
| { | |||
| auto layout = instance->getBusesLayout(); | |||
| readBusLayoutFromXml (layout, instance, *layoutEntity, true); | |||
| readBusLayoutFromXml (layout, instance, *layoutEntity, false); | |||
| readBusLayoutFromXml (layout, *instance, *layoutEntity, true); | |||
| readBusLayoutFromXml (layout, *instance, *layoutEntity, false); | |||
| instance->setBusesLayout (layout); | |||
| } | |||
| if (auto node = graph.addNode (instance, NodeID ((uint32) xml.getIntAttribute ("uid")))) | |||
| if (auto node = graph.addNode (std::move (instance), NodeID ((uint32) xml.getIntAttribute ("uid")))) | |||
| { | |||
| if (auto* state = xml.getChildByName ("STATE")) | |||
| { | |||
| @@ -84,23 +84,6 @@ public: | |||
| AudioProcessorGraph graph; | |||
| private: | |||
| //============================================================================== | |||
| struct AsyncCallback : public AudioPluginFormat::InstantiationCompletionCallback | |||
| { | |||
| AsyncCallback(FilterGraph& g, Point<double> pos) : owner(g), position(pos) | |||
| {} | |||
| void completionCallback(AudioPluginInstance* instance, const String& error) override | |||
| { | |||
| owner.addFilterCallback(instance, error, position); | |||
| } | |||
| FilterGraph& owner; | |||
| Point<double> position; | |||
| JUCE_DECLARE_NON_COPYABLE (AsyncCallback) | |||
| }; | |||
| //============================================================================== | |||
| AudioPluginFormatManager& formatManager; | |||
| OwnedArray<PluginWindow> activePluginWindows; | |||
| @@ -108,8 +91,8 @@ private: | |||
| NodeID lastUID; | |||
| NodeID getNextUID() noexcept; | |||
| void createNodeFromXml (const XmlElement& xml); | |||
| void addFilterCallback (AudioPluginInstance*, const String& error, Point<double>); | |||
| void createNodeFromXml (const XmlElement&); | |||
| void addPluginCallback (std::unique_ptr<AudioPluginInstance>, const String& error, Point<double>); | |||
| void changeListenerCallback (ChangeBroadcaster*) override; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilterGraph) | |||
| @@ -64,10 +64,8 @@ public: | |||
| bool isBusesLayoutSupported (const BusesLayout& layout) const override | |||
| { | |||
| if (! isGenerator) | |||
| { | |||
| if (layout.getMainOutputChannelSet() != channelSet) | |||
| return false; | |||
| } | |||
| if (layout.getMainInputChannelSet() != channelSet) | |||
| return false; | |||
| @@ -130,7 +128,7 @@ private: | |||
| class SineWaveSynth : public InternalPlugin | |||
| { | |||
| public: | |||
| SineWaveSynth (const PluginDescription& descr) : InternalPlugin (descr) | |||
| SineWaveSynth (const PluginDescription& descr) : InternalPlugin (descr) | |||
| { | |||
| const int numVoices = 8; | |||
| @@ -174,22 +172,17 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| class SineWaveSound : public SynthesiserSound | |||
| struct SineWaveSound : public SynthesiserSound | |||
| { | |||
| public: | |||
| SineWaveSound() {} | |||
| SineWaveSound() = default; | |||
| bool appliesToNote (int /*midiNoteNumber*/) override { return true; } | |||
| bool appliesToChannel (int /*midiChannel*/) override { return true; } | |||
| }; | |||
| class SineWaveVoice : public SynthesiserVoice | |||
| struct SineWaveVoice : public SynthesiserVoice | |||
| { | |||
| public: | |||
| SineWaveVoice() | |||
| : currentAngle (0), angleDelta (0), level (0), tailOff (0) | |||
| { | |||
| } | |||
| SineWaveVoice() = default; | |||
| bool canPlaySound (SynthesiserSound* sound) override | |||
| { | |||
| @@ -287,7 +280,7 @@ private: | |||
| using SynthesiserVoice::renderNextBlock; | |||
| private: | |||
| double currentAngle, angleDelta, level, tailOff; | |||
| double currentAngle = 0, angleDelta = 0, level = 0, tailOff = 0; | |||
| }; | |||
| //============================================================================== | |||
| @@ -366,28 +359,27 @@ InternalPluginFormat::InternalPluginFormat() | |||
| } | |||
| } | |||
| AudioPluginInstance* InternalPluginFormat::createInstance (const String& name) | |||
| std::unique_ptr<AudioPluginInstance> InternalPluginFormat::createInstance (const String& name) | |||
| { | |||
| if (name == audioOutDesc.name) return new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode); | |||
| if (name == audioInDesc.name) return new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode); | |||
| if (name == midiInDesc.name) return new AudioProcessorGraph::AudioGraphIOProcessor (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode); | |||
| if (name == audioOutDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode); | |||
| if (name == audioInDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode); | |||
| if (name == midiInDesc.name) return std::make_unique<AudioProcessorGraph::AudioGraphIOProcessor> (AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode); | |||
| if (name == SineWaveSynth::getIdentifier()) return new SineWaveSynth (SineWaveSynth::getPluginDescription()); | |||
| if (name == ReverbFilter::getIdentifier()) return new ReverbFilter (ReverbFilter::getPluginDescription()); | |||
| if (name == SineWaveSynth::getIdentifier()) return std::make_unique<SineWaveSynth> (SineWaveSynth::getPluginDescription()); | |||
| if (name == ReverbFilter::getIdentifier()) return std::make_unique<ReverbFilter> (ReverbFilter::getPluginDescription()); | |||
| return nullptr; | |||
| return {}; | |||
| } | |||
| void InternalPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| double /*initialSampleRate*/, | |||
| int /*initialBufferSize*/, | |||
| void* userData, | |||
| double /*initialSampleRate*/, int /*initialBufferSize*/, | |||
| PluginCreationCallback callback) | |||
| { | |||
| auto* p = createInstance (desc.name); | |||
| callback (userData, p, p == nullptr ? NEEDS_TRANS ("Invalid internal filter name") : String()); | |||
| if (auto p = createInstance (desc.name)) | |||
| callback (std::move (p), {}); | |||
| else | |||
| callback (nullptr, NEEDS_TRANS ("Invalid internal plugin name")); | |||
| } | |||
| bool InternalPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept | |||
| @@ -57,9 +57,11 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| void createPluginInstance (const PluginDescription&, double initialSampleRate, int initialBufferSize, | |||
| void* userData, PluginCreationCallback) override; | |||
| AudioPluginInstance* createInstance (const String& name); | |||
| void createPluginInstance (const PluginDescription&, | |||
| double initialSampleRate, int initialBufferSize, | |||
| PluginCreationCallback) override; | |||
| std::unique_ptr<AudioPluginInstance> createInstance (const String& name); | |||
| bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; | |||
| }; | |||
| @@ -27,188 +27,83 @@ | |||
| namespace juce | |||
| { | |||
| namespace AudioPluginFormatHelpers | |||
| { | |||
| struct CallbackInvoker | |||
| { | |||
| struct InvokeOnMessageThread : public CallbackMessage | |||
| { | |||
| InvokeOnMessageThread (AudioPluginInstance* inInstance, const String& inError, | |||
| AudioPluginFormat::InstantiationCompletionCallback* inCompletion, | |||
| CallbackInvoker* invoker) | |||
| : instance (inInstance), error (inError), compCallback (inCompletion), owner (invoker) | |||
| {} | |||
| void messageCallback() override { compCallback->completionCallback (instance.release(), error); } | |||
| //============================================================================== | |||
| std::unique_ptr<AudioPluginInstance> instance; | |||
| String error; | |||
| std::unique_ptr<AudioPluginFormat::InstantiationCompletionCallback> compCallback; | |||
| std::unique_ptr<CallbackInvoker> owner; | |||
| }; | |||
| //============================================================================== | |||
| CallbackInvoker (AudioPluginFormat::InstantiationCompletionCallback* cc) : completion (cc) | |||
| {} | |||
| void completionCallback (AudioPluginInstance* instance, const String& error) | |||
| { | |||
| (new InvokeOnMessageThread (instance, error, completion, this))->post(); | |||
| } | |||
| static void staticCompletionCallback (void* userData, AudioPluginInstance* instance, const String& error) | |||
| { | |||
| reinterpret_cast<CallbackInvoker*> (userData)->completionCallback (instance, error); | |||
| } | |||
| //============================================================================== | |||
| AudioPluginFormat::InstantiationCompletionCallback* completion; | |||
| }; | |||
| } | |||
| AudioPluginFormat::AudioPluginFormat() noexcept {} | |||
| AudioPluginFormat::~AudioPluginFormat() {} | |||
| AudioPluginInstance* AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc, | |||
| double initialSampleRate, | |||
| int initialBufferSize) | |||
| std::unique_ptr<AudioPluginInstance> AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc, | |||
| double initialSampleRate, | |||
| int initialBufferSize) | |||
| { | |||
| String errorMessage; | |||
| return createInstanceFromDescription (desc, initialSampleRate, initialBufferSize, errorMessage); | |||
| } | |||
| //============================================================================== | |||
| struct EventSignaler : public AudioPluginFormat::InstantiationCompletionCallback | |||
| { | |||
| EventSignaler (WaitableEvent& inEvent, AudioPluginInstance*& inInstance, String& inErrorMessage) | |||
| : event (inEvent), outInstance (inInstance), outErrorMessage (inErrorMessage) | |||
| {} | |||
| void completionCallback (AudioPluginInstance* newInstance, const String& result) override | |||
| { | |||
| outInstance = newInstance; | |||
| outErrorMessage = result; | |||
| event.signal(); | |||
| } | |||
| static void staticCompletionCallback (void* userData, AudioPluginInstance* pluginInstance, const String& error) | |||
| { | |||
| reinterpret_cast<EventSignaler*> (userData)->completionCallback (pluginInstance, error); | |||
| } | |||
| WaitableEvent& event; | |||
| AudioPluginInstance*& outInstance; | |||
| String& outErrorMessage; | |||
| JUCE_DECLARE_NON_COPYABLE (EventSignaler) | |||
| }; | |||
| AudioPluginInstance* AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| String& errorMessage) | |||
| std::unique_ptr<AudioPluginInstance> AudioPluginFormat::createInstanceFromDescription (const PluginDescription& desc, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| String& errorMessage) | |||
| { | |||
| if (MessageManager::getInstance()->isThisTheMessageThread() | |||
| && requiresUnblockedMessageThreadDuringCreation(desc)) | |||
| && requiresUnblockedMessageThreadDuringCreation (desc)) | |||
| { | |||
| errorMessage = NEEDS_TRANS ("This plug-in cannot be instantiated synchronously"); | |||
| return nullptr; | |||
| return {}; | |||
| } | |||
| WaitableEvent waitForCreation; | |||
| AudioPluginInstance* instance = nullptr; | |||
| WaitableEvent finishedSignal; | |||
| std::unique_ptr<AudioPluginInstance> instance; | |||
| std::unique_ptr<EventSignaler> eventSignaler (new EventSignaler (waitForCreation, instance, errorMessage)); | |||
| auto callback = [&] (std::unique_ptr<AudioPluginInstance> p, const String& error) | |||
| { | |||
| errorMessage = error; | |||
| instance = std::move (p); | |||
| finishedSignal.signal(); | |||
| }; | |||
| if (! MessageManager::getInstance()->isThisTheMessageThread()) | |||
| createPluginInstanceAsync (desc, initialSampleRate, initialBufferSize, eventSignaler.release()); | |||
| createPluginInstanceAsync (desc, initialSampleRate, initialBufferSize, std::move (callback)); | |||
| else | |||
| createPluginInstance (desc, initialSampleRate, initialBufferSize, | |||
| eventSignaler.get(), EventSignaler::staticCompletionCallback); | |||
| waitForCreation.wait(); | |||
| createPluginInstance (desc, initialSampleRate, initialBufferSize, std::move (callback)); | |||
| finishedSignal.wait(); | |||
| return instance; | |||
| } | |||
| void AudioPluginFormat::createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| AudioPluginFormat::InstantiationCompletionCallback* callback) | |||
| double initialSampleRate, int initialBufferSize, | |||
| PluginCreationCallback callback) | |||
| { | |||
| jassert (callback != nullptr); | |||
| if (MessageManager::getInstance()->isThisTheMessageThread()) | |||
| { | |||
| createPluginInstanceOnMessageThread (description, initialSampleRate, initialBufferSize, callback); | |||
| createPluginInstance (description, initialSampleRate, initialBufferSize, std::move (callback)); | |||
| return; | |||
| } | |||
| //============================================================================== | |||
| struct InvokeOnMessageThread : public CallbackMessage | |||
| { | |||
| InvokeOnMessageThread (AudioPluginFormat* myself, | |||
| const PluginDescription& descriptionParam, | |||
| double initialSampleRateParam, | |||
| int initialBufferSizeParam, | |||
| AudioPluginFormat::InstantiationCompletionCallback* callbackParam) | |||
| : owner (myself), descr (descriptionParam), sampleRate (initialSampleRateParam), | |||
| bufferSize (initialBufferSizeParam), call (callbackParam) | |||
| {} | |||
| InvokeOnMessageThread (AudioPluginFormat& f, const PluginDescription& d, | |||
| double sr, int size, PluginCreationCallback call) | |||
| : format (f), desc (d), sampleRate (sr), bufferSize (size), | |||
| callbackToUse (std::move (call)) | |||
| { | |||
| post(); | |||
| } | |||
| void messageCallback() override | |||
| { | |||
| owner->createPluginInstanceOnMessageThread (descr, sampleRate, bufferSize, call); | |||
| format.createPluginInstance (desc, sampleRate, bufferSize, std::move (callbackToUse)); | |||
| } | |||
| AudioPluginFormat* owner; | |||
| PluginDescription descr; | |||
| AudioPluginFormat& format; | |||
| PluginDescription desc; | |||
| double sampleRate; | |||
| int bufferSize; | |||
| AudioPluginFormat::InstantiationCompletionCallback* call; | |||
| }; | |||
| (new InvokeOnMessageThread (this, description, initialSampleRate, initialBufferSize, callback))->post(); | |||
| } | |||
| void AudioPluginFormat::createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| std::function<void(AudioPluginInstance*, const String&)> f) | |||
| { | |||
| struct CallbackInvoker : public AudioPluginFormat::InstantiationCompletionCallback | |||
| { | |||
| CallbackInvoker (std::function<void(AudioPluginInstance*, const String&)> inCompletion) | |||
| : completion (inCompletion) | |||
| {} | |||
| void completionCallback (AudioPluginInstance* instance, const String& error) override | |||
| { | |||
| completion (instance, error); | |||
| } | |||
| std::function<void(AudioPluginInstance*, const String&)> completion; | |||
| PluginCreationCallback callbackToUse; | |||
| }; | |||
| createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, new CallbackInvoker (f)); | |||
| } | |||
| void AudioPluginFormat::createPluginInstanceOnMessageThread (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| AudioPluginFormat::InstantiationCompletionCallback* callback) | |||
| { | |||
| jassert (callback != nullptr); | |||
| JUCE_ASSERT_MESSAGE_THREAD | |||
| //============================================================================== | |||
| //============================================================================== | |||
| AudioPluginFormatHelpers::CallbackInvoker* completion = new AudioPluginFormatHelpers::CallbackInvoker (callback); | |||
| createPluginInstance (description, initialSampleRate, initialBufferSize, completion, | |||
| AudioPluginFormatHelpers::CallbackInvoker::staticCompletionCallback); | |||
| new InvokeOnMessageThread (*this, description, initialSampleRate, initialBufferSize, std::move (callback)); | |||
| } | |||
| } // namespace juce | |||
| @@ -38,17 +38,6 @@ namespace juce | |||
| class JUCE_API AudioPluginFormat | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Structure used for callbacks when instantiation is completed. */ | |||
| struct JUCE_API InstantiationCompletionCallback | |||
| { | |||
| virtual ~InstantiationCompletionCallback() = default; | |||
| virtual void completionCallback (AudioPluginInstance* instance, const String& error) = 0; | |||
| JUCE_LEAK_DETECTOR (InstantiationCompletionCallback) | |||
| }; | |||
| //============================================================================== | |||
| /** Destructor. */ | |||
| virtual ~AudioPluginFormat(); | |||
| @@ -73,32 +62,30 @@ public: | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| @see AudioPluginFormatManager::createInstance | |||
| */ | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription&, | |||
| double initialSampleRate, | |||
| int initialBufferSize); | |||
| std::unique_ptr<AudioPluginInstance> createInstanceFromDescription (const PluginDescription&, | |||
| double initialSampleRate, | |||
| int initialBufferSize); | |||
| /** Same as above but with the possibility of returning an error message. | |||
| @see AudioPluginFormatManager::createInstance | |||
| */ | |||
| AudioPluginInstance* createInstanceFromDescription (const PluginDescription&, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| String& errorMessage); | |||
| std::unique_ptr<AudioPluginInstance> createInstanceFromDescription (const PluginDescription&, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| String& errorMessage); | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| /** A callback lambda that is passed to createPluginInstanceAsync() */ | |||
| using PluginCreationCallback = std::function<void(std::unique_ptr<AudioPluginInstance>, const String&)>; | |||
| @see AudioPluginFormatManager::createInstanceAsync | |||
| /** Tries to recreate a type from a previously generated PluginDescription. | |||
| When the plugin has been created, it will be passed to the caller via an | |||
| asynchronous call to the PluginCreationCallback lambda that was provided. | |||
| @see AudioPluginFormatManager::createPluginInstanceAsync | |||
| */ | |||
| void createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| InstantiationCompletionCallback* completionCallback); | |||
| void createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| std::function<void(AudioPluginInstance*, const String&)> completionCallback); | |||
| PluginCreationCallback); | |||
| /** Should do a quick check to see if this file or directory might be a plugin of | |||
| this format. | |||
| @@ -151,22 +138,15 @@ protected: | |||
| AudioPluginFormat() noexcept; | |||
| using PluginCreationCallback = void (*) (void*, AudioPluginInstance*, const String&); | |||
| /** Implementors must override this function. This is guaranteed to be called on | |||
| the message thread. You may call the callback on any thread. | |||
| */ | |||
| virtual void createPluginInstance (const PluginDescription&, double initialSampleRate, | |||
| int initialBufferSize, void* userData, | |||
| PluginCreationCallback) = 0; | |||
| int initialBufferSize, PluginCreationCallback) = 0; | |||
| virtual bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept = 0; | |||
| private: | |||
| /** @internal */ | |||
| void createPluginInstanceOnMessageThread (const PluginDescription&, double rate, int size, | |||
| AudioPluginFormat::InstantiationCompletionCallback*); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormat) | |||
| }; | |||
| @@ -27,37 +27,6 @@ | |||
| namespace juce | |||
| { | |||
| namespace PluginFormatManagerHelpers | |||
| { | |||
| struct ErrorCallbackOnMessageThread : public CallbackMessage | |||
| { | |||
| ErrorCallbackOnMessageThread (const String& inError, | |||
| AudioPluginFormat::InstantiationCompletionCallback* c) | |||
| : error (inError), callback (c) | |||
| { | |||
| } | |||
| void messageCallback() override { callback->completionCallback (nullptr, error); } | |||
| String error; | |||
| std::unique_ptr<AudioPluginFormat::InstantiationCompletionCallback> callback; | |||
| }; | |||
| struct ErrorLambdaOnMessageThread : public CallbackMessage | |||
| { | |||
| ErrorLambdaOnMessageThread (const String& inError, | |||
| std::function<void(AudioPluginInstance*, const String&)> f) | |||
| : error (inError), lambda (f) | |||
| { | |||
| } | |||
| void messageCallback() override { lambda (nullptr, error); } | |||
| String error; | |||
| std::function<void(AudioPluginInstance*, const String&)> lambda; | |||
| }; | |||
| } | |||
| AudioPluginFormatManager::AudioPluginFormatManager() {} | |||
| AudioPluginFormatManager::~AudioPluginFormatManager() {} | |||
| @@ -120,39 +89,40 @@ void AudioPluginFormatManager::addFormat (AudioPluginFormat* format) | |||
| formats.add (format); | |||
| } | |||
| AudioPluginInstance* AudioPluginFormatManager::createPluginInstance (const PluginDescription& description, double rate, | |||
| int blockSize, String& errorMessage) const | |||
| std::unique_ptr<AudioPluginInstance> AudioPluginFormatManager::createPluginInstance (const PluginDescription& description, | |||
| double rate, int blockSize, | |||
| String& errorMessage) const | |||
| { | |||
| if (auto* format = findFormatForDescription (description, errorMessage)) | |||
| return format->createInstanceFromDescription (description, rate, blockSize, errorMessage); | |||
| return nullptr; | |||
| return {}; | |||
| } | |||
| void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| AudioPluginFormat::InstantiationCompletionCallback* callback) | |||
| double initialSampleRate, int initialBufferSize, | |||
| AudioPluginFormat::PluginCreationCallback callback) | |||
| { | |||
| String error; | |||
| if (auto* format = findFormatForDescription (description, error)) | |||
| return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, callback); | |||
| return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, std::move (callback)); | |||
| (new PluginFormatManagerHelpers::ErrorCallbackOnMessageThread (error, callback))->post(); | |||
| } | |||
| struct DeliverError : public CallbackMessage | |||
| { | |||
| DeliverError (AudioPluginFormat::PluginCreationCallback c, const String& e) | |||
| : call (std::move (c)), error (e) | |||
| { | |||
| post(); | |||
| } | |||
| void AudioPluginFormatManager::createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| std::function<void(AudioPluginInstance*, const String&)> f) | |||
| { | |||
| String error; | |||
| void messageCallback() override { call (nullptr, error); } | |||
| if (auto* format = findFormatForDescription (description, error)) | |||
| return format->createPluginInstanceAsync (description, initialSampleRate, initialBufferSize, f); | |||
| AudioPluginFormat::PluginCreationCallback call; | |||
| String error; | |||
| }; | |||
| (new PluginFormatManagerHelpers::ErrorLambdaOnMessageThread (error, f))->post(); | |||
| new DeliverError (std::move (callback), error); | |||
| } | |||
| AudioPluginFormat* AudioPluginFormatManager::findFormatForDescription (const PluginDescription& description, | |||
| @@ -167,7 +137,7 @@ AudioPluginFormat* AudioPluginFormatManager::findFormatForDescription (const Plu | |||
| errorMessage = NEEDS_TRANS ("No compatible plug-in format exists for this plug-in"); | |||
| return nullptr; | |||
| return {}; | |||
| } | |||
| bool AudioPluginFormatManager::doesPluginStillExist (const PluginDescription& description) const | |||
| @@ -45,30 +45,25 @@ public: | |||
| ~AudioPluginFormatManager(); | |||
| //============================================================================== | |||
| /** Adds any formats that it knows about, e.g. VST. | |||
| */ | |||
| /** Adds the set of available standard formats, e.g. VST. */ | |||
| void addDefaultFormats(); | |||
| //============================================================================== | |||
| /** Returns the number of types of format that are available. | |||
| Use getFormat() to get one of them. | |||
| */ | |||
| int getNumFormats(); | |||
| /** Returns one of the available formats. | |||
| @see getNumFormats | |||
| */ | |||
| AudioPluginFormat* getFormat (int index); | |||
| //============================================================================== | |||
| /** Adds a format to the list. | |||
| The object passed in will be owned and deleted by the manager. | |||
| */ | |||
| void addFormat (AudioPluginFormat* format); | |||
| void addFormat (AudioPluginFormat*); | |||
| //============================================================================== | |||
| /** Tries to load the type for this description, by trying all the formats | |||
| @@ -84,10 +79,9 @@ public: | |||
| thread other than the message thread and without blocking the message | |||
| thread. | |||
| */ | |||
| AudioPluginInstance* createPluginInstance (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| String& errorMessage) const; | |||
| std::unique_ptr<AudioPluginInstance> createPluginInstance (const PluginDescription& description, | |||
| double initialSampleRate, int initialBufferSize, | |||
| String& errorMessage) const; | |||
| /** Tries to asynchronously load the type for this description, by trying | |||
| all the formats that this manager knows about. | |||
| @@ -112,24 +106,16 @@ public: | |||
| from an auxiliary thread. | |||
| */ | |||
| void createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| AudioPluginFormat::InstantiationCompletionCallback* callback); | |||
| void createPluginInstanceAsync (const PluginDescription& description, | |||
| double initialSampleRate, | |||
| int initialBufferSize, | |||
| std::function<void(AudioPluginInstance*, const String&)> completionCallback); | |||
| double initialSampleRate, int initialBufferSize, | |||
| AudioPluginFormat::PluginCreationCallback callback); | |||
| /** Checks that the file or component for this plugin actually still exists. | |||
| (This won't try to load the plugin) | |||
| */ | |||
| bool doesPluginStillExist (const PluginDescription& description) const; | |||
| bool doesPluginStillExist (const PluginDescription&) const; | |||
| private: | |||
| //============================================================================== | |||
| //@internal | |||
| AudioPluginFormat* findFormatForDescription (const PluginDescription&, String& errorMessage) const; | |||
| OwnedArray<AudioPluginFormat> formats; | |||
| @@ -57,7 +57,7 @@ private: | |||
| //============================================================================== | |||
| void createPluginInstance (const PluginDescription&, | |||
| double initialSampleRate, int initialBufferSize, | |||
| void* userData, PluginCreationCallback) override; | |||
| PluginCreationCallback) override; | |||
| bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; | |||
| @@ -2637,9 +2637,9 @@ void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& | |||
| try | |||
| { | |||
| std::unique_ptr<AudioPluginInstance> createdInstance (createInstanceFromDescription (desc, 44100.0, 512)); | |||
| auto createdInstance = createInstanceFromDescription (desc, 44100.0, 512); | |||
| if (AudioUnitPluginInstance* auInstance = dynamic_cast<AudioUnitPluginInstance*> (createdInstance.get())) | |||
| if (auto auInstance = dynamic_cast<AudioUnitPluginInstance*> (createdInstance.get())) | |||
| results.add (new PluginDescription (auInstance->getPluginDescription())); | |||
| } | |||
| catch (...) | |||
| @@ -2650,13 +2650,12 @@ void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& | |||
| void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| double rate, int blockSize, | |||
| void* userData, PluginCreationCallback callback) | |||
| PluginCreationCallback callback) | |||
| { | |||
| using namespace AudioUnitFormatHelpers; | |||
| if (fileMightContainThisPluginType (desc.fileOrIdentifier)) | |||
| { | |||
| String pluginName, version, manufacturer; | |||
| AudioComponentDescription componentDesc; | |||
| AudioComponent auComponent; | |||
| @@ -2665,19 +2664,19 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| if ((! getComponentDescFromIdentifier (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer)) | |||
| && (! getComponentDescFromFile (desc.fileOrIdentifier, componentDesc, pluginName, version, manufacturer))) | |||
| { | |||
| callback (userData, nullptr, errMessage); | |||
| callback (nullptr, errMessage); | |||
| return; | |||
| } | |||
| if ((auComponent = AudioComponentFindNext (nullptr, &componentDesc)) == nullptr) | |||
| { | |||
| callback (userData, nullptr, errMessage); | |||
| callback (nullptr, errMessage); | |||
| return; | |||
| } | |||
| if (AudioComponentGetDescription (auComponent, &componentDesc) != noErr) | |||
| { | |||
| callback (userData, nullptr, errMessage); | |||
| callback (nullptr, errMessage); | |||
| return; | |||
| } | |||
| @@ -2688,9 +2687,9 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| #endif | |||
| AUAsyncInitializationCallback (double inSampleRate, int inFramesPerBuffer, | |||
| void* inUserData, PluginCreationCallback inOriginalCallback) | |||
| PluginCreationCallback inOriginalCallback) | |||
| : sampleRate (inSampleRate), framesPerBuffer (inFramesPerBuffer), | |||
| passUserData (inUserData), originalCallback (inOriginalCallback) | |||
| originalCallback (std::move (inOriginalCallback)) | |||
| { | |||
| #if JUCE_SUPPORTS_AUv3 | |||
| block = CreateObjCBlock (this, &AUAsyncInitializationCallback::completion); | |||
| @@ -2708,15 +2707,14 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| std::unique_ptr<AudioUnitPluginInstance> instance (new AudioUnitPluginInstance (audioUnit)); | |||
| if (instance->initialise (sampleRate, framesPerBuffer)) | |||
| originalCallback (passUserData, instance.release(), StringRef()); | |||
| originalCallback (std::move (instance), {}); | |||
| else | |||
| originalCallback (passUserData, nullptr, | |||
| NEEDS_TRANS ("Unable to initialise the AudioUnit plug-in")); | |||
| originalCallback (nullptr, NEEDS_TRANS ("Unable to initialise the AudioUnit plug-in")); | |||
| } | |||
| else | |||
| { | |||
| String errMsg = NEEDS_TRANS ("An OS error occurred during initialisation of the plug-in (XXX)"); | |||
| originalCallback (passUserData, nullptr, errMsg.replace ("XXX", String (err))); | |||
| auto errMsg = TRANS ("An OS error occurred during initialisation of the plug-in (XXX)"); | |||
| originalCallback (nullptr, errMsg.replace ("XXX", String (err))); | |||
| } | |||
| delete this; | |||
| @@ -2724,7 +2722,6 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| double sampleRate; | |||
| int framesPerBuffer; | |||
| void* passUserData; | |||
| PluginCreationCallback originalCallback; | |||
| #if JUCE_SUPPORTS_AUv3 | |||
| @@ -2732,7 +2729,7 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| #endif | |||
| }; | |||
| auto callbackBlock = new AUAsyncInitializationCallback (rate, blockSize, userData, callback); | |||
| auto callbackBlock = new AUAsyncInitializationCallback (rate, blockSize, std::move (callback)); | |||
| #if JUCE_SUPPORTS_AUv3 | |||
| //============================================================================== | |||
| @@ -2753,7 +2750,7 @@ void AudioUnitPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| } | |||
| else | |||
| { | |||
| callback (userData, nullptr, NEEDS_TRANS ("Plug-in description is not an AudioUnit plug-in")); | |||
| callback (nullptr, NEEDS_TRANS ("Plug-in description is not an AudioUnit plug-in")); | |||
| } | |||
| } | |||
| @@ -586,7 +586,8 @@ void LADSPAPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& res | |||
| desc.fileOrIdentifier = fileOrIdentifier; | |||
| desc.uid = 0; | |||
| std::unique_ptr<LADSPAPluginInstance> instance (dynamic_cast<LADSPAPluginInstance*> (createInstanceFromDescription (desc, 44100.0, 512))); | |||
| auto createdInstance = createInstanceFromDescription (desc, 44100.0, 512); | |||
| auto instance = dynamic_cast<LADSPAPluginInstance*> (createdInstance.get()); | |||
| if (instance == nullptr || ! instance->isValid()) | |||
| return; | |||
| @@ -616,7 +617,7 @@ void LADSPAPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& res | |||
| void LADSPAPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| double sampleRate, int blockSize, | |||
| void* userData, PluginCreationCallback callback) | |||
| PluginCreationCallback callback) | |||
| { | |||
| std::unique_ptr<LADSPAPluginInstance> result; | |||
| @@ -647,9 +648,9 @@ void LADSPAPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| String errorMsg; | |||
| if (result == nullptr) | |||
| errorMsg = String (NEEDS_TRANS ("Unable to load XXX plug-in file")).replace ("XXX", "LADSPA"); | |||
| errorMsg = TRANS ("Unable to load XXX plug-in file").replace ("XXX", "LADSPA"); | |||
| callback (userData, result.release(), errorMsg); | |||
| callback (std::move (result), errorMsg); | |||
| } | |||
| bool LADSPAPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept | |||
| @@ -55,7 +55,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| void createPluginInstance (const PluginDescription&, double initialSampleRate, | |||
| int initialBufferSize, void* userData, PluginCreationCallback) override; | |||
| int initialBufferSize, PluginCreationCallback) override; | |||
| bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; | |||
| @@ -3078,8 +3078,8 @@ void VST3PluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& resul | |||
| VST3ModuleHandle::getAllDescriptionsForFile (results, fileOrIdentifier); | |||
| } | |||
| void VST3PluginFormat::createPluginInstance (const PluginDescription& description, double, int, | |||
| void* userData, PluginCreationCallback callback) | |||
| void VST3PluginFormat::createPluginInstance (const PluginDescription& description, | |||
| double, int, PluginCreationCallback callback) | |||
| { | |||
| std::unique_ptr<VST3PluginInstance> result; | |||
| @@ -3109,9 +3109,9 @@ void VST3PluginFormat::createPluginInstance (const PluginDescription& descriptio | |||
| String errorMsg; | |||
| if (result == nullptr) | |||
| errorMsg = String (NEEDS_TRANS ("Unable to load XXX plug-in file")).replace ("XXX", "VST-3"); | |||
| errorMsg = TRANS ("Unable to load XXX plug-in file").replace ("XXX", "VST-3"); | |||
| callback (userData, result.release(), errorMsg); | |||
| callback (std::move (result), errorMsg); | |||
| } | |||
| bool VST3PluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept | |||
| @@ -63,7 +63,7 @@ public: | |||
| private: | |||
| void createPluginInstance (const PluginDescription&, double initialSampleRate, | |||
| int initialBufferSize, void* userData, PluginCreationCallback) override; | |||
| int initialBufferSize, PluginCreationCallback) override; | |||
| bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; | |||
| @@ -3498,11 +3498,11 @@ static pointer_sized_int VSTCALLBACK audioMaster (Vst2::AEffect* effect, int32 o | |||
| VSTPluginFormat::VSTPluginFormat() {} | |||
| VSTPluginFormat::~VSTPluginFormat() {} | |||
| static VSTPluginInstance* createAndUpdateDesc (VSTPluginFormat& format, PluginDescription& desc) | |||
| static std::unique_ptr<VSTPluginInstance> createAndUpdateDesc (VSTPluginFormat& format, PluginDescription& desc) | |||
| { | |||
| if (auto* p = format.createInstanceFromDescription (desc, 44100.0, 512)) | |||
| if (auto p = format.createInstanceFromDescription (desc, 44100.0, 512)) | |||
| { | |||
| if (auto* instance = dynamic_cast<VSTPluginInstance*> (p)) | |||
| if (auto instance = dynamic_cast<VSTPluginInstance*> (p.release())) | |||
| { | |||
| #if JUCE_MAC | |||
| if (instance->vstModule->resFileId != 0) | |||
| @@ -3510,13 +3510,13 @@ static VSTPluginInstance* createAndUpdateDesc (VSTPluginFormat& format, PluginDe | |||
| #endif | |||
| instance->fillInPluginDescription (desc); | |||
| return instance; | |||
| return std::unique_ptr<VSTPluginInstance> (instance); | |||
| } | |||
| jassertfalse; | |||
| } | |||
| return nullptr; | |||
| return {}; | |||
| } | |||
| void VSTPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& results, | |||
| @@ -3529,7 +3529,7 @@ void VSTPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& result | |||
| desc.fileOrIdentifier = fileOrIdentifier; | |||
| desc.uid = 0; | |||
| std::unique_ptr<VSTPluginInstance> instance (createAndUpdateDesc (*this, desc)); | |||
| auto instance = createAndUpdateDesc (*this, desc); | |||
| if (instance == nullptr) | |||
| return; | |||
| @@ -3574,7 +3574,7 @@ void VSTPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& result | |||
| void VSTPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| double sampleRate, int blockSize, | |||
| void* userData, PluginCreationCallback callback) | |||
| PluginCreationCallback callback) | |||
| { | |||
| std::unique_ptr<VSTPluginInstance> result; | |||
| @@ -3601,9 +3601,9 @@ void VSTPluginFormat::createPluginInstance (const PluginDescription& desc, | |||
| String errorMsg; | |||
| if (result == nullptr) | |||
| errorMsg = String (NEEDS_TRANS ("Unable to load XXX plug-in file")).replace ("XXX", "VST-2"); | |||
| errorMsg = TRANS ("Unable to load XXX plug-in file").replace ("XXX", "VST-2"); | |||
| callback (userData, result.release(), errorMsg); | |||
| callback (std::move (result), errorMsg); | |||
| } | |||
| bool VSTPluginFormat::requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept | |||
| @@ -118,7 +118,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| void createPluginInstance (const PluginDescription&, double initialSampleRate, | |||
| int initialBufferSize, void* userData, PluginCreationCallback) override; | |||
| int initialBufferSize, PluginCreationCallback) override; | |||
| bool requiresUnblockedMessageThreadDuringCreation (const PluginDescription&) const noexcept override; | |||
| @@ -797,8 +797,8 @@ bool AudioProcessorGraph::Connection::operator< (const Connection& other) const | |||
| } | |||
| //============================================================================== | |||
| AudioProcessorGraph::Node::Node (NodeID n, AudioProcessor* p) noexcept | |||
| : nodeID (n), processor (p) | |||
| AudioProcessorGraph::Node::Node (NodeID n, std::unique_ptr<AudioProcessor> p) noexcept | |||
| : nodeID (n), processor (std::move (p)) | |||
| { | |||
| jassert (processor != nullptr); | |||
| } | |||
| @@ -914,9 +914,9 @@ AudioProcessorGraph::Node* AudioProcessorGraph::getNodeForId (NodeID nodeID) con | |||
| return {}; | |||
| } | |||
| AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (AudioProcessor* newProcessor, NodeID nodeID) | |||
| AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (std::unique_ptr<AudioProcessor> newProcessor, NodeID nodeID) | |||
| { | |||
| if (newProcessor == nullptr || newProcessor == this) | |||
| if (newProcessor == nullptr || newProcessor.get() == this) | |||
| { | |||
| jassertfalse; | |||
| return {}; | |||
| @@ -927,7 +927,7 @@ AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (AudioProcessor* new | |||
| for (auto* n : nodes) | |||
| { | |||
| if (n->getProcessor() == newProcessor || n->nodeID == nodeID) | |||
| if (n->getProcessor() == newProcessor.get() || n->nodeID == nodeID) | |||
| { | |||
| jassertfalse; // Cannot add two copies of the same processor, or duplicate node IDs! | |||
| return {}; | |||
| @@ -939,7 +939,7 @@ AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (AudioProcessor* new | |||
| newProcessor->setPlayHead (getPlayHead()); | |||
| Node::Ptr n (new Node (nodeID, newProcessor)); | |||
| Node::Ptr n (new Node (nodeID, std::move (newProcessor))); | |||
| nodes.add (n.get()); | |||
| n->setParentGraph (this); | |||
| topologyChanged(); | |||
| @@ -145,7 +145,7 @@ public: | |||
| Array<Connection> inputs, outputs; | |||
| bool isPrepared = false, bypassed = false; | |||
| Node (NodeID, AudioProcessor*) noexcept; | |||
| Node (NodeID, std::unique_ptr<AudioProcessor>) noexcept; | |||
| void setParentGraph (AudioProcessorGraph*) const; | |||
| void prepare (double newSampleRate, int newBlockSize, AudioProcessorGraph*, ProcessingPrecision); | |||
| @@ -214,7 +214,7 @@ public: | |||
| If this succeeds, it returns a pointer to the newly-created node. | |||
| */ | |||
| Node::Ptr addNode (AudioProcessor* newProcessor, NodeID nodeId = {}); | |||
| Node::Ptr addNode (std::unique_ptr<AudioProcessor> newProcessor, NodeID nodeId = {}); | |||
| /** Deletes a node within the graph which has the specified ID. | |||
| This will also delete any connections that are attached to this node. | |||
| @@ -95,7 +95,7 @@ public: | |||
| withParameter() method, then the string will have these appended on the | |||
| end and url-encoded. | |||
| */ | |||
| String getSubPath (bool includeGetParamters = false) const; | |||
| String getSubPath (bool includeGetParameters = false) const; | |||
| /** If any parameters are set, returns these URL encoded, including the "?" | |||
| * prefix. | |||