mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Move files without UI dependencies to juce_audio_processors_headless
This commit is contained in:
parent
1f5d09d3fc
commit
407cc5b004
73 changed files with 115 additions and 80 deletions
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
PluginDescription AudioPluginInstance::getPluginDescription() const
|
||||
{
|
||||
PluginDescription desc;
|
||||
fillInPluginDescription (desc);
|
||||
return desc;
|
||||
}
|
||||
|
||||
void* AudioPluginInstance::getPlatformSpecificData() { return nullptr; }
|
||||
|
||||
void AudioPluginInstance::getExtensions (ExtensionsVisitor& visitor) const { visitor.visitUnknown ({}); }
|
||||
|
||||
String AudioPluginInstance::getParameterID (int parameterIndex)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
// Currently there is no corresponding method available in the
|
||||
// AudioProcessorParameter class, and the previous behaviour of JUCE's
|
||||
// plug-in hosting code simply returns a string version of the index; to
|
||||
// maintain backwards compatibility you should perform the operation below
|
||||
// this comment. However the caveat is that for plug-ins which change their
|
||||
// number of parameters dynamically at runtime you cannot rely upon the
|
||||
// returned parameter ID mapping to the correct parameter. A comprehensive
|
||||
// solution to this problem requires some additional work in JUCE's hosting
|
||||
// code.
|
||||
return String (parameterIndex);
|
||||
}
|
||||
|
||||
float AudioPluginInstance::getParameter (int parameterIndex)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getValue();
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void AudioPluginInstance::setParameter (int parameterIndex, float newValue)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
param->setValue (newValue);
|
||||
}
|
||||
|
||||
const String AudioPluginInstance::getParameterName (int parameterIndex)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getName (1024);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String AudioPluginInstance::getParameterName (int parameterIndex, int maximumStringLength)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getName (maximumStringLength);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const String AudioPluginInstance::getParameterText (int parameterIndex)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getCurrentValueAsText();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String AudioPluginInstance::getParameterText (int parameterIndex, int maximumStringLength)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getCurrentValueAsText().substring (0, maximumStringLength);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
float AudioPluginInstance::getParameterDefaultValue (int parameterIndex)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getDefaultValue();
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
int AudioPluginInstance::getParameterNumSteps (int parameterIndex)
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getNumSteps();
|
||||
|
||||
return AudioProcessor::getDefaultNumParameterSteps();
|
||||
}
|
||||
|
||||
bool AudioPluginInstance::isParameterDiscrete (int parameterIndex) const
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->isDiscrete();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioPluginInstance::isParameterAutomatable (int parameterIndex) const
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->isAutomatable();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String AudioPluginInstance::getParameterLabel (int parameterIndex) const
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getLabel();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool AudioPluginInstance::isParameterOrientationInverted (int parameterIndex) const
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->isOrientationInverted();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioPluginInstance::isMetaParameter (int parameterIndex) const
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->isMetaParameter();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AudioProcessorParameter::Category AudioPluginInstance::getParameterCategory (int parameterIndex) const
|
||||
{
|
||||
assertOnceOnDeprecatedMethodUse();
|
||||
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
return param->getCategory();
|
||||
|
||||
return AudioProcessorParameter::genericParameter;
|
||||
}
|
||||
|
||||
void AudioPluginInstance::assertOnceOnDeprecatedMethodUse() const noexcept
|
||||
{
|
||||
if (! deprecationAssertiontriggered)
|
||||
{
|
||||
// If you hit this assertion then you are using at least one of the
|
||||
// methods marked as deprecated in this class. For now you can simply
|
||||
// continue past this point and subsequent uses of deprecated methods
|
||||
// will not trigger additional assertions. However, we will shortly be
|
||||
// removing these methods so you are strongly advised to look at the
|
||||
// implementation of the corresponding method in this class and use
|
||||
// that approach instead.
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
deprecationAssertiontriggered = true;
|
||||
}
|
||||
|
||||
bool AudioPluginInstance::deprecationAssertiontriggered = false;
|
||||
|
||||
AudioPluginInstance::Parameter::Parameter()
|
||||
: onStrings { TRANS ("on"), TRANS ("yes"), TRANS ("true") },
|
||||
offStrings { TRANS ("off"), TRANS ("no"), TRANS ("false") }
|
||||
{
|
||||
}
|
||||
|
||||
String AudioPluginInstance::Parameter::getText (float value, int maximumStringLength) const
|
||||
{
|
||||
if (isBoolean())
|
||||
return value < 0.5f ? TRANS ("Off") : TRANS ("On");
|
||||
|
||||
return String (value).substring (0, maximumStringLength);
|
||||
}
|
||||
|
||||
float AudioPluginInstance::Parameter::getValueForText (const String& text) const
|
||||
{
|
||||
auto floatValue = text.retainCharacters ("-0123456789.").getFloatValue();
|
||||
|
||||
if (isBoolean())
|
||||
{
|
||||
if (onStrings.contains (text, true))
|
||||
return 1.0f;
|
||||
|
||||
if (offStrings.contains (text, true))
|
||||
return 0.0f;
|
||||
|
||||
return floatValue < 0.5f ? 0.0f : 1.0f;
|
||||
}
|
||||
|
||||
return floatValue;
|
||||
}
|
||||
|
||||
void AudioPluginInstance::addHostedParameter (std::unique_ptr<HostedParameter> param)
|
||||
{
|
||||
addParameter (param.release());
|
||||
}
|
||||
|
||||
void AudioPluginInstance::addHostedParameterGroup (std::unique_ptr<AudioProcessorParameterGroup> group)
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
// All parameters *must* be HostedParameters, otherwise getHostedParameter will return
|
||||
// garbage and your host will crash and burn
|
||||
for (auto* param : group->getParameters (true))
|
||||
{
|
||||
jassertquiet (dynamic_cast<HostedParameter*> (param) != nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
addParameterGroup (std::move (group));
|
||||
}
|
||||
|
||||
void AudioPluginInstance::setHostedParameterTree (AudioProcessorParameterGroup group)
|
||||
{
|
||||
#if JUCE_DEBUG
|
||||
// All parameters *must* be HostedParameters, otherwise getHostedParameter will return
|
||||
// garbage and your host will crash and burn
|
||||
for (auto* param : group.getParameters (true))
|
||||
{
|
||||
jassertquiet (dynamic_cast<HostedParameter*> (param) != nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
setParameterTree (std::move (group));
|
||||
}
|
||||
|
||||
AudioPluginInstance::HostedParameter* AudioPluginInstance::getHostedParameter (int index) const
|
||||
{
|
||||
// It's important that all AudioPluginInstance implementations
|
||||
// only ever own HostedParameters!
|
||||
return static_cast<HostedParameter*> (getParameters()[index]);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
// MSVC does not like it if you override a deprecated method even if you
|
||||
// keep the deprecation attribute. Other compilers are more forgiving.
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for an active instance of a plugin.
|
||||
|
||||
This derives from the AudioProcessor class, and adds some extra functionality
|
||||
that helps when wrapping dynamically loaded plugins.
|
||||
|
||||
This class is not needed when writing plugins, and you should never need to derive
|
||||
your own sub-classes from it. The plugin hosting classes use it internally and will
|
||||
return AudioPluginInstance objects which wrap external plugins.
|
||||
|
||||
@see AudioProcessor, AudioPluginFormat
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioPluginInstance : public AudioProcessor
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor.
|
||||
|
||||
Make sure that you delete any UI components that belong to this plugin before
|
||||
deleting the plugin.
|
||||
*/
|
||||
~AudioPluginInstance() override = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Fills-in the appropriate parts of this plugin description object. */
|
||||
virtual void fillInPluginDescription (PluginDescription&) const = 0;
|
||||
|
||||
/** Returns a PluginDescription for this plugin.
|
||||
This is just a convenience method to avoid calling fillInPluginDescription.
|
||||
*/
|
||||
PluginDescription getPluginDescription() const;
|
||||
|
||||
/** Allows retrieval of information related to the inner workings of a particular plugin format,
|
||||
such as the AEffect* of a VST, or the handle of an AudioUnit.
|
||||
|
||||
To use this, create a new class derived from ExtensionsVisitor, and override
|
||||
each of the visit member functions. If this AudioPluginInstance wraps a VST3 plugin
|
||||
the visitVST3() member will be called, while if the AudioPluginInstance wraps an
|
||||
unknown format the visitUnknown() member will be called. The argument of the visit function
|
||||
can be queried to extract information related to the AudioPluginInstance's implementation.
|
||||
*/
|
||||
virtual void getExtensions (ExtensionsVisitor&) const;
|
||||
|
||||
using HostedParameter = HostedAudioProcessorParameter;
|
||||
|
||||
/** Adds a parameter to this instance.
|
||||
|
||||
@see AudioProcessor::addParameter()
|
||||
*/
|
||||
void addHostedParameter (std::unique_ptr<HostedParameter>);
|
||||
|
||||
/** Adds multiple parameters to this instance.
|
||||
|
||||
In debug mode, this will also check that all added parameters derive from
|
||||
HostedParameter.
|
||||
|
||||
@see AudioProcessor::addParameterGroup()
|
||||
*/
|
||||
void addHostedParameterGroup (std::unique_ptr<AudioProcessorParameterGroup>);
|
||||
|
||||
/** Adds multiple parameters to this instance.
|
||||
|
||||
In debug mode, this will also check that all added parameters derive from
|
||||
HostedParameter.
|
||||
|
||||
@see AudioProcessor::setParameterTree()
|
||||
*/
|
||||
void setHostedParameterTree (AudioProcessorParameterGroup);
|
||||
|
||||
/** Gets the parameter at a particular index.
|
||||
|
||||
If you want to find lots of parameters by their IDs, you should probably build and
|
||||
use a map<String, HostedParameter*> by looping through all parameters.
|
||||
*/
|
||||
HostedParameter* getHostedParameter (int index) const;
|
||||
|
||||
/** @cond */
|
||||
/** Use the new typesafe visitor-based interface rather than this function.
|
||||
|
||||
Returns a pointer to some kind of platform-specific data about the plugin.
|
||||
E.g. For a VST, this value can be cast to an AEffect*. For an AudioUnit, it can be
|
||||
cast to an AudioUnit handle.
|
||||
*/
|
||||
[[deprecated ("Use the new typesafe visitor-based interface rather than this function.")]]
|
||||
virtual void* getPlatformSpecificData();
|
||||
|
||||
// Rather than using these methods you should call the corresponding methods
|
||||
// on the AudioProcessorParameter objects returned from getParameters().
|
||||
// See the implementations of the methods below for some examples of how to
|
||||
// do this.
|
||||
//
|
||||
// In addition to being marked as deprecated these methods will assert on
|
||||
// the first call.
|
||||
[[deprecated]] String getParameterID (int index) override;
|
||||
[[deprecated]] float getParameter (int parameterIndex) override;
|
||||
[[deprecated]] void setParameter (int parameterIndex, float newValue) override;
|
||||
[[deprecated]] const String getParameterName (int parameterIndex) override;
|
||||
[[deprecated]] String getParameterName (int parameterIndex, int maximumStringLength) override;
|
||||
[[deprecated]] const String getParameterText (int parameterIndex) override;
|
||||
[[deprecated]] String getParameterText (int parameterIndex, int maximumStringLength) override;
|
||||
[[deprecated]] int getParameterNumSteps (int parameterIndex) override;
|
||||
[[deprecated]] bool isParameterDiscrete (int parameterIndex) const override;
|
||||
[[deprecated]] bool isParameterAutomatable (int parameterIndex) const override;
|
||||
[[deprecated]] float getParameterDefaultValue (int parameterIndex) override;
|
||||
[[deprecated]] String getParameterLabel (int parameterIndex) const override;
|
||||
[[deprecated]] bool isParameterOrientationInverted (int parameterIndex) const override;
|
||||
[[deprecated]] bool isMetaParameter (int parameterIndex) const override;
|
||||
[[deprecated]] AudioProcessorParameter::Category getParameterCategory (int parameterIndex) const override;
|
||||
/** @endcond */
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Structure used to describe plugin parameters */
|
||||
struct Parameter : public HostedParameter
|
||||
{
|
||||
public:
|
||||
Parameter();
|
||||
|
||||
String getText (float value, int maximumStringLength) const override;
|
||||
float getValueForText (const String& text) const override;
|
||||
|
||||
private:
|
||||
const StringArray onStrings, offStrings;
|
||||
};
|
||||
|
||||
AudioPluginInstance() = default;
|
||||
AudioPluginInstance (const BusesProperties& ioLayouts) : AudioProcessor (ioLayouts) {}
|
||||
template <size_t numLayouts>
|
||||
AudioPluginInstance (const short channelLayoutList[numLayouts][2]) : AudioProcessor (channelLayoutList) {}
|
||||
|
||||
private:
|
||||
// It's not safe to add a plain AudioProcessorParameter to an AudioPluginInstance.
|
||||
// Instead, all parameters must be HostedParameters.
|
||||
using AudioProcessor::addParameter;
|
||||
using AudioProcessor::addParameterGroup;
|
||||
using AudioProcessor::setParameterTree;
|
||||
|
||||
void assertOnceOnDeprecatedMethodUse() const noexcept;
|
||||
|
||||
static bool deprecationAssertiontriggered;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginInstance)
|
||||
};
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
} // namespace juce
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,472 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A type of AudioProcessor which plays back a graph of other AudioProcessors.
|
||||
|
||||
Use one of these objects if you want to wire-up a set of AudioProcessors
|
||||
and play back the result.
|
||||
|
||||
Processors can be added to the graph as "nodes" using addNode(), and once
|
||||
added, you can connect any of their input or output channels to other
|
||||
nodes using addConnection().
|
||||
|
||||
To play back a graph through an audio device, you might want to use an
|
||||
AudioProcessorPlayer object.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorGraph : public AudioProcessor,
|
||||
public ChangeBroadcaster
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty graph. */
|
||||
AudioProcessorGraph();
|
||||
|
||||
/** Destructor.
|
||||
Any processor objects that have been added to the graph will also be deleted.
|
||||
*/
|
||||
~AudioProcessorGraph() override;
|
||||
|
||||
/** Each node in the graph has a UID of this type. */
|
||||
struct NodeID
|
||||
{
|
||||
constexpr NodeID() = default;
|
||||
explicit constexpr NodeID (uint32 i) : uid (i) {}
|
||||
|
||||
uint32 uid = 0;
|
||||
|
||||
constexpr bool operator== (const NodeID& other) const noexcept { return uid == other.uid; }
|
||||
constexpr bool operator!= (const NodeID& other) const noexcept { return uid != other.uid; }
|
||||
constexpr bool operator< (const NodeID& other) const noexcept { return uid < other.uid; }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** A special index that represents the midi channel of a node.
|
||||
|
||||
This is used as a channel index value if you want to refer to the midi input
|
||||
or output instead of an audio channel.
|
||||
*/
|
||||
enum { midiChannelIndex = 0x1000 };
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents an input or output channel of a node in an AudioProcessorGraph.
|
||||
*/
|
||||
class NodeAndChannel
|
||||
{
|
||||
constexpr auto tie() const { return std::tie (nodeID, channelIndex); }
|
||||
|
||||
public:
|
||||
NodeID nodeID;
|
||||
int channelIndex;
|
||||
|
||||
constexpr bool isMIDI() const noexcept { return channelIndex == midiChannelIndex; }
|
||||
|
||||
constexpr bool operator== (const NodeAndChannel& other) const noexcept { return tie() == other.tie(); }
|
||||
constexpr bool operator!= (const NodeAndChannel& other) const noexcept { return tie() != other.tie(); }
|
||||
constexpr bool operator< (const NodeAndChannel& other) const noexcept { return tie() < other.tie(); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Represents one of the nodes, or processors, in an AudioProcessorGraph.
|
||||
|
||||
To create a node, call AudioProcessorGraph::addNode().
|
||||
*/
|
||||
class JUCE_API Node : public ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** The ID number assigned to this node.
|
||||
This is assigned by the graph that owns it, and can't be changed.
|
||||
*/
|
||||
const NodeID nodeID;
|
||||
|
||||
/** The actual processor object that this node represents. */
|
||||
AudioProcessor* getProcessor() const noexcept { return processor.get(); }
|
||||
|
||||
/** A set of user-definable properties that are associated with this node.
|
||||
|
||||
This can be used to attach values to the node for whatever purpose seems
|
||||
useful. For example, you might store an x and y position if your application
|
||||
is displaying the nodes on-screen.
|
||||
*/
|
||||
NamedValueSet properties;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns if the node is bypassed or not. */
|
||||
bool isBypassed() const noexcept
|
||||
{
|
||||
if (processor != nullptr)
|
||||
{
|
||||
if (auto* bypassParam = processor->getBypassParameter())
|
||||
return ! approximatelyEqual (bypassParam->getValue(), 0.0f);
|
||||
}
|
||||
|
||||
return bypassed;
|
||||
}
|
||||
|
||||
/** Tell this node to bypass processing. */
|
||||
void setBypassed (bool shouldBeBypassed) noexcept
|
||||
{
|
||||
if (processor != nullptr)
|
||||
{
|
||||
if (auto* bypassParam = processor->getBypassParameter())
|
||||
bypassParam->setValueNotifyingHost (shouldBeBypassed ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
bypassed = shouldBeBypassed;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A convenient typedef for referring to a pointer to a node object. */
|
||||
using Ptr = ReferenceCountedObjectPtr<Node>;
|
||||
|
||||
/** @internal
|
||||
|
||||
Returns true if setBypassed (true) was called on this node.
|
||||
This behaviour is different from isBypassed(), which may additionally return true if
|
||||
the node has a bypass parameter that is not set to 0.
|
||||
*/
|
||||
bool userRequestedBypass() const { return bypassed; }
|
||||
|
||||
/** @internal
|
||||
|
||||
To create a new node, use AudioProcessorGraph::addNode.
|
||||
*/
|
||||
Node (NodeID n, std::unique_ptr<AudioProcessor> p) noexcept
|
||||
: nodeID (n), processor (std::move (p))
|
||||
{
|
||||
jassert (processor != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::unique_ptr<AudioProcessor> processor;
|
||||
std::atomic<bool> bypassed { false };
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Represents a connection between two channels of two nodes in an AudioProcessorGraph.
|
||||
|
||||
To create a connection, use AudioProcessorGraph::addConnection().
|
||||
*/
|
||||
struct JUCE_API Connection
|
||||
{
|
||||
//==============================================================================
|
||||
constexpr Connection() = default;
|
||||
constexpr Connection (NodeAndChannel sourceIn, NodeAndChannel destinationIn) noexcept
|
||||
: source (sourceIn), destination (destinationIn) {}
|
||||
|
||||
constexpr Connection (const Connection&) = default;
|
||||
constexpr Connection& operator= (const Connection&) = default;
|
||||
|
||||
constexpr bool operator== (const Connection& other) const noexcept
|
||||
{
|
||||
return source == other.source && destination == other.destination;
|
||||
}
|
||||
|
||||
constexpr bool operator!= (const Connection& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
constexpr bool operator< (const Connection& other) const noexcept
|
||||
{
|
||||
const auto tie = [] (auto& x)
|
||||
{
|
||||
return std::tie (x.source.nodeID,
|
||||
x.destination.nodeID,
|
||||
x.source.channelIndex,
|
||||
x.destination.channelIndex);
|
||||
};
|
||||
return tie (*this) < tie (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** The channel and node which is the input source for this connection. */
|
||||
NodeAndChannel source { {}, 0 };
|
||||
|
||||
/** The channel and node which is the input source for this connection. */
|
||||
NodeAndChannel destination { {}, 0 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Indicates how the graph should be updated after a change.
|
||||
|
||||
If you need to make lots of changes to a graph (e.g. lots of separate calls
|
||||
to addNode, addConnection etc.) you can avoid rebuilding the graph on each
|
||||
change by using the async update kind.
|
||||
*/
|
||||
enum class UpdateKind
|
||||
{
|
||||
sync, ///< Graph should be rebuilt immediately after modification.
|
||||
async, ///< Graph rebuild should be delayed. If you make several changes to the graph
|
||||
///< inside the same call stack, these changes will be applied in one go.
|
||||
none ///< Graph should not be rebuilt automatically. Use rebuild() to trigger a graph
|
||||
///< rebuild.
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Deletes all nodes and connections from this graph.
|
||||
Any processor objects in the graph will be deleted.
|
||||
*/
|
||||
void clear (UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Returns the array of nodes in the graph. */
|
||||
const ReferenceCountedArray<Node>& getNodes() const noexcept;
|
||||
|
||||
/** Returns the number of nodes in the graph. */
|
||||
int getNumNodes() const noexcept { return getNodes().size(); }
|
||||
|
||||
/** Returns a pointer to one of the nodes in the graph.
|
||||
This will return nullptr if the index is out of range.
|
||||
@see getNodeForId
|
||||
*/
|
||||
Node::Ptr getNode (int index) const noexcept { return getNodes()[index]; }
|
||||
|
||||
/** Searches the graph for a node with the given ID number and returns it.
|
||||
If no such node was found, this returns nullptr.
|
||||
@see getNode
|
||||
*/
|
||||
Node* getNodeForId (NodeID) const;
|
||||
|
||||
/** Adds a node to the graph.
|
||||
|
||||
This creates a new node in the graph, for the specified processor. Once you have
|
||||
added a processor to the graph, the graph owns it and will delete it later when
|
||||
it is no longer needed.
|
||||
|
||||
The optional nodeId parameter lets you specify a unique ID to use for the node.
|
||||
If the value is already in use, this method will fail and return an empty node.
|
||||
|
||||
If this succeeds, it returns a pointer to the newly-created node.
|
||||
*/
|
||||
Node::Ptr addNode (std::unique_ptr<AudioProcessor> newProcessor, std::optional<NodeID> nodeId = std::nullopt, UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Deletes a node within the graph which has the specified ID.
|
||||
This will also delete any connections that are attached to this node.
|
||||
*/
|
||||
Node::Ptr removeNode (NodeID, UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Deletes a node within the graph.
|
||||
This will also delete any connections that are attached to this node.
|
||||
*/
|
||||
Node::Ptr removeNode (Node*, UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Returns the list of connections in the graph. */
|
||||
std::vector<Connection> getConnections() const;
|
||||
|
||||
/** Returns true if the given connection exists. */
|
||||
bool isConnected (const Connection&) const noexcept;
|
||||
|
||||
/** Returns true if there is a direct connection between any of the channels of
|
||||
two specified nodes.
|
||||
*/
|
||||
bool isConnected (NodeID possibleSourceNodeID, NodeID possibleDestNodeID) const noexcept;
|
||||
|
||||
/** Does a recursive check to see if there's a direct or indirect series of connections
|
||||
between these two nodes.
|
||||
*/
|
||||
bool isAnInputTo (const Node& source, const Node& destination) const noexcept;
|
||||
|
||||
/** Does a recursive check to see if there's a direct or indirect series of connections
|
||||
between these two nodes.
|
||||
*/
|
||||
bool isAnInputTo (NodeID source, NodeID destination) const noexcept;
|
||||
|
||||
/** Returns true if it would be legal to connect the specified points. */
|
||||
bool canConnect (const Connection&) const;
|
||||
|
||||
/** Attempts to connect two specified channels of two nodes.
|
||||
|
||||
If this isn't allowed (e.g. because you're trying to connect a midi channel
|
||||
to an audio one or other such nonsense), then it'll return false.
|
||||
*/
|
||||
bool addConnection (const Connection&, UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Deletes the given connection. */
|
||||
bool removeConnection (const Connection&, UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Removes all connections from the specified node. */
|
||||
bool disconnectNode (NodeID, UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Returns true if the given connection's channel numbers map on to valid
|
||||
channels at each end.
|
||||
Even if a connection is valid when created, its status could change if
|
||||
a node changes its channel config.
|
||||
*/
|
||||
bool isConnectionLegal (const Connection&) const;
|
||||
|
||||
/** Performs a sanity checks of all the connections.
|
||||
|
||||
This might be useful if some of the processors are doing things like changing
|
||||
their channel counts, which could render some connections obsolete.
|
||||
*/
|
||||
bool removeIllegalConnections (UpdateKind = UpdateKind::sync);
|
||||
|
||||
/** Rebuilds the graph if necessary.
|
||||
|
||||
This function will only ever rebuild the graph on the main thread. If this function is
|
||||
called from another thread, the rebuild request will be dispatched asynchronously to the
|
||||
main thread.
|
||||
*/
|
||||
void rebuild();
|
||||
|
||||
//==============================================================================
|
||||
/** A special type of AudioProcessor that can live inside an AudioProcessorGraph
|
||||
in order to use the audio that comes into and out of the graph itself.
|
||||
|
||||
If you create an AudioGraphIOProcessor in "input" mode, it will act as a
|
||||
node in the graph which delivers the audio that is coming into the parent
|
||||
graph. This allows you to stream the data to other nodes and process the
|
||||
incoming audio.
|
||||
|
||||
Likewise, one of these in "output" mode can be sent data which it will add to
|
||||
the sum of data being sent to the graph's output.
|
||||
|
||||
@see AudioProcessorGraph
|
||||
*/
|
||||
class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance
|
||||
{
|
||||
public:
|
||||
/** Specifies the mode in which this processor will operate.
|
||||
*/
|
||||
enum IODeviceType
|
||||
{
|
||||
audioInputNode, /**< In this mode, the processor has output channels
|
||||
representing all the audio input channels that are
|
||||
coming into its parent audio graph. */
|
||||
audioOutputNode, /**< In this mode, the processor has input channels
|
||||
representing all the audio output channels that are
|
||||
going out of its parent audio graph. */
|
||||
midiInputNode, /**< In this mode, the processor has a midi output which
|
||||
delivers the same midi data that is arriving at its
|
||||
parent graph. */
|
||||
midiOutputNode /**< In this mode, the processor has a midi input and
|
||||
any data sent to it will be passed out of the parent
|
||||
graph. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the mode of this processor. */
|
||||
IODeviceType getType() const noexcept { return type; }
|
||||
|
||||
/** Returns the parent graph to which this processor belongs, or nullptr if it
|
||||
hasn't yet been added to one. */
|
||||
AudioProcessorGraph* getParentGraph() const noexcept { return graph; }
|
||||
|
||||
/** True if this is an audio or midi input. */
|
||||
bool isInput() const noexcept;
|
||||
/** True if this is an audio or midi output. */
|
||||
bool isOutput() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
AudioGraphIOProcessor (IODeviceType);
|
||||
~AudioGraphIOProcessor() override;
|
||||
|
||||
const String getName() const override;
|
||||
void fillInPluginDescription (PluginDescription&) const override;
|
||||
void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override;
|
||||
void releaseResources() override;
|
||||
void processBlock (AudioBuffer<float>& , MidiBuffer&) override;
|
||||
void processBlock (AudioBuffer<double>&, MidiBuffer&) override;
|
||||
bool supportsDoublePrecisionProcessing() const override;
|
||||
|
||||
double getTailLengthSeconds() const override;
|
||||
bool acceptsMidi() const override;
|
||||
bool producesMidi() const override;
|
||||
|
||||
bool hasEditor() const override;
|
||||
AudioProcessorEditor* createEditor() override;
|
||||
|
||||
int getNumPrograms() override;
|
||||
int getCurrentProgram() override;
|
||||
void setCurrentProgram (int) override;
|
||||
const String getProgramName (int) override;
|
||||
void changeProgramName (int, const String&) override;
|
||||
|
||||
void getStateInformation (juce::MemoryBlock& destData) override;
|
||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||
|
||||
/** @internal */
|
||||
void setParentGraph (AudioProcessorGraph*);
|
||||
|
||||
private:
|
||||
const IODeviceType type;
|
||||
AudioProcessorGraph* graph = nullptr;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioGraphIOProcessor)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
const String getName() const override;
|
||||
void prepareToPlay (double, int) override;
|
||||
void releaseResources() override;
|
||||
void processBlock (AudioBuffer<float>&, MidiBuffer&) override;
|
||||
void processBlock (AudioBuffer<double>&, MidiBuffer&) override;
|
||||
bool supportsDoublePrecisionProcessing() const override;
|
||||
|
||||
void reset() override;
|
||||
void setNonRealtime (bool) noexcept override;
|
||||
|
||||
double getTailLengthSeconds() const override;
|
||||
bool acceptsMidi() const override;
|
||||
bool producesMidi() const override;
|
||||
|
||||
bool hasEditor() const override { return false; }
|
||||
AudioProcessorEditor* createEditor() override { return nullptr; }
|
||||
int getNumPrograms() override { return 0; }
|
||||
int getCurrentProgram() override { return 0; }
|
||||
void setCurrentProgram (int) override { }
|
||||
const String getProgramName (int) override { return {}; }
|
||||
void changeProgramName (int, const String&) override { }
|
||||
void getStateInformation (juce::MemoryBlock&) override;
|
||||
void setStateInformation (const void* data, int sizeInBytes) override;
|
||||
|
||||
private:
|
||||
class Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorGraph)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {}
|
||||
void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class AudioProcessor;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for listeners that want to know about changes to an AudioProcessor.
|
||||
|
||||
Use AudioProcessor::addListener() to register your listener with an AudioProcessor.
|
||||
|
||||
@see AudioProcessor
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
virtual ~AudioProcessorListener() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Receives a callback when a parameter is changed.
|
||||
|
||||
IMPORTANT NOTE: This will be called synchronously when a parameter changes, and
|
||||
many audio processors will change their parameter during their audio callback.
|
||||
This means that not only has your handler code got to be completely thread-safe,
|
||||
but it's also got to be VERY fast, and avoid blocking. If you need to handle
|
||||
this event on your message thread, use this callback to trigger an AsyncUpdater
|
||||
or ChangeBroadcaster which you can respond to on the message thread.
|
||||
*/
|
||||
virtual void audioProcessorParameterChanged (AudioProcessor* processor,
|
||||
int parameterIndex,
|
||||
float newValue) = 0;
|
||||
|
||||
/** Provides details about aspects of an AudioProcessor which have changed.
|
||||
*/
|
||||
struct JUCE_API ChangeDetails
|
||||
{
|
||||
/** @see withLatencyChanged */
|
||||
bool latencyChanged = false;
|
||||
/** @see withParameterInfoChanged */
|
||||
bool parameterInfoChanged = false;
|
||||
/** @see withProgramChanged */
|
||||
bool programChanged = false;
|
||||
/** @see withNonParameterStateChanged */
|
||||
bool nonParameterStateChanged = false;
|
||||
|
||||
/** Indicates that the AudioProcessor's latency has changed.
|
||||
|
||||
Most of the time, you won't need to use this function directly.
|
||||
AudioProcessor::setLatencySamples() will automatically call
|
||||
AudioProcessor::updateHostDisplay(), indicating that the latency has changed.
|
||||
|
||||
@see latencyChanged
|
||||
*/
|
||||
[[nodiscard]] ChangeDetails withLatencyChanged (bool b) const noexcept { return with (&ChangeDetails::latencyChanged, b); }
|
||||
|
||||
/** Indicates that some attributes of the AudioProcessor's parameters have changed.
|
||||
|
||||
When this flag is set, the host should rescan the AudioProcessor's parameters, and
|
||||
update its controls to match. This is often used to update the names of a plugin's
|
||||
parameters in the host.
|
||||
|
||||
@see parameterInfoChanged
|
||||
*/
|
||||
[[nodiscard]] ChangeDetails withParameterInfoChanged (bool b) const noexcept { return with (&ChangeDetails::parameterInfoChanged, b); }
|
||||
|
||||
/** Indicates that the loaded program has changed.
|
||||
|
||||
When this flag is set, the host should call AudioProcessor::getCurrentProgram() and
|
||||
update any preset list views to display the program that is currently in use.
|
||||
|
||||
@see programChanged
|
||||
*/
|
||||
[[nodiscard]] ChangeDetails withProgramChanged (bool b) const noexcept { return with (&ChangeDetails::programChanged, b); }
|
||||
|
||||
/** Indicates that the plugin state has changed (but not its parameters!).
|
||||
|
||||
An AudioProcessor can call updateHostDisplay with this flag set to notify the host that
|
||||
its state has changed in a way that requires re-saving.
|
||||
|
||||
If a host receives a call to audioProcessorChanged with this flag set, it should offer
|
||||
to save the plugin state before taking any actions that might irrevocably destroy the
|
||||
current plugin state, such as closing the project.
|
||||
|
||||
@see nonParameterStateChanged
|
||||
*/
|
||||
[[nodiscard]] ChangeDetails withNonParameterStateChanged (bool b) const noexcept { return with (&ChangeDetails::nonParameterStateChanged, b); }
|
||||
|
||||
/** Returns the default set of flags that will be used when
|
||||
AudioProcessor::updateHostDisplay() is called with no arguments.
|
||||
*/
|
||||
static ChangeDetails getDefaultFlags()
|
||||
{
|
||||
return ChangeDetails{}.withLatencyChanged (true)
|
||||
.withParameterInfoChanged (true)
|
||||
.withProgramChanged (true);
|
||||
}
|
||||
|
||||
[[deprecated ("The naming of this function is misleading. Use getDefaultFlags instead.")]]
|
||||
static ChangeDetails getAllChanged()
|
||||
{
|
||||
return getDefaultFlags();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Member, typename Value>
|
||||
ChangeDetails with (Member&& member, Value&& value) const noexcept
|
||||
{
|
||||
auto copy = *this;
|
||||
copy.*member = std::forward<Value> (value);
|
||||
return copy;
|
||||
}
|
||||
};
|
||||
|
||||
/** Called to indicate that something else in the plugin has changed, like its
|
||||
program, number of parameters, etc.
|
||||
|
||||
IMPORTANT NOTE: This will be called synchronously, and many audio processors will
|
||||
call it during their audio callback. This means that not only has your handler code
|
||||
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
||||
blocking. If you need to handle this event on your message thread, use this callback
|
||||
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
||||
message thread.
|
||||
*/
|
||||
virtual void audioProcessorChanged (AudioProcessor* processor, const ChangeDetails& details) = 0;
|
||||
|
||||
/** Indicates that a parameter change gesture has started.
|
||||
|
||||
E.g. if the user is dragging a slider, this would be called when they first
|
||||
press the mouse button, and audioProcessorParameterChangeGestureEnd would be
|
||||
called when they release it.
|
||||
|
||||
IMPORTANT NOTE: This will be called synchronously, and many audio processors will
|
||||
call it during their audio callback. This means that not only has your handler code
|
||||
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
||||
blocking. If you need to handle this event on your message thread, use this callback
|
||||
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
||||
message thread.
|
||||
|
||||
@see audioProcessorParameterChangeGestureEnd
|
||||
*/
|
||||
virtual void audioProcessorParameterChangeGestureBegin (AudioProcessor* processor,
|
||||
int parameterIndex);
|
||||
|
||||
/** Indicates that a parameter change gesture has finished.
|
||||
|
||||
E.g. if the user is dragging a slider, this would be called when they release
|
||||
the mouse button.
|
||||
|
||||
IMPORTANT NOTE: This will be called synchronously, and many audio processors will
|
||||
call it during their audio callback. This means that not only has your handler code
|
||||
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
||||
blocking. If you need to handle this event on your message thread, use this callback
|
||||
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
||||
message thread.
|
||||
|
||||
@see audioProcessorParameterChangeGestureBegin
|
||||
*/
|
||||
virtual void audioProcessorParameterChangeGestureEnd (AudioProcessor* processor,
|
||||
int parameterIndex);
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
AudioProcessorParameter::~AudioProcessorParameter()
|
||||
{
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This will fail if you've called beginChangeGesture() without having made
|
||||
// a corresponding call to endChangeGesture...
|
||||
jassert (! isPerformingGesture);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::setParameterIndex (int index) noexcept
|
||||
{
|
||||
jassert (parameterIndex < 0 && 0 <= index);
|
||||
parameterIndex = index;
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::setOwner (Listener* listenerIn) noexcept
|
||||
{
|
||||
jassert (finalListener == nullptr);
|
||||
finalListener = listenerIn;
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::setValueNotifyingHost (float newValue)
|
||||
{
|
||||
setValue (newValue);
|
||||
sendValueChangedMessageToListeners (newValue);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::beginChangeGesture()
|
||||
{
|
||||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (parameterIndex >= 0);
|
||||
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called beginChangeGesture twice in succession without
|
||||
// a matching call to endChangeGesture. That might be fine in most hosts,
|
||||
// but it would be better to avoid doing it.
|
||||
jassert (! isPerformingGesture);
|
||||
isPerformingGesture = true;
|
||||
#endif
|
||||
|
||||
ScopedLock lock (listenerLock);
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = listeners[i])
|
||||
l->parameterGestureChanged (getParameterIndex(), true);
|
||||
|
||||
if (finalListener != nullptr)
|
||||
finalListener->parameterGestureChanged (getParameterIndex(), true);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::endChangeGesture()
|
||||
{
|
||||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (parameterIndex >= 0);
|
||||
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called endChangeGesture without having previously
|
||||
// called beginChangeGesture. That might be fine in most hosts, but it
|
||||
// would be better to keep the calls matched correctly.
|
||||
jassert (isPerformingGesture);
|
||||
isPerformingGesture = false;
|
||||
#endif
|
||||
|
||||
ScopedLock lock (listenerLock);
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = listeners[i])
|
||||
l->parameterGestureChanged (getParameterIndex(), false);
|
||||
|
||||
if (finalListener != nullptr)
|
||||
finalListener->parameterGestureChanged (getParameterIndex(), false);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue)
|
||||
{
|
||||
ScopedLock lock (listenerLock);
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = listeners [i])
|
||||
l->parameterValueChanged (getParameterIndex(), newValue);
|
||||
|
||||
if (finalListener != nullptr)
|
||||
finalListener->parameterValueChanged (getParameterIndex(), newValue);
|
||||
}
|
||||
|
||||
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
|
||||
bool AudioProcessorParameter::isAutomatable() const { return true; }
|
||||
bool AudioProcessorParameter::isMetaParameter() const { return false; }
|
||||
AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const { return genericParameter; }
|
||||
int AudioProcessorParameter::getNumSteps() const { return getDefaultNumParameterSteps(); }
|
||||
bool AudioProcessorParameter::isDiscrete() const { return false; }
|
||||
bool AudioProcessorParameter::isBoolean() const { return false; }
|
||||
|
||||
String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
|
||||
{
|
||||
return String (value, 2);
|
||||
}
|
||||
|
||||
String AudioProcessorParameter::getCurrentValueAsText() const
|
||||
{
|
||||
return getText (getValue(), 1024);
|
||||
}
|
||||
|
||||
StringArray AudioProcessorParameter::getAllValueStrings() const
|
||||
{
|
||||
if (isDiscrete() && valueStrings.isEmpty())
|
||||
{
|
||||
auto maxIndex = getNumSteps() - 1;
|
||||
|
||||
for (int i = 0; i < getNumSteps(); ++i)
|
||||
valueStrings.add (getText ((float) i / (float) maxIndex, 1024));
|
||||
}
|
||||
|
||||
return valueStrings;
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::addListener (AudioProcessorParameter::Listener* newListener)
|
||||
{
|
||||
const ScopedLock sl (listenerLock);
|
||||
listeners.addIfNotAlreadyThere (newListener);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::removeListener (AudioProcessorParameter::Listener* listenerToRemove)
|
||||
{
|
||||
const ScopedLock sl (listenerLock);
|
||||
listeners.removeFirstMatchingValue (listenerToRemove);
|
||||
}
|
||||
|
||||
int AudioProcessorParameter::getDefaultNumParameterSteps() noexcept
|
||||
{
|
||||
return 0x7fffffff;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** An abstract base class for parameter objects that can be added to an
|
||||
AudioProcessor.
|
||||
|
||||
@see AudioProcessor::addParameter
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorParameter
|
||||
{
|
||||
public:
|
||||
AudioProcessorParameter() noexcept = default;
|
||||
|
||||
/** The version hint supplied to this constructor is used in Audio Unit plugins to aid ordering
|
||||
parameter identifiers when JUCE_FORCE_USE_LEGACY_PARAM_IDS is not enabled.
|
||||
|
||||
When adding a parameter that is not present in a previous version of the Audio Unit, you
|
||||
must ensure that the version hint supplied is a number higher than that of any parameter in
|
||||
any previous plugin version.
|
||||
|
||||
For example, in the first release of a plugin, every parameter was created with "1" as a
|
||||
version hint. If you add some parameters in the second release of the plugin, all of the
|
||||
new parameters should have "2" as a version hint. Additional parameters added in subsequent
|
||||
plugin versions should have "3", "4", and so forth, increasing monotonically.
|
||||
|
||||
Note that adding or removing parameters with a version hint that is lower than the maximum
|
||||
version hint of all parameters will break saved automation in some hosts, so be careful!
|
||||
|
||||
A version hint of "0" will be treated as though the version hint has not been set
|
||||
explicitly. When targeting the AU format, the version hint may be checked at runtime in
|
||||
debug builds to ensure that it has been set.
|
||||
|
||||
Rationale:
|
||||
|
||||
According to <a href="https://developer.apple.com/documentation/audiotoolbox/audiounitparameter?language=objc">Apple's Documentation</a>:
|
||||
> An audio unit parameter is uniquely identified by the combination of its scope, element, and ID.
|
||||
|
||||
However, Logic Pro and GarageBand have a known limitation that causes them to use parameter
|
||||
indices instead of IDs to identify parameters. The effect of this is that adding parameters
|
||||
to a later version of a plugin can break automation saved with an earlier version of the
|
||||
plugin if the indices of existing parameters are changed. It is *always* unsafe to remove
|
||||
parameters from an Audio Unit plugin that will be used in one of these hosts, because
|
||||
removing a parameter will always modify the indices of following parameters.
|
||||
|
||||
In order to work around this limitation, parameters in AUv2 plugins are sorted first by
|
||||
their version hint, and then by the hash of their string identifier. As long as the
|
||||
parameters from later versions of the plugin always have a version hint that is higher than
|
||||
the parameters from earlier versions of the plugin, recall of automation data will work as
|
||||
expected in Logic and GarageBand.
|
||||
|
||||
Note that we can't just use the JUCE parameter index directly in order to preserve ordering.
|
||||
This would require all new parameters to be added at the end of the parameter list, which
|
||||
would make it impossible to add parameters to existing parameter groups. It would also make
|
||||
it awkward to structure code sensibly, undoing all of the benefits of string-based parameter
|
||||
identifiers.
|
||||
|
||||
At time of writing, AUv3 plugins seem to be affected by the same issue, but there does not
|
||||
appear to be any API to control parameter indices in this format. Therefore, when building
|
||||
AUv3 plugins you must not add or remove parameters in subsequent plugin versions if you
|
||||
wish to support Logic and GarageBand.
|
||||
*/
|
||||
explicit AudioProcessorParameter (int versionHint)
|
||||
: version (versionHint) {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~AudioProcessorParameter();
|
||||
|
||||
/** Called by the host to find out the value of this parameter.
|
||||
|
||||
Hosts will expect the value returned to be between 0 and 1.0.
|
||||
|
||||
This could be called quite frequently, so try to make your code efficient.
|
||||
It's also likely to be called by non-UI threads, so the code in here should
|
||||
be thread-aware.
|
||||
*/
|
||||
virtual float getValue() const = 0;
|
||||
|
||||
/** The host will call this method to change the value of a parameter.
|
||||
|
||||
The host may call this at any time, including during the audio processing
|
||||
callback, so your implementation has to process this very efficiently and
|
||||
avoid any kind of locking.
|
||||
|
||||
If you want to set the value of a parameter internally, e.g. from your
|
||||
editor component, then don't call this directly - instead, use the
|
||||
setValueNotifyingHost() method, which will also send a message to
|
||||
the host telling it about the change. If the message isn't sent, the host
|
||||
won't be able to automate your parameters properly.
|
||||
|
||||
The value passed will be between 0 and 1.0.
|
||||
*/
|
||||
virtual void setValue (float newValue) = 0;
|
||||
|
||||
/** A processor should call this when it needs to change one of its parameters.
|
||||
|
||||
This could happen when the editor or some other internal operation changes
|
||||
a parameter. This method will call the setValue() method to change the
|
||||
value, and will then send a message to the host telling it about the change.
|
||||
|
||||
Note that to make sure the host correctly handles automation, you should call
|
||||
the beginChangeGesture() and endChangeGesture() methods to tell the host when
|
||||
the user has started and stopped changing the parameter.
|
||||
*/
|
||||
void setValueNotifyingHost (float newValue);
|
||||
|
||||
/** Sends a signal to the host to tell it that the user is about to start changing this
|
||||
parameter.
|
||||
This allows the host to know when a parameter is actively being held by the user, and
|
||||
it may use this information to help it record automation.
|
||||
If you call this, it must be matched by a later call to endChangeGesture().
|
||||
*/
|
||||
void beginChangeGesture();
|
||||
|
||||
/** Tells the host that the user has finished changing this parameter.
|
||||
This allows the host to know when a parameter is actively being held by the user,
|
||||
and it may use this information to help it record automation.
|
||||
A call to this method must follow a call to beginChangeGesture().
|
||||
*/
|
||||
void endChangeGesture();
|
||||
|
||||
/** This should return the default value for this parameter. */
|
||||
virtual float getDefaultValue() const = 0;
|
||||
|
||||
/** Returns the name to display for this parameter, which should be made
|
||||
to fit within the given string length.
|
||||
*/
|
||||
virtual String getName (int maximumStringLength) const = 0;
|
||||
|
||||
/** Some parameters may be able to return a label string for
|
||||
their units. For example "Hz" or "%".
|
||||
*/
|
||||
virtual String getLabel() const = 0;
|
||||
|
||||
/** Returns the number of steps that this parameter's range should be quantised into.
|
||||
|
||||
If you want a continuous range of values, don't override this method, and allow
|
||||
the default implementation to return getDefaultNumParameterSteps().
|
||||
|
||||
If your parameter is boolean, then you may want to make this return 2.
|
||||
|
||||
The value that is returned may or may not be used, depending on the host. If you
|
||||
want the host to display stepped automation values, rather than a continuous
|
||||
interpolation between successive values, you should override isDiscrete to return true.
|
||||
|
||||
@see isDiscrete
|
||||
*/
|
||||
virtual int getNumSteps() const;
|
||||
|
||||
/** Returns whether the parameter uses discrete values, based on the result of
|
||||
getNumSteps, or allows the host to select values continuously.
|
||||
|
||||
This information may or may not be used, depending on the host. If you
|
||||
want the host to display stepped automation values, rather than a continuous
|
||||
interpolation between successive values, override this method to return true.
|
||||
|
||||
@see getNumSteps
|
||||
*/
|
||||
virtual bool isDiscrete() const;
|
||||
|
||||
/** Returns whether the parameter represents a boolean switch, typically with
|
||||
"On" and "Off" states.
|
||||
|
||||
This information may or may not be used, depending on the host. If you
|
||||
want the host to display a switch, rather than a two item dropdown menu,
|
||||
override this method to return true. You also need to override
|
||||
isDiscrete() to return `true` and getNumSteps() to return `2`.
|
||||
|
||||
@see isDiscrete getNumSteps
|
||||
*/
|
||||
virtual bool isBoolean() const;
|
||||
|
||||
/** Returns a textual version of the supplied normalised parameter value.
|
||||
The default implementation just returns the floating point value
|
||||
as a string, but this could do anything you need for a custom type
|
||||
of value.
|
||||
*/
|
||||
virtual String getText (float normalisedValue, int /*maximumStringLength*/) const;
|
||||
|
||||
/** Should parse a string and return the appropriate value for it. */
|
||||
virtual float getValueForText (const String& text) const = 0;
|
||||
|
||||
/** This can be overridden to tell the host that this parameter operates in the
|
||||
reverse direction.
|
||||
(Not all plugin formats or hosts will actually use this information).
|
||||
*/
|
||||
virtual bool isOrientationInverted() const;
|
||||
|
||||
/** Returns true if the host can automate this parameter.
|
||||
By default, this returns true.
|
||||
*/
|
||||
virtual bool isAutomatable() const;
|
||||
|
||||
/** Should return true if this parameter is a "meta" parameter.
|
||||
A meta-parameter is a parameter that changes other params. It is used
|
||||
by some hosts (e.g. AudioUnit hosts).
|
||||
By default this returns false.
|
||||
*/
|
||||
virtual bool isMetaParameter() const;
|
||||
|
||||
enum Category
|
||||
{
|
||||
genericParameter = (0 << 16) | 0, /**< If your parameter is not a meter then you should use this category */
|
||||
|
||||
inputGain = (1 << 16) | 0, /**< Currently not used */
|
||||
outputGain = (1 << 16) | 1,
|
||||
|
||||
/** The following categories tell the host that this parameter is a meter level value
|
||||
and therefore read-only. Most hosts will display these type of parameters as
|
||||
a meter in the generic view of your plug-in. Pro-Tools will also show the meter
|
||||
in the mixer view.
|
||||
*/
|
||||
inputMeter = (2 << 16) | 0,
|
||||
outputMeter = (2 << 16) | 1,
|
||||
compressorLimiterGainReductionMeter = (2 << 16) | 2,
|
||||
expanderGateGainReductionMeter = (2 << 16) | 3,
|
||||
analysisMeter = (2 << 16) | 4,
|
||||
otherMeter = (2 << 16) | 5
|
||||
};
|
||||
|
||||
/** Returns the parameter's category. */
|
||||
virtual Category getCategory() const;
|
||||
|
||||
/** Returns the index of this parameter in its parent processor's parameter list. */
|
||||
int getParameterIndex() const noexcept { return parameterIndex; }
|
||||
|
||||
/** @internal
|
||||
This should only be called by the owner of the parameter after it has been added to
|
||||
a processor. Do not call this function; changing the parameter index *will* break things!
|
||||
*/
|
||||
void setParameterIndex (int) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the current value of the parameter as a String.
|
||||
|
||||
This function can be called when you are hosting plug-ins to get a
|
||||
more specialised textual representation of the current value from the
|
||||
plug-in, for example "On" rather than "1.0".
|
||||
|
||||
If you are implementing a plug-in then you should ignore this function
|
||||
and instead override getText.
|
||||
*/
|
||||
virtual String getCurrentValueAsText() const;
|
||||
|
||||
/** Returns the set of strings which represent the possible states a parameter
|
||||
can be in.
|
||||
|
||||
If you are hosting a plug-in you can use the result of this function to
|
||||
populate a ComboBox listing the allowed values.
|
||||
|
||||
If you are implementing a plug-in then you do not need to override this.
|
||||
*/
|
||||
virtual StringArray getAllValueStrings() const;
|
||||
|
||||
//==============================================================================
|
||||
/** @see AudioProcessorParameter (int) */
|
||||
int getVersionHint() const { return version; }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A base class for listeners that want to know about changes to an
|
||||
AudioProcessorParameter.
|
||||
|
||||
Use AudioProcessorParameter::addListener() to register your listener with
|
||||
an AudioProcessorParameter.
|
||||
|
||||
This Listener replaces most of the functionality in the
|
||||
AudioProcessorListener class, which will be deprecated and removed.
|
||||
*/
|
||||
class JUCE_API Listener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** Receives a callback when a parameter has been changed.
|
||||
|
||||
IMPORTANT NOTE: This will be called synchronously when a parameter changes, and
|
||||
many audio processors will change their parameter during their audio callback.
|
||||
This means that not only has your handler code got to be completely thread-safe,
|
||||
but it's also got to be VERY fast, and avoid blocking. If you need to handle
|
||||
this event on your message thread, use this callback to trigger an AsyncUpdater
|
||||
or ChangeBroadcaster which you can respond to on the message thread.
|
||||
*/
|
||||
virtual void parameterValueChanged (int parameterIndex, float newValue) = 0;
|
||||
|
||||
/** Indicates that a parameter change gesture has started.
|
||||
|
||||
E.g. if the user is dragging a slider, this would be called with gestureIsStarting
|
||||
being true when they first press the mouse button, and it will be called again with
|
||||
gestureIsStarting being false when they release it.
|
||||
|
||||
IMPORTANT NOTE: This will be called synchronously, and many audio processors will
|
||||
call it during their audio callback. This means that not only has your handler code
|
||||
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
||||
blocking. If you need to handle this event on your message thread, use this callback
|
||||
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
||||
message thread.
|
||||
*/
|
||||
virtual void parameterGestureChanged (int parameterIndex, bool gestureIsStarting) = 0;
|
||||
};
|
||||
|
||||
/** @internal
|
||||
This should only be called by the owner of the parameter after it has been added to
|
||||
a processor. Do not call this function; changing the owner *will* break things!
|
||||
*/
|
||||
void setOwner (Listener* listener) noexcept;
|
||||
|
||||
/** Registers a listener to receive events when the parameter's state changes.
|
||||
If the listener is already registered, this will not register it again.
|
||||
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* newListener);
|
||||
|
||||
/** Removes a previously registered parameter listener
|
||||
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void sendValueChangedMessageToListeners (float newValue);
|
||||
|
||||
/** Returns the default number of steps for a parameter.
|
||||
|
||||
NOTE! This method is deprecated! It's recommended that you use
|
||||
AudioProcessorParameter::getNumSteps() instead.
|
||||
|
||||
@see getParameterNumSteps
|
||||
*/
|
||||
static int getDefaultNumParameterSteps() noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int parameterIndex = -1;
|
||||
int version = 0;
|
||||
CriticalSection listenerLock;
|
||||
Array<Listener*> listeners;
|
||||
Listener* finalListener = nullptr;
|
||||
mutable StringArray valueStrings;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
bool isPerformingGesture = false;
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterNode::~AudioProcessorParameterNode() = default;
|
||||
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterNode::AudioProcessorParameterNode (AudioProcessorParameterNode&& other)
|
||||
: group (std::move (other.group)), parameter (std::move (other.parameter))
|
||||
{
|
||||
if (group != nullptr)
|
||||
group->parent = parent;
|
||||
}
|
||||
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterNode::AudioProcessorParameterNode (std::unique_ptr<AudioProcessorParameter> param,
|
||||
AudioProcessorParameterGroup* parentGroup)
|
||||
: parameter (std::move (param)), parent (parentGroup)
|
||||
{}
|
||||
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterNode::AudioProcessorParameterNode (std::unique_ptr<AudioProcessorParameterGroup> grp,
|
||||
AudioProcessorParameterGroup* parentGroup)
|
||||
: group (std::move (grp)), parent (parentGroup)
|
||||
{
|
||||
group->parent = parent;
|
||||
}
|
||||
|
||||
AudioProcessorParameterGroup* AudioProcessorParameterGroup::AudioProcessorParameterNode::getParent() const { return parent; }
|
||||
AudioProcessorParameter* AudioProcessorParameterGroup::AudioProcessorParameterNode::getParameter() const { return parameter.get(); }
|
||||
AudioProcessorParameterGroup* AudioProcessorParameterGroup::AudioProcessorParameterNode::getGroup() const { return group.get(); }
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterGroup() = default;
|
||||
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterGroup (String groupID, String groupName, String subgroupSeparator)
|
||||
: identifier (std::move (groupID)), name (std::move (groupName)), separator (std::move (subgroupSeparator))
|
||||
{
|
||||
}
|
||||
|
||||
AudioProcessorParameterGroup::~AudioProcessorParameterGroup() = default;
|
||||
|
||||
AudioProcessorParameterGroup::AudioProcessorParameterGroup (AudioProcessorParameterGroup&& other)
|
||||
: identifier (std::move (other.identifier)),
|
||||
name (std::move (other.name)),
|
||||
separator (std::move (other.separator)),
|
||||
children (std::move (other.children))
|
||||
{
|
||||
updateChildParentage();
|
||||
}
|
||||
|
||||
AudioProcessorParameterGroup& AudioProcessorParameterGroup::operator= (AudioProcessorParameterGroup&& other)
|
||||
{
|
||||
identifier = std::move (other.identifier);
|
||||
name = std::move (other.name);
|
||||
separator = std::move (other.separator);
|
||||
children = std::move (other.children);
|
||||
updateChildParentage();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AudioProcessorParameterGroup::updateChildParentage()
|
||||
{
|
||||
for (auto* child : children)
|
||||
{
|
||||
child->parent = this;
|
||||
|
||||
if (auto* group = child->getGroup())
|
||||
group->parent = this;
|
||||
}
|
||||
}
|
||||
|
||||
String AudioProcessorParameterGroup::getID() const { return identifier; }
|
||||
String AudioProcessorParameterGroup::getName() const { return name; }
|
||||
String AudioProcessorParameterGroup::getSeparator() const { return separator; }
|
||||
const AudioProcessorParameterGroup* AudioProcessorParameterGroup::getParent() const noexcept { return parent; }
|
||||
|
||||
void AudioProcessorParameterGroup::setName (String newName) { name = std::move (newName); }
|
||||
|
||||
const AudioProcessorParameterGroup::AudioProcessorParameterNode* const* AudioProcessorParameterGroup::begin() const noexcept { return const_cast<const AudioProcessorParameterNode**> (children.begin()); }
|
||||
const AudioProcessorParameterGroup::AudioProcessorParameterNode* const* AudioProcessorParameterGroup::end() const noexcept { return const_cast<const AudioProcessorParameterNode**> (children.end()); }
|
||||
|
||||
void AudioProcessorParameterGroup::append (std::unique_ptr<AudioProcessorParameter> newParameter)
|
||||
{
|
||||
children.add (new AudioProcessorParameterNode (std::move (newParameter), this));
|
||||
}
|
||||
|
||||
void AudioProcessorParameterGroup::append (std::unique_ptr<AudioProcessorParameterGroup> newSubGroup)
|
||||
{
|
||||
children.add (new AudioProcessorParameterNode (std::move (newSubGroup), this));
|
||||
}
|
||||
|
||||
Array<const AudioProcessorParameterGroup*> AudioProcessorParameterGroup::getSubgroups (bool recursive) const
|
||||
{
|
||||
Array<const AudioProcessorParameterGroup*> groups;
|
||||
getSubgroups (groups, recursive);
|
||||
return groups;
|
||||
}
|
||||
|
||||
Array<AudioProcessorParameter*> AudioProcessorParameterGroup::getParameters (bool recursive) const
|
||||
{
|
||||
Array<AudioProcessorParameter*> parameters;
|
||||
getParameters (parameters, recursive);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
Array<const AudioProcessorParameterGroup*> AudioProcessorParameterGroup::getGroupsForParameter (AudioProcessorParameter* parameter) const
|
||||
{
|
||||
Array<const AudioProcessorParameterGroup*> groups;
|
||||
|
||||
if (auto* group = getGroupForParameter (parameter))
|
||||
{
|
||||
while (group != nullptr && group != this)
|
||||
{
|
||||
groups.insert (0, group);
|
||||
group = group->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
void AudioProcessorParameterGroup::getSubgroups (Array<const AudioProcessorParameterGroup*>& previousGroups, bool recursive) const
|
||||
{
|
||||
for (auto* child : children)
|
||||
{
|
||||
if (auto* group = child->getGroup())
|
||||
{
|
||||
previousGroups.add (group);
|
||||
|
||||
if (recursive)
|
||||
group->getSubgroups (previousGroups, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessorParameterGroup::getParameters (Array<AudioProcessorParameter*>& previousParameters, bool recursive) const
|
||||
{
|
||||
for (auto* child : children)
|
||||
{
|
||||
if (auto* parameter = child->getParameter())
|
||||
previousParameters.add (parameter);
|
||||
else if (recursive)
|
||||
child->getGroup()->getParameters (previousParameters, true);
|
||||
}
|
||||
}
|
||||
|
||||
const AudioProcessorParameterGroup* AudioProcessorParameterGroup::getGroupForParameter (AudioProcessorParameter* parameter) const
|
||||
{
|
||||
for (auto* child : children)
|
||||
{
|
||||
if (child->getParameter() == parameter)
|
||||
return this;
|
||||
|
||||
if (auto* group = child->getGroup())
|
||||
if (auto* foundGroup = group->getGroupForParameter (parameter))
|
||||
return foundGroup;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class ParameterGroupTests final : public UnitTest
|
||||
{
|
||||
public:
|
||||
ParameterGroupTests()
|
||||
: UnitTest ("ParameterGroups", UnitTestCategories::audioProcessorParameters)
|
||||
{}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("ParameterGroups");
|
||||
|
||||
auto g1 = std::make_unique<AudioProcessorParameterGroup> ("g1", "g1", " - ");
|
||||
|
||||
auto* p1 = new AudioParameterFloat ("p1", "p1", { 0.0f, 2.0f }, 0.5f);
|
||||
auto* p2 = new AudioParameterFloat ("p2", "p2", { 0.0f, 2.0f }, 0.5f);
|
||||
auto* p3 = new AudioParameterFloat ("p3", "p3", { 0.0f, 2.0f }, 0.5f);
|
||||
|
||||
g1->addChild (std::unique_ptr<AudioParameterFloat> (p1));
|
||||
g1->addChild (std::unique_ptr<AudioParameterFloat> (p2),
|
||||
std::unique_ptr<AudioParameterFloat> (p3));
|
||||
|
||||
auto p4 = std::make_unique<AudioParameterFloat> ("p4", "p4", NormalisableRange<float> (0.0f, 2.0f), 0.5f);
|
||||
auto p5 = std::make_unique<AudioParameterFloat> ("p5", "p5", NormalisableRange<float> (0.0f, 2.0f), 0.5f);
|
||||
auto p6 = std::make_unique<AudioParameterFloat> ("p6", "p6", NormalisableRange<float> (0.0f, 2.0f), 0.5f);
|
||||
|
||||
g1->addChild (std::move (p4));
|
||||
g1->addChild (std::move (p5),
|
||||
std::move (p6));
|
||||
|
||||
{
|
||||
auto topLevelParams = g1->getParameters (false);
|
||||
auto params = g1->getParameters (true);
|
||||
expect (topLevelParams == params);
|
||||
expectEquals (params.size(), 6);
|
||||
|
||||
expect (params[0] == (AudioProcessorParameter*) p1);
|
||||
expect (params[1] == (AudioProcessorParameter*) p2);
|
||||
expect (params[2] == (AudioProcessorParameter*) p3);
|
||||
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[3])->name == "p4");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[4])->name == "p5");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[5])->name == "p6");
|
||||
}
|
||||
|
||||
auto* p7 = new AudioParameterFloat ("p7", "p7", { 0.0f, 2.0f }, 0.5f);
|
||||
auto* p8 = new AudioParameterFloat ("p8", "p8", { 0.0f, 2.0f }, 0.5f);
|
||||
auto* p9 = new AudioParameterFloat ("p9", "p9", { 0.0f, 2.0f }, 0.5f);
|
||||
|
||||
auto p10 = std::make_unique<AudioParameterFloat> ("p10", "p10", NormalisableRange<float> (0.0f, 2.0f), 0.5f);
|
||||
auto p11 = std::make_unique<AudioParameterFloat> ("p11", "p11", NormalisableRange<float> (0.0f, 2.0f), 0.5f);
|
||||
auto p12 = std::make_unique<AudioParameterFloat> ("p12", "p12", NormalisableRange<float> (0.0f, 2.0f), 0.5f);
|
||||
|
||||
auto g2 = std::make_unique<AudioProcessorParameterGroup> ("g2", "g2", " | ", std::unique_ptr<AudioParameterFloat> (p7));
|
||||
auto g3 = std::make_unique<AudioProcessorParameterGroup> ("g3", "g3", " | ", std::unique_ptr<AudioParameterFloat> (p8), std::unique_ptr<AudioParameterFloat> (p9));
|
||||
auto g4 = std::make_unique<AudioProcessorParameterGroup> ("g4", "g4", " | ", std::move (p10));
|
||||
auto g5 = std::make_unique<AudioProcessorParameterGroup> ("g5", "g5", " | ", std::move (p11), std::move (p12));
|
||||
|
||||
g1->addChild (std::move (g2));
|
||||
g4->addChild (std::move (g5));
|
||||
g1->addChild (std::move (g3), std::move (g4));
|
||||
|
||||
{
|
||||
auto topLevelParams = g1->getParameters (false);
|
||||
auto params = g1->getParameters (true);
|
||||
expectEquals (topLevelParams.size(), 6);
|
||||
expectEquals (params.size(), 12);
|
||||
|
||||
expect (params[0] == (AudioProcessorParameter*) p1);
|
||||
expect (params[1] == (AudioProcessorParameter*) p2);
|
||||
expect (params[2] == (AudioProcessorParameter*) p3);
|
||||
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[3])->name == "p4");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[4])->name == "p5");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[5])->name == "p6");
|
||||
|
||||
expect (params[6] == (AudioProcessorParameter*) p7);
|
||||
expect (params[7] == (AudioProcessorParameter*) p8);
|
||||
expect (params[8] == (AudioProcessorParameter*) p9);
|
||||
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[9]) ->name == "p10");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[10])->name == "p11");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (params[11])->name == "p12");
|
||||
}
|
||||
|
||||
g1->addChild (std::make_unique<AudioProcessorParameterGroup> ("g6", "g6", " | ",
|
||||
std::make_unique<AudioParameterFloat> ("p13", "p13", NormalisableRange<float> (0.0f, 2.0f), 0.5f),
|
||||
std::make_unique<AudioProcessorParameterGroup> ("g7", "g7", " | ",
|
||||
std::make_unique<AudioParameterFloat> ("p14", "p14", NormalisableRange<float> (0.0f, 2.0f), 0.5f)),
|
||||
std::make_unique<AudioParameterFloat> ("p15", "p15", NormalisableRange<float> (0.0f, 2.0f), 0.5f)));
|
||||
|
||||
TestAudioProcessor processor;
|
||||
|
||||
processor.addParameter (new AudioParameterFloat ("pstart", "pstart", NormalisableRange<float> (0.0f, 2.0f), 0.5f));
|
||||
auto groupParams = g1->getParameters (true);
|
||||
processor.addParameterGroup (std::move (g1));
|
||||
processor.addParameter (new AudioParameterFloat ("pend", "pend", NormalisableRange<float> (0.0f, 2.0f), 0.5f));
|
||||
|
||||
auto& processorParams = processor.getParameters();
|
||||
expect (dynamic_cast<AudioParameterFloat*> (processorParams.getFirst())->name == "pstart");
|
||||
expect (dynamic_cast<AudioParameterFloat*> (processorParams.getLast()) ->name == "pend");
|
||||
|
||||
auto numParams = processorParams.size();
|
||||
|
||||
for (int i = 1; i < numParams - 1; ++i)
|
||||
expect (processorParams[i] == groupParams[i - 1]);
|
||||
|
||||
}
|
||||
private:
|
||||
struct TestAudioProcessor final : public AudioProcessor
|
||||
{
|
||||
const String getName() const override { return "ap"; }
|
||||
void prepareToPlay (double, int) override {}
|
||||
void releaseResources() override {}
|
||||
void processBlock (AudioBuffer<float>&, MidiBuffer&) override {}
|
||||
using AudioProcessor::processBlock;
|
||||
double getTailLengthSeconds() const override { return 0.0; }
|
||||
bool acceptsMidi() const override { return false; }
|
||||
bool producesMidi() const override { return false; }
|
||||
AudioProcessorEditor* createEditor() override { return nullptr; }
|
||||
bool hasEditor() const override { return false; }
|
||||
int getNumPrograms() override { return 0; }
|
||||
int getCurrentProgram() override { return 0; }
|
||||
void setCurrentProgram (int) override {}
|
||||
const String getProgramName (int) override { return {}; }
|
||||
void changeProgramName (int, const String&) override {}
|
||||
void getStateInformation (MemoryBlock&) override {}
|
||||
void setStateInformation (const void*, int) override {}
|
||||
};
|
||||
};
|
||||
|
||||
static ParameterGroupTests parameterGroupTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** A class encapsulating a group of AudioProcessorParameters and nested
|
||||
AudioProcessorParameterGroups.
|
||||
|
||||
This class is predominantly write-only; there are methods for adding group
|
||||
members but none for removing them. Ultimately you will probably want to
|
||||
add a fully constructed group to an AudioProcessor.
|
||||
|
||||
@see AudioProcessor::addParameterGroup
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorParameterGroup
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** A child of an AudioProcessorParameterGroup.
|
||||
|
||||
This can contain either an AudioProcessorParameter or an
|
||||
AudioProcessorParameterGroup. You can query which using the
|
||||
getParameter and getGroup methods.
|
||||
|
||||
@code
|
||||
for (auto* child : group)
|
||||
if (auto* parameter = node.getParameter())
|
||||
parameter->setValueNotifyingHost (0.5f);
|
||||
else
|
||||
node.getGroup()->AddChild (new Parameter());
|
||||
@endcode
|
||||
*/
|
||||
class AudioProcessorParameterNode
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
AudioProcessorParameterNode (AudioProcessorParameterNode&&);
|
||||
~AudioProcessorParameterNode();
|
||||
|
||||
/** Returns the parent group or nullptr if this is a top-level group. */
|
||||
AudioProcessorParameterGroup* getParent() const;
|
||||
|
||||
/** Returns a pointer to a parameter if this node contains a parameter, nullptr otherwise. */
|
||||
AudioProcessorParameter* getParameter() const;
|
||||
|
||||
/** Returns a pointer to a group if this node contains a group, nullptr otherwise. */
|
||||
AudioProcessorParameterGroup* getGroup() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
AudioProcessorParameterNode (std::unique_ptr<AudioProcessorParameter>, AudioProcessorParameterGroup*);
|
||||
AudioProcessorParameterNode (std::unique_ptr<AudioProcessorParameterGroup>, AudioProcessorParameterGroup*);
|
||||
|
||||
std::unique_ptr<AudioProcessorParameterGroup> group;
|
||||
std::unique_ptr<AudioProcessorParameter> parameter;
|
||||
AudioProcessorParameterGroup* parent = nullptr;
|
||||
|
||||
friend class AudioProcessorParameterGroup;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterNode)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty AudioProcessorParameterGroup with no name or ID. */
|
||||
AudioProcessorParameterGroup();
|
||||
|
||||
/** Creates an empty AudioProcessorParameterGroup.
|
||||
|
||||
@param groupID A unique identifier for the group. Keep it basic; don't use any special
|
||||
characters like "." and avoid pure integer strings which could collide with
|
||||
legacy parameter IDs.
|
||||
@param groupName The group's name, which will be displayed in the host.
|
||||
@param subgroupSeparator A separator string to use between the name of this group and the name of any
|
||||
subgroups if this group is flattened. AUv3 and VST3 plug-ins can have multiple
|
||||
layers of nested subgroups, but AU plug-ins cannot have any subgroups.
|
||||
|
||||
*/
|
||||
AudioProcessorParameterGroup (String groupID, String groupName, String subgroupSeparator);
|
||||
|
||||
/** Creates an AudioProcessorParameterGroup with a single child.
|
||||
|
||||
@param groupID A unique identifier for the group. Keep it basic; don't use any special
|
||||
characters like "." and avoid pure integer strings which could collide with
|
||||
legacy parameter IDs.
|
||||
@param groupName The group's name, which will be displayed in the host.
|
||||
@param subgroupSeparator A separator string to use between the name of this group and the name of any
|
||||
subgroups if this group is flattened. AUv3 and VST3 plug-ins can have multiple
|
||||
layers of nested subgroups, but AU plug-ins cannot have any subgroups.
|
||||
@param child An AudioProcessorParameter or an AudioProcessorParameterGroup to add to the group.
|
||||
*/
|
||||
template <typename ParameterOrGroup>
|
||||
AudioProcessorParameterGroup (String groupID, String groupName, String subgroupSeparator,
|
||||
std::unique_ptr<ParameterOrGroup> child)
|
||||
: AudioProcessorParameterGroup (groupID, groupName, subgroupSeparator)
|
||||
{
|
||||
addChild (std::move (child));
|
||||
}
|
||||
|
||||
/** Creates an AudioProcessorParameterGroup with multiple children.
|
||||
|
||||
@param groupID A unique identifier for the group. Keep it basic; don't use any special
|
||||
characters like "." and avoid pure integer strings which could collide with
|
||||
legacy parameter IDs.
|
||||
@param groupName The group's name, which will be displayed in the host.
|
||||
@param subgroupSeparator A separator string to use between the name of this group and the name of any
|
||||
subgroups if this group is flattened. AUv3 and VST3 plug-ins can have multiple
|
||||
layers of nested subgroups, but AU plug-ins cannot have any subgroups.
|
||||
@param firstChild An AudioProcessorParameter or an AudioProcessorParameterGroup to add to the group.
|
||||
@param remainingChildren A list of more AudioProcessorParameters or AudioProcessorParameterGroups to add to the group.
|
||||
*/
|
||||
template <typename ParameterOrGroup, typename... Args>
|
||||
AudioProcessorParameterGroup (String groupID, String groupName, String subgroupSeparator,
|
||||
std::unique_ptr<ParameterOrGroup> firstChild, Args&&... remainingChildren)
|
||||
: AudioProcessorParameterGroup (groupID, groupName, subgroupSeparator, std::move (firstChild))
|
||||
{
|
||||
addChild (std::forward<Args> (remainingChildren)...);
|
||||
}
|
||||
|
||||
/** Once a group has been added to an AudioProcessor don't try to mutate it by
|
||||
moving or swapping it - this will crash most hosts.
|
||||
*/
|
||||
AudioProcessorParameterGroup (AudioProcessorParameterGroup&&);
|
||||
|
||||
/** Once a group has been added to an AudioProcessor don't try to mutate it by
|
||||
moving or swapping it - this will crash most hosts.
|
||||
*/
|
||||
AudioProcessorParameterGroup& operator= (AudioProcessorParameterGroup&&);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioProcessorParameterGroup();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the group's ID. */
|
||||
String getID() const;
|
||||
|
||||
/** Returns the group's name. */
|
||||
String getName() const;
|
||||
|
||||
/** Returns the group's separator string. */
|
||||
String getSeparator() const;
|
||||
|
||||
/** Returns the parent of the group, or nullptr if this is a top-level group. */
|
||||
const AudioProcessorParameterGroup* getParent() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the name of the group. If you do this after the group has been added
|
||||
to an AudioProcessor, call updateHostDisplay() to inform the host of the
|
||||
change. Not all hosts support dynamic group name changes.
|
||||
*/
|
||||
void setName (String newName);
|
||||
|
||||
//==============================================================================
|
||||
const AudioProcessorParameterNode* const* begin() const noexcept;
|
||||
const AudioProcessorParameterNode* const* end() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns all subgroups of this group.
|
||||
|
||||
@param recursive If this is true then this method will fetch all nested
|
||||
subgroups using a depth first search.
|
||||
*/
|
||||
Array<const AudioProcessorParameterGroup*> getSubgroups (bool recursive) const;
|
||||
|
||||
/** Returns all the parameters in this group.
|
||||
|
||||
@param recursive If this is true then this method will fetch all nested
|
||||
parameters using a depth first search.
|
||||
*/
|
||||
Array<AudioProcessorParameter*> getParameters (bool recursive) const;
|
||||
|
||||
/** Searches this group recursively for a parameter and returns a depth ordered
|
||||
list of the groups it belongs to.
|
||||
*/
|
||||
Array<const AudioProcessorParameterGroup*> getGroupsForParameter (AudioProcessorParameter*) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a child to the group.
|
||||
|
||||
Do not add children to a group which has itself already been added to the
|
||||
AudioProcessor - the new elements will be ignored.
|
||||
*/
|
||||
template <typename ParameterOrGroup>
|
||||
void addChild (std::unique_ptr<ParameterOrGroup> child)
|
||||
{
|
||||
// If you hit a compiler error here then you are attempting to add a
|
||||
// child that is neither a pointer to an AudioProcessorParameterGroup
|
||||
// nor a pointer to an AudioProcessorParameter.
|
||||
append (std::move (child));
|
||||
}
|
||||
|
||||
/** Adds multiple parameters or sub-groups to this group.
|
||||
|
||||
Do not add children to a group which has itself already been added to the
|
||||
AudioProcessor - the new elements will be ignored.
|
||||
*/
|
||||
template <typename ParameterOrGroup, typename... Args>
|
||||
void addChild (std::unique_ptr<ParameterOrGroup> firstChild, Args&&... remainingChildren)
|
||||
{
|
||||
addChild (std::move (firstChild));
|
||||
addChild (std::forward<Args> (remainingChildren)...);
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
[[deprecated ("This class now has a move operator, so if you're trying to move them around, you "
|
||||
"should use that, or if you really need to swap two groups, just call std::swap. "
|
||||
"However, remember that swapping a group that's already owned by an AudioProcessor "
|
||||
"will most likely crash the host, so don't do that.")]]
|
||||
void swapWith (AudioProcessorParameterGroup& other) { std::swap (*this, other); }
|
||||
/** @endcond */
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void getSubgroups (Array<const AudioProcessorParameterGroup*>&, bool recursive) const;
|
||||
void getParameters (Array<AudioProcessorParameter*>&, bool recursive) const;
|
||||
const AudioProcessorParameterGroup* getGroupForParameter (AudioProcessorParameter*) const;
|
||||
void updateChildParentage();
|
||||
void append (std::unique_ptr<AudioProcessorParameter>);
|
||||
void append (std::unique_ptr<AudioProcessorParameterGroup>);
|
||||
|
||||
//==============================================================================
|
||||
String identifier, name, separator;
|
||||
OwnedArray<AudioProcessorParameterNode> children;
|
||||
AudioProcessorParameterGroup* parent = nullptr;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterGroup)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A parameter with functions that are useful for plugin hosts.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct JUCE_API HostedAudioProcessorParameter : public AudioProcessorParameter
|
||||
{
|
||||
using AudioProcessorParameter::AudioProcessorParameter;
|
||||
|
||||
/** Returns an ID that is unique to this parameter.
|
||||
|
||||
Parameter indices are unstable across plugin versions, which means that the
|
||||
parameter found at a particular index in one version of a plugin might move
|
||||
to a different index in the subsequent version.
|
||||
|
||||
Unlike the parameter index, the ID returned by this function should be
|
||||
somewhat stable (depending on the format of the plugin), so it is more
|
||||
suitable for storing/recalling automation data.
|
||||
*/
|
||||
virtual String getParameterID() const = 0;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
bool PluginDescription::isDuplicateOf (const PluginDescription& other) const noexcept
|
||||
{
|
||||
const auto tie = [] (const PluginDescription& d)
|
||||
{
|
||||
return std::tie (d.fileOrIdentifier, d.deprecatedUid, d.uniqueId);
|
||||
};
|
||||
|
||||
return tie (*this) == tie (other);
|
||||
}
|
||||
|
||||
static String getPluginDescSuffix (const PluginDescription& d, int uid)
|
||||
{
|
||||
return "-" + String::toHexString (d.fileOrIdentifier.hashCode())
|
||||
+ "-" + String::toHexString (uid);
|
||||
}
|
||||
|
||||
bool PluginDescription::matchesIdentifierString (const String& identifierString) const
|
||||
{
|
||||
const auto matches = [&] (int uid)
|
||||
{
|
||||
return identifierString.endsWithIgnoreCase (getPluginDescSuffix (*this, uid));
|
||||
};
|
||||
|
||||
return matches (uniqueId) || matches (deprecatedUid);
|
||||
}
|
||||
|
||||
String PluginDescription::createIdentifierString() const
|
||||
{
|
||||
const auto idToUse = uniqueId != 0 ? uniqueId : deprecatedUid;
|
||||
return pluginFormatName + "-" + name + getPluginDescSuffix (*this, idToUse);
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> PluginDescription::createXml() const
|
||||
{
|
||||
auto e = std::make_unique<XmlElement> ("PLUGIN");
|
||||
|
||||
e->setAttribute ("name", name);
|
||||
|
||||
if (descriptiveName != name)
|
||||
e->setAttribute ("descriptiveName", descriptiveName);
|
||||
|
||||
e->setAttribute ("format", pluginFormatName);
|
||||
e->setAttribute ("category", category);
|
||||
e->setAttribute ("manufacturer", manufacturerName);
|
||||
e->setAttribute ("version", version);
|
||||
e->setAttribute ("file", fileOrIdentifier);
|
||||
e->setAttribute ("uniqueId", String::toHexString (uniqueId));
|
||||
e->setAttribute ("isInstrument", isInstrument);
|
||||
e->setAttribute ("fileTime", String::toHexString (lastFileModTime.toMilliseconds()));
|
||||
e->setAttribute ("infoUpdateTime", String::toHexString (lastInfoUpdateTime.toMilliseconds()));
|
||||
e->setAttribute ("numInputs", numInputChannels);
|
||||
e->setAttribute ("numOutputs", numOutputChannels);
|
||||
e->setAttribute ("isShell", hasSharedContainer);
|
||||
e->setAttribute ("hasARAExtension", hasARAExtension);
|
||||
|
||||
e->setAttribute ("uid", String::toHexString (deprecatedUid));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool PluginDescription::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName ("PLUGIN"))
|
||||
{
|
||||
name = xml.getStringAttribute ("name");
|
||||
descriptiveName = xml.getStringAttribute ("descriptiveName", name);
|
||||
pluginFormatName = xml.getStringAttribute ("format");
|
||||
category = xml.getStringAttribute ("category");
|
||||
manufacturerName = xml.getStringAttribute ("manufacturer");
|
||||
version = xml.getStringAttribute ("version");
|
||||
fileOrIdentifier = xml.getStringAttribute ("file");
|
||||
isInstrument = xml.getBoolAttribute ("isInstrument", false);
|
||||
lastFileModTime = Time (xml.getStringAttribute ("fileTime").getHexValue64());
|
||||
lastInfoUpdateTime = Time (xml.getStringAttribute ("infoUpdateTime").getHexValue64());
|
||||
numInputChannels = xml.getIntAttribute ("numInputs");
|
||||
numOutputChannels = xml.getIntAttribute ("numOutputs");
|
||||
hasSharedContainer = xml.getBoolAttribute ("isShell", false);
|
||||
hasARAExtension = xml.getBoolAttribute ("hasARAExtension", false);
|
||||
|
||||
deprecatedUid = xml.getStringAttribute ("uid").getHexValue32();
|
||||
uniqueId = xml.getStringAttribute ("uniqueId", "0").getHexValue32();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A small class to represent some facts about a particular type of plug-in.
|
||||
|
||||
This class is for storing and managing the details about a plug-in without
|
||||
actually having to load an instance of it.
|
||||
|
||||
A KnownPluginList contains a list of PluginDescription objects.
|
||||
|
||||
@see KnownPluginList
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API PluginDescription
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
PluginDescription() = default;
|
||||
|
||||
PluginDescription (const PluginDescription&) = default;
|
||||
PluginDescription (PluginDescription&&) = default;
|
||||
|
||||
PluginDescription& operator= (const PluginDescription&) = default;
|
||||
PluginDescription& operator= (PluginDescription&&) = default;
|
||||
|
||||
//==============================================================================
|
||||
/** The name of the plug-in. */
|
||||
String name;
|
||||
|
||||
/** A more descriptive name for the plug-in.
|
||||
This may be the same as the 'name' field, but some plug-ins may provide an
|
||||
alternative name.
|
||||
*/
|
||||
String descriptiveName;
|
||||
|
||||
/** The plug-in format, e.g. "VST", "AudioUnit", etc. */
|
||||
String pluginFormatName;
|
||||
|
||||
/** A category, such as "Dynamics", "Reverbs", etc. */
|
||||
String category;
|
||||
|
||||
/** The manufacturer. */
|
||||
String manufacturerName;
|
||||
|
||||
/** The version. This string doesn't have any particular format. */
|
||||
String version;
|
||||
|
||||
/** Either the file containing the plug-in module, or some other unique way
|
||||
of identifying it.
|
||||
|
||||
E.g. for an AU, this would be an ID string that the component manager
|
||||
could use to retrieve the plug-in. For a VST, it's the file path.
|
||||
*/
|
||||
String fileOrIdentifier;
|
||||
|
||||
/** The last time the plug-in file was changed.
|
||||
This is handy when scanning for new or changed plug-ins.
|
||||
*/
|
||||
Time lastFileModTime;
|
||||
|
||||
/** The last time that this information was updated. This would typically have
|
||||
been during a scan when this plugin was first tested or found to have changed.
|
||||
*/
|
||||
Time lastInfoUpdateTime;
|
||||
|
||||
/** Deprecated: New projects should use uniqueId instead.
|
||||
|
||||
A unique ID for the plug-in.
|
||||
|
||||
Note that this might not be unique between formats, e.g. a VST and some
|
||||
other format might actually have the same id.
|
||||
|
||||
@see createIdentifierString
|
||||
*/
|
||||
int deprecatedUid = 0;
|
||||
|
||||
/** A unique ID for the plug-in.
|
||||
|
||||
Note that this might not be unique between formats, e.g. a VST and some
|
||||
other format might actually have the same id.
|
||||
|
||||
The uniqueId field replaces the deprecatedUid field, and fixes an issue
|
||||
where VST3 plugins with matching FUIDs would generate different uid
|
||||
values depending on the platform. The deprecatedUid field is kept for
|
||||
backwards compatibility, allowing existing hosts to migrate from the
|
||||
old uid to the new uniqueId.
|
||||
|
||||
@see createIdentifierString
|
||||
*/
|
||||
int uniqueId = 0;
|
||||
|
||||
/** True if the plug-in identifies itself as a synthesiser. */
|
||||
bool isInstrument = false;
|
||||
|
||||
/** The number of inputs. */
|
||||
int numInputChannels = 0;
|
||||
|
||||
/** The number of outputs. */
|
||||
int numOutputChannels = 0;
|
||||
|
||||
/** True if the plug-in is part of a multi-type container, e.g. a VST Shell. */
|
||||
bool hasSharedContainer = false;
|
||||
|
||||
/** True if the plug-in is ARA enabled and can supply a valid ARAFactoryWrapper. */
|
||||
bool hasARAExtension = false;
|
||||
|
||||
/** Returns true if the two descriptions refer to the same plug-in.
|
||||
|
||||
This isn't quite as simple as them just having the same file (because of
|
||||
shell plug-ins).
|
||||
*/
|
||||
bool isDuplicateOf (const PluginDescription& other) const noexcept;
|
||||
|
||||
/** Return true if this description is equivalent to another one which created the
|
||||
given identifier string.
|
||||
|
||||
Note that this isn't quite as simple as them just calling createIdentifierString()
|
||||
and comparing the strings, because the identifiers can differ (thanks to shell plug-ins).
|
||||
*/
|
||||
bool matchesIdentifierString (const String& identifierString) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string that can be saved and used to uniquely identify the
|
||||
plugin again.
|
||||
|
||||
This contains less info than the XML encoding, and is independent of the
|
||||
plug-in's file location, so can be used to store a plug-in ID for use
|
||||
across different machines.
|
||||
*/
|
||||
String createIdentifierString() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an XML object containing these details.
|
||||
|
||||
@see loadFromXml
|
||||
*/
|
||||
std::unique_ptr<XmlElement> createXml() const;
|
||||
|
||||
/** Reloads the info in this structure from an XML record that was previously
|
||||
saved with createXML().
|
||||
|
||||
Returns true if the XML was a valid plug-in description.
|
||||
*/
|
||||
bool loadFromXml (const XmlElement& xml);
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
JUCE_LEAK_DETECTOR (PluginDescription)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Loading…
Add table
Add a link
Reference in a new issue