git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
292
deps/juce/modules/juce_audio_processors/processors/juce_AudioPluginInstance.cpp
vendored
Normal file
292
deps/juce/modules/juce_audio_processors/processors/juce_AudioPluginInstance.cpp
vendored
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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.add (TRANS("on"));
|
||||
onStrings.add (TRANS("yes"));
|
||||
onStrings.add (TRANS("true"));
|
||||
|
||||
offStrings.add (TRANS("off"));
|
||||
offStrings.add (TRANS("no"));
|
||||
offStrings.add (TRANS("false"));
|
||||
}
|
||||
|
||||
AudioPluginInstance::Parameter::~Parameter() = default;
|
||||
|
||||
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))
|
||||
{
|
||||
jassert (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))
|
||||
{
|
||||
jassert (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
|
199
deps/juce/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h
vendored
Normal file
199
deps/juce/modules/juce_audio_processors/processors/juce_AudioPluginInstance.h
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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;
|
||||
|
||||
/**
|
||||
A parameter with functions which are useful for plugin hosts.
|
||||
*/
|
||||
struct HostedParameter : public AudioProcessorParameter
|
||||
{
|
||||
/** Returns an ID which 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;
|
||||
};
|
||||
|
||||
/** 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;
|
||||
|
||||
#ifndef DOXYGEN
|
||||
/** 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;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Structure used to describe plugin parameters */
|
||||
struct Parameter : public HostedParameter
|
||||
{
|
||||
public:
|
||||
Parameter();
|
||||
~Parameter() override;
|
||||
|
||||
String getText (float value, int maximumStringLength) const override;
|
||||
float getValueForText (const String& text) const override;
|
||||
|
||||
private:
|
||||
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
|
1627
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
vendored
Normal file
1627
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1519
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessor.h
vendored
Normal file
1519
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessor.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
230
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp
vendored
Normal file
230
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor& p) noexcept : processor (p)
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
|
||||
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* p) noexcept : processor (*p)
|
||||
{
|
||||
// the filter must be valid..
|
||||
jassert (p != nullptr);
|
||||
initialise();
|
||||
}
|
||||
|
||||
AudioProcessorEditor::~AudioProcessorEditor()
|
||||
{
|
||||
splashScreen.deleteAndZero();
|
||||
|
||||
// if this fails, then the wrapper hasn't called editorBeingDeleted() on the
|
||||
// filter for some reason..
|
||||
jassert (processor.getActiveEditor() != this);
|
||||
removeComponentListener (resizeListener.get());
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {}
|
||||
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }
|
||||
|
||||
bool AudioProcessorEditor::supportsHostMIDIControllerPresence (bool) { return true; }
|
||||
void AudioProcessorEditor::hostMIDIControllerIsAvailable (bool) {}
|
||||
|
||||
void AudioProcessorEditor::initialise()
|
||||
{
|
||||
/*
|
||||
==========================================================================
|
||||
In accordance with the terms of the JUCE 6 End-Use License Agreement, the
|
||||
JUCE Code in SECTION A cannot be removed, changed or otherwise rendered
|
||||
ineffective unless you have a JUCE Indie or Pro license, or are using
|
||||
JUCE under the GPL v3 license.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
==========================================================================
|
||||
*/
|
||||
|
||||
// BEGIN SECTION A
|
||||
|
||||
splashScreen = new JUCESplashScreen (*this);
|
||||
|
||||
// END SECTION A
|
||||
|
||||
attachConstrainer (&defaultConstrainer);
|
||||
resizeListener.reset (new AudioProcessorEditorListener (*this));
|
||||
addComponentListener (resizeListener.get());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AudioProcessorEditor::setResizable (bool allowHostToResize, bool useBottomRightCornerResizer)
|
||||
{
|
||||
resizableByHost = allowHostToResize;
|
||||
|
||||
const auto hasResizableCorner = (resizableCorner.get() != nullptr);
|
||||
|
||||
if (useBottomRightCornerResizer != hasResizableCorner)
|
||||
{
|
||||
if (useBottomRightCornerResizer)
|
||||
attachResizableCornerComponent();
|
||||
else
|
||||
resizableCorner = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::setResizeLimits (int newMinimumWidth,
|
||||
int newMinimumHeight,
|
||||
int newMaximumWidth,
|
||||
int newMaximumHeight) noexcept
|
||||
{
|
||||
if (constrainer != nullptr && constrainer != &defaultConstrainer)
|
||||
{
|
||||
// if you've set up a custom constrainer then these settings won't have any effect..
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
resizableByHost = (newMinimumWidth != newMaximumWidth || newMinimumHeight != newMaximumHeight);
|
||||
|
||||
defaultConstrainer.setSizeLimits (newMinimumWidth, newMinimumHeight,
|
||||
newMaximumWidth, newMaximumHeight);
|
||||
|
||||
if (constrainer == nullptr)
|
||||
setConstrainer (&defaultConstrainer);
|
||||
|
||||
if (resizableCorner != nullptr)
|
||||
attachResizableCornerComponent();
|
||||
|
||||
setBoundsConstrained (getBounds());
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::setConstrainer (ComponentBoundsConstrainer* newConstrainer)
|
||||
{
|
||||
if (constrainer != newConstrainer)
|
||||
{
|
||||
attachConstrainer (newConstrainer);
|
||||
|
||||
if (constrainer != nullptr)
|
||||
resizableByHost = (newConstrainer->getMinimumWidth() != newConstrainer->getMaximumWidth()
|
||||
|| newConstrainer->getMinimumHeight() != newConstrainer->getMaximumHeight());
|
||||
|
||||
if (resizableCorner != nullptr)
|
||||
attachResizableCornerComponent();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::attachConstrainer (ComponentBoundsConstrainer* newConstrainer)
|
||||
{
|
||||
if (constrainer != newConstrainer)
|
||||
{
|
||||
constrainer = newConstrainer;
|
||||
updatePeer();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::attachResizableCornerComponent()
|
||||
{
|
||||
resizableCorner = std::make_unique<ResizableCornerComponent> (this, constrainer);
|
||||
Component::addChildComponent (resizableCorner.get());
|
||||
resizableCorner->setAlwaysOnTop (true);
|
||||
editorResized (true);
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::setBoundsConstrained (Rectangle<int> newBounds)
|
||||
{
|
||||
if (constrainer == nullptr)
|
||||
{
|
||||
setBounds (newBounds);
|
||||
return;
|
||||
}
|
||||
|
||||
auto currentBounds = getBounds();
|
||||
|
||||
constrainer->setBoundsForComponent (this,
|
||||
newBounds,
|
||||
newBounds.getY() != currentBounds.getY() && newBounds.getBottom() == currentBounds.getBottom(),
|
||||
newBounds.getX() != currentBounds.getX() && newBounds.getRight() == currentBounds.getRight(),
|
||||
newBounds.getY() == currentBounds.getY() && newBounds.getBottom() != currentBounds.getBottom(),
|
||||
newBounds.getX() == currentBounds.getX() && newBounds.getRight() != currentBounds.getRight());
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::editorResized (bool wasResized)
|
||||
{
|
||||
// The host needs to be able to rescale the plug-in editor and applying your own transform will
|
||||
// obliterate it! If you want to scale the whole of your UI use Desktop::setGlobalScaleFactor(),
|
||||
// or, for applying other transforms, consider putting the component you want to transform
|
||||
// in a child of the editor and transform that instead.
|
||||
jassert (getTransform() == hostScaleTransform);
|
||||
|
||||
if (wasResized)
|
||||
{
|
||||
bool resizerHidden = false;
|
||||
|
||||
if (auto* peer = getPeer())
|
||||
resizerHidden = peer->isFullScreen() || peer->isKioskMode();
|
||||
|
||||
if (resizableCorner != nullptr)
|
||||
{
|
||||
resizableCorner->setVisible (! resizerHidden);
|
||||
|
||||
const int resizerSize = 18;
|
||||
resizableCorner->setBounds (getWidth() - resizerSize,
|
||||
getHeight() - resizerSize,
|
||||
resizerSize, resizerSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::updatePeer()
|
||||
{
|
||||
if (isOnDesktop())
|
||||
if (auto* peer = getPeer())
|
||||
peer->setConstrainer (constrainer);
|
||||
}
|
||||
|
||||
void AudioProcessorEditor::setScaleFactor (float newScale)
|
||||
{
|
||||
hostScaleTransform = AffineTransform::scale (newScale);
|
||||
setTransform (hostScaleTransform);
|
||||
|
||||
editorResized (true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
|
||||
createUnityPeerFunctionType juce_createUnityPeerFn = nullptr;
|
||||
|
||||
ComponentPeer* AudioProcessorEditor::createNewPeer (int styleFlags, void* nativeWindow)
|
||||
{
|
||||
if (juce_createUnityPeerFn != nullptr)
|
||||
{
|
||||
ignoreUnused (styleFlags, nativeWindow);
|
||||
return juce_createUnityPeerFn (*this);
|
||||
}
|
||||
|
||||
return Component::createNewPeer (styleFlags, nativeWindow);
|
||||
}
|
||||
|
||||
} // namespace juce
|
244
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h
vendored
Normal file
244
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class AudioProcessorEditorListener;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for the component that acts as the GUI for an AudioProcessor.
|
||||
|
||||
Derive your editor component from this class, and create an instance of it
|
||||
by overriding the AudioProcessor::createEditor() method.
|
||||
|
||||
@see AudioProcessor, GenericAudioProcessorEditor
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API AudioProcessorEditor : public Component
|
||||
{
|
||||
protected:
|
||||
//==============================================================================
|
||||
/** Creates an editor for the specified processor. */
|
||||
AudioProcessorEditor (AudioProcessor&) noexcept;
|
||||
|
||||
/** Creates an editor for the specified processor. */
|
||||
AudioProcessorEditor (AudioProcessor*) noexcept;
|
||||
|
||||
public:
|
||||
/** Destructor. */
|
||||
~AudioProcessorEditor() override;
|
||||
|
||||
//==============================================================================
|
||||
/** The AudioProcessor that this editor represents. */
|
||||
AudioProcessor& processor;
|
||||
|
||||
/** Returns a pointer to the processor that this editor represents.
|
||||
|
||||
This method is here to support legacy code, but it's easier to just use the
|
||||
AudioProcessorEditor::processor member variable directly to get this object.
|
||||
*/
|
||||
AudioProcessor* getAudioProcessor() const noexcept { return &processor; }
|
||||
|
||||
//==============================================================================
|
||||
/** Used by the setParameterHighlighting() method. */
|
||||
struct ParameterControlHighlightInfo
|
||||
{
|
||||
int parameterIndex;
|
||||
bool isHighlighted;
|
||||
Colour suggestedColour;
|
||||
};
|
||||
|
||||
/** Some types of plugin can call this to suggest that the control for a particular
|
||||
parameter should be highlighted.
|
||||
|
||||
Currently only AAX plugins will call this, and implementing it is optional.
|
||||
*/
|
||||
virtual void setControlHighlight (ParameterControlHighlightInfo);
|
||||
|
||||
/** Called by certain plug-in wrappers to find out whether a component is used
|
||||
to control a parameter.
|
||||
|
||||
If the given component represents a particular plugin parameter, then this
|
||||
method should return the index of that parameter. If not, it should return -1.
|
||||
Currently only AAX plugins will call this, and implementing it is optional.
|
||||
*/
|
||||
virtual int getControlParameterIndex (Component&);
|
||||
|
||||
/** Override this method to indicate if your editor supports the presence or
|
||||
absence of a host-provided MIDI controller.
|
||||
|
||||
Currently only AUv3 plug-ins compiled for MacOS 10.13 or iOS 11.0 (or later)
|
||||
support this functionality, and even then the host may choose to ignore this
|
||||
information.
|
||||
|
||||
The default behaviour is to report support for both cases.
|
||||
*/
|
||||
virtual bool supportsHostMIDIControllerPresence (bool hostMIDIControllerIsAvailable);
|
||||
|
||||
/** Called to indicate if a host is providing a MIDI controller when the host
|
||||
reconfigures its layout.
|
||||
|
||||
Use this as an opportunity to hide or display your own onscreen keyboard or
|
||||
other input component.
|
||||
|
||||
Currently only AUv3 plug-ins compiled for MacOS 10.13 or iOS 11.0 (or later)
|
||||
support this functionality.
|
||||
*/
|
||||
virtual void hostMIDIControllerIsAvailable (bool controllerIsAvailable);
|
||||
|
||||
/** Can be called by a host to tell the editor that it should use a non-unity
|
||||
GUI scale.
|
||||
*/
|
||||
virtual void setScaleFactor (float newScale);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets whether the editor is resizable by the host and/or user.
|
||||
|
||||
@param allowHostToResize whether the editor's parent window can be resized
|
||||
by the host. Even if this is false, you can still
|
||||
resize your window yourself by calling setBounds
|
||||
(for example, when a user clicks on a button in
|
||||
your editor to drop out a panel) which will bypass
|
||||
any resizable/constraints checks.
|
||||
@param useBottomRightCornerResizer if this is true, a ResizableCornerComponent will be
|
||||
added to the editor's bottom-right to allow the user
|
||||
to resize the editor regardless of the value of
|
||||
`allowHostToResize`.
|
||||
|
||||
@see setResizeLimits, isResizable
|
||||
*/
|
||||
void setResizable (bool allowHostToResize, bool useBottomRightCornerResizer);
|
||||
|
||||
/** Returns true if the host is allowed to resize the editor's parent window.
|
||||
|
||||
@see setResizable
|
||||
*/
|
||||
bool isResizable() const noexcept { return resizableByHost; }
|
||||
|
||||
/** This sets the maximum and minimum sizes for the window.
|
||||
|
||||
If the window's current size is outside these limits, it will be resized to
|
||||
make sure it's within them.
|
||||
|
||||
If you pass in a different minimum and maximum size, this will mark the editor
|
||||
as resizable by the host.
|
||||
|
||||
A direct call to setBounds() will bypass any constraint checks, but when the
|
||||
window is dragged by the user or resized by other indirect means, the constrainer
|
||||
will limit the numbers involved.
|
||||
|
||||
Note that if you have set a custom constrainer for this editor then this will have
|
||||
no effect, and if you have removed the constrainer with `setConstrainer (nullptr);`
|
||||
then this will re-add the default constrainer with the new limits.
|
||||
|
||||
@see setResizable
|
||||
*/
|
||||
void setResizeLimits (int newMinimumWidth,
|
||||
int newMinimumHeight,
|
||||
int newMaximumWidth,
|
||||
int newMaximumHeight) noexcept;
|
||||
|
||||
/** Returns the bounds constrainer object that this window is using.
|
||||
|
||||
You can access this to change its properties.
|
||||
*/
|
||||
ComponentBoundsConstrainer* getConstrainer() noexcept { return constrainer; }
|
||||
|
||||
/** Sets the bounds-constrainer object to use for resizing and dragging this window.
|
||||
|
||||
A pointer to the object you pass in will be kept, but it won't be deleted
|
||||
by this object, so it's the caller's responsibility to manage it.
|
||||
|
||||
If you pass a nullptr, then no contraints will be placed on the positioning of the window.
|
||||
*/
|
||||
void setConstrainer (ComponentBoundsConstrainer* newConstrainer);
|
||||
|
||||
/** Calls the window's setBounds method, after first checking these bounds
|
||||
with the current constrainer.
|
||||
|
||||
@see setConstrainer
|
||||
*/
|
||||
void setBoundsConstrained (Rectangle<int> newBounds);
|
||||
|
||||
/** Gets a context object, if one is available.
|
||||
|
||||
Returns nullptr if the host does not provide any information that the editor
|
||||
can query.
|
||||
|
||||
The returned pointer is non-owning, so do not attempt to free it.
|
||||
*/
|
||||
AudioProcessorEditorHostContext* getHostContext() const noexcept { return hostContext; }
|
||||
|
||||
/** Sets a context object that can be queried to find information that the host
|
||||
makes available to the plugin.
|
||||
|
||||
You will only need to call this function if you are implementing a plugin host.
|
||||
*/
|
||||
void setHostContext (AudioProcessorEditorHostContext* context) noexcept { hostContext = context; }
|
||||
|
||||
/** The ResizableCornerComponent which is currently being used by this editor,
|
||||
or nullptr if it does not have one.
|
||||
*/
|
||||
std::unique_ptr<ResizableCornerComponent> resizableCorner;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct AudioProcessorEditorListener : public ComponentListener
|
||||
{
|
||||
AudioProcessorEditorListener (AudioProcessorEditor& e) : ed (e) {}
|
||||
|
||||
void componentMovedOrResized (Component&, bool, bool wasResized) override { ed.editorResized (wasResized); }
|
||||
void componentParentHierarchyChanged (Component&) override { ed.updatePeer(); }
|
||||
|
||||
AudioProcessorEditor& ed;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditorListener)
|
||||
};
|
||||
|
||||
ComponentPeer* createNewPeer (int styleFlags, void*) override;
|
||||
|
||||
//==============================================================================
|
||||
void initialise();
|
||||
void editorResized (bool wasResized);
|
||||
void updatePeer();
|
||||
void attachConstrainer (ComponentBoundsConstrainer*);
|
||||
void attachResizableCornerComponent();
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<AudioProcessorEditorListener> resizeListener;
|
||||
bool resizableByHost = false;
|
||||
ComponentBoundsConstrainer defaultConstrainer;
|
||||
ComponentBoundsConstrainer* constrainer = nullptr;
|
||||
AudioProcessorEditorHostContext* hostContext = nullptr;
|
||||
Component::SafePointer<Component> splashScreen;
|
||||
AffineTransform hostScaleTransform;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor)
|
||||
};
|
||||
|
||||
} // namespace juce
|
78
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorEditorHostContext.h
vendored
Normal file
78
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorEditorHostContext.h
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/** This wraps a context menu for a specific parameter, as provided by the host.
|
||||
|
||||
You can choose to create a standard PopupMenu to display the host-provided
|
||||
options. Alternatively, you can ask the host to display a native menu at
|
||||
a specific location.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct HostProvidedContextMenu
|
||||
{
|
||||
virtual ~HostProvidedContextMenu() = default;
|
||||
|
||||
/** Get a PopupMenu holding entries specified by the host.
|
||||
|
||||
Most hosts will populate this menu with options that relate to the
|
||||
parameter, such as displaying its automation lane. You are free
|
||||
to modify this menu before displaying it, if you wish to add additional
|
||||
options.
|
||||
*/
|
||||
virtual PopupMenu getEquivalentPopupMenu() const = 0;
|
||||
|
||||
/** Asks the host to display its native menu at a location relative
|
||||
to the top left corner of the editor.
|
||||
|
||||
The position you provide should be in logical pixels. To display
|
||||
the menu next to the mouse cursor, call Component::getMouseXYRelative()
|
||||
on your editor and pass the result to this function.
|
||||
*/
|
||||
virtual void showNativeMenu (Point<int> pos) const = 0;
|
||||
};
|
||||
|
||||
/** Calling AudioProcessorEditor::getHostContext() may return a pointer to an
|
||||
instance of this class.
|
||||
|
||||
At the moment, this can be used to retrieve context menus for parameters in
|
||||
compatible VST3 hosts. Additional extensions may be added here in the future.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct AudioProcessorEditorHostContext
|
||||
{
|
||||
virtual ~AudioProcessorEditorHostContext() = default;
|
||||
|
||||
/** Returns an object which can be used to display a context menu for the
|
||||
parameter with the given index.
|
||||
*/
|
||||
virtual std::unique_ptr<HostProvidedContextMenu> getContextMenuForParameterIndex (const AudioProcessorParameter *) const = 0;
|
||||
};
|
||||
|
||||
} // namespace juce
|
1588
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
vendored
Normal file
1588
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
456
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h
vendored
Normal file
456
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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,
|
||||
private AsyncUpdater
|
||||
{
|
||||
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
|
||||
{
|
||||
NodeID() {}
|
||||
explicit NodeID (uint32 i) : uid (i) {}
|
||||
|
||||
uint32 uid = 0;
|
||||
|
||||
bool operator== (const NodeID& other) const noexcept { return uid == other.uid; }
|
||||
bool operator!= (const NodeID& other) const noexcept { return uid != other.uid; }
|
||||
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.
|
||||
*/
|
||||
struct NodeAndChannel
|
||||
{
|
||||
NodeID nodeID;
|
||||
int channelIndex;
|
||||
|
||||
bool isMIDI() const noexcept { return channelIndex == midiChannelIndex; }
|
||||
|
||||
bool operator== (const NodeAndChannel& other) const noexcept { return nodeID == other.nodeID && channelIndex == other.channelIndex; }
|
||||
bool operator!= (const NodeAndChannel& other) const noexcept { return ! operator== (other); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** 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;
|
||||
|
||||
/** Tell this node to bypass processing. */
|
||||
void setBypassed (bool shouldBeBypassed) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** A convenient typedef for referring to a pointer to a node object. */
|
||||
using Ptr = ReferenceCountedObjectPtr<Node>;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class AudioProcessorGraph;
|
||||
template <typename Float>
|
||||
friend struct GraphRenderSequence;
|
||||
template <typename Float>
|
||||
friend struct RenderSequenceBuilder;
|
||||
|
||||
struct Connection
|
||||
{
|
||||
Node* otherNode;
|
||||
int otherChannel, thisChannel;
|
||||
|
||||
bool operator== (const Connection&) const noexcept;
|
||||
};
|
||||
|
||||
std::unique_ptr<AudioProcessor> processor;
|
||||
Array<Connection> inputs, outputs;
|
||||
bool isPrepared = false;
|
||||
std::atomic<bool> bypassed { false };
|
||||
|
||||
Node (NodeID, std::unique_ptr<AudioProcessor>) noexcept;
|
||||
|
||||
void setParentGraph (AudioProcessorGraph*) const;
|
||||
void prepare (double newSampleRate, int newBlockSize, AudioProcessorGraph*, ProcessingPrecision);
|
||||
void unprepare();
|
||||
|
||||
template <typename Sample>
|
||||
void processBlock (AudioBuffer<Sample>& audio, MidiBuffer& midi)
|
||||
{
|
||||
const ScopedLock lock (processorLock);
|
||||
processor->processBlock (audio, midi);
|
||||
}
|
||||
|
||||
template <typename Sample>
|
||||
void processBlockBypassed (AudioBuffer<Sample>& audio, MidiBuffer& midi)
|
||||
{
|
||||
const ScopedLock lock (processorLock);
|
||||
processor->processBlockBypassed (audio, midi);
|
||||
}
|
||||
|
||||
CriticalSection processorLock;
|
||||
|
||||
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
|
||||
{
|
||||
//==============================================================================
|
||||
Connection() = default;
|
||||
Connection (NodeAndChannel source, NodeAndChannel destination) noexcept;
|
||||
|
||||
Connection (const Connection&) = default;
|
||||
Connection& operator= (const Connection&) = default;
|
||||
|
||||
bool operator== (const Connection&) const noexcept;
|
||||
bool operator!= (const Connection&) const noexcept;
|
||||
bool operator< (const Connection&) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** 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 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Deletes all nodes and connections from this graph.
|
||||
Any processor objects in the graph will be deleted.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/** Returns the array of nodes in the graph. */
|
||||
const ReferenceCountedArray<Node>& getNodes() const noexcept { return nodes; }
|
||||
|
||||
/** Returns the number of nodes in the graph. */
|
||||
int getNumNodes() const noexcept { return nodes.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 nodes[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, NodeID nodeId = {});
|
||||
|
||||
/** Deletes a node within the graph which has the specified ID.
|
||||
This will also delete any connections that are attached to this node.
|
||||
*/
|
||||
Node::Ptr removeNode (NodeID);
|
||||
|
||||
/** Deletes a node within the graph.
|
||||
This will also delete any connections that are attached to this node.
|
||||
*/
|
||||
Node::Ptr removeNode (Node*);
|
||||
|
||||
/** 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 (Node& source, Node& 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&);
|
||||
|
||||
/** Deletes the given connection. */
|
||||
bool removeConnection (const Connection&);
|
||||
|
||||
/** Removes all connections from the specified node. */
|
||||
bool disconnectNode (NodeID);
|
||||
|
||||
/** 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();
|
||||
|
||||
//==============================================================================
|
||||
/** 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:
|
||||
struct PrepareSettings
|
||||
{
|
||||
ProcessingPrecision precision = ProcessingPrecision::singlePrecision;
|
||||
double sampleRate = 0.0;
|
||||
int blockSize = 0;
|
||||
bool valid = false;
|
||||
|
||||
using Tied = std::tuple<const ProcessingPrecision&,
|
||||
const double&,
|
||||
const int&,
|
||||
const bool&>;
|
||||
|
||||
Tied tie() const noexcept { return std::tie (precision, sampleRate, blockSize, valid); }
|
||||
|
||||
bool operator== (const PrepareSettings& other) const noexcept { return tie() == other.tie(); }
|
||||
bool operator!= (const PrepareSettings& other) const noexcept { return tie() != other.tie(); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ReferenceCountedArray<Node> nodes;
|
||||
NodeID lastNodeID = {};
|
||||
|
||||
struct RenderSequenceFloat;
|
||||
struct RenderSequenceDouble;
|
||||
std::unique_ptr<RenderSequenceFloat> renderSequenceFloat;
|
||||
std::unique_ptr<RenderSequenceDouble> renderSequenceDouble;
|
||||
|
||||
PrepareSettings prepareSettings;
|
||||
|
||||
friend class AudioGraphIOProcessor;
|
||||
|
||||
std::atomic<bool> isPrepared { false };
|
||||
|
||||
void topologyChanged();
|
||||
void unprepare();
|
||||
void handleAsyncUpdate() override;
|
||||
void clearRenderingSequence();
|
||||
void buildRenderingSequence();
|
||||
bool anyNodesNeedPreparing() const noexcept;
|
||||
bool isConnected (Node* src, int sourceChannel, Node* dest, int destChannel) const noexcept;
|
||||
bool isAnInputTo (Node& src, Node& dst, int recursionCheck) const noexcept;
|
||||
bool canConnect (Node* src, int sourceChannel, Node* dest, int destChannel) const noexcept;
|
||||
bool isLegal (Node* src, int sourceChannel, Node* dest, int destChannel) const noexcept;
|
||||
static void getNodeConnections (Node&, std::vector<Connection>&);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorGraph)
|
||||
};
|
||||
|
||||
} // namespace juce
|
137
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorListener.h
vendored
Normal file
137
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorListener.h
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
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
|
||||
{
|
||||
bool latencyChanged = false;
|
||||
bool parameterInfoChanged = false;
|
||||
bool programChanged = false;
|
||||
|
||||
ChangeDetails withLatencyChanged (bool b) const noexcept { return with (&ChangeDetails::latencyChanged, b); }
|
||||
ChangeDetails withParameterInfoChanged (bool b) const noexcept { return with (&ChangeDetails::parameterInfoChanged, b); }
|
||||
ChangeDetails withProgramChanged (bool b) const noexcept { return with (&ChangeDetails::programChanged, b); }
|
||||
|
||||
static ChangeDetails getAllChanged()
|
||||
{
|
||||
return ChangeDetails{}.withLatencyChanged (true)
|
||||
.withParameterInfoChanged (true)
|
||||
.withProgramChanged (true);
|
||||
}
|
||||
|
||||
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
|
305
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h
vendored
Normal file
305
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h
vendored
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class AudioProcessor;
|
||||
|
||||
//==============================================================================
|
||||
/** 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;
|
||||
|
||||
/** 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 AudioProcessor::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; }
|
||||
|
||||
//==============================================================================
|
||||
/** 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;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
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;
|
||||
};
|
||||
|
||||
/** 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);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class AudioProcessor;
|
||||
friend class LegacyAudioParameter;
|
||||
AudioProcessor* processor = nullptr;
|
||||
int parameterIndex = -1;
|
||||
CriticalSection listenerLock;
|
||||
Array<Listener*> listeners;
|
||||
mutable StringArray valueStrings;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
bool isPerformingGesture = false;
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter)
|
||||
};
|
||||
|
||||
} // namespace juce
|
321
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.cpp
vendored
Normal file
321
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.cpp
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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 : 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 : 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
|
254
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h
vendored
Normal file
254
deps/juce/modules/juce_audio_processors/processors/juce_AudioProcessorParameterGroup.h
vendored
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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 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)...);
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
[[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); }
|
||||
#endif
|
||||
|
||||
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
|
616
deps/juce/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp
vendored
Normal file
616
deps/juce/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp
vendored
Normal file
@ -0,0 +1,616 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class ParameterListener : private AudioProcessorParameter::Listener,
|
||||
private AudioProcessorListener,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
ParameterListener (AudioProcessor& proc, AudioProcessorParameter& param)
|
||||
: processor (proc), parameter (param), isLegacyParam (LegacyAudioParameter::isLegacy (¶m))
|
||||
{
|
||||
if (isLegacyParam)
|
||||
processor.addListener (this);
|
||||
else
|
||||
parameter.addListener (this);
|
||||
|
||||
startTimer (100);
|
||||
}
|
||||
|
||||
~ParameterListener() override
|
||||
{
|
||||
if (isLegacyParam)
|
||||
processor.removeListener (this);
|
||||
else
|
||||
parameter.removeListener (this);
|
||||
}
|
||||
|
||||
AudioProcessorParameter& getParameter() const noexcept
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
|
||||
virtual void handleNewParameterValue() = 0;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void parameterValueChanged (int, float) override
|
||||
{
|
||||
parameterValueHasChanged = 1;
|
||||
}
|
||||
|
||||
void parameterGestureChanged (int, bool) override {}
|
||||
|
||||
//==============================================================================
|
||||
void audioProcessorParameterChanged (AudioProcessor*, int index, float) override
|
||||
{
|
||||
if (index == parameter.getParameterIndex())
|
||||
parameterValueHasChanged = 1;
|
||||
}
|
||||
|
||||
void audioProcessorChanged (AudioProcessor*, const ChangeDetails&) override {}
|
||||
|
||||
//==============================================================================
|
||||
void timerCallback() override
|
||||
{
|
||||
if (parameterValueHasChanged.compareAndSetBool (0, 1))
|
||||
{
|
||||
handleNewParameterValue();
|
||||
startTimerHz (50);
|
||||
}
|
||||
else
|
||||
{
|
||||
startTimer (jmin (250, getTimerInterval() + 10));
|
||||
}
|
||||
}
|
||||
|
||||
AudioProcessor& processor;
|
||||
AudioProcessorParameter& parameter;
|
||||
Atomic<int> parameterValueHasChanged { 0 };
|
||||
const bool isLegacyParam;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterListener)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class BooleanParameterComponent final : public Component,
|
||||
private ParameterListener
|
||||
{
|
||||
public:
|
||||
BooleanParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
|
||||
: ParameterListener (proc, param)
|
||||
{
|
||||
// Set the initial value.
|
||||
handleNewParameterValue();
|
||||
|
||||
button.onClick = [this] { buttonClicked(); };
|
||||
|
||||
addAndMakeVisible (button);
|
||||
}
|
||||
|
||||
void paint (Graphics&) override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto area = getLocalBounds();
|
||||
area.removeFromLeft (8);
|
||||
button.setBounds (area.reduced (0, 10));
|
||||
}
|
||||
|
||||
private:
|
||||
void handleNewParameterValue() override
|
||||
{
|
||||
button.setToggleState (isParameterOn(), dontSendNotification);
|
||||
}
|
||||
|
||||
void buttonClicked()
|
||||
{
|
||||
if (isParameterOn() != button.getToggleState())
|
||||
{
|
||||
getParameter().beginChangeGesture();
|
||||
getParameter().setValueNotifyingHost (button.getToggleState() ? 1.0f : 0.0f);
|
||||
getParameter().endChangeGesture();
|
||||
}
|
||||
}
|
||||
|
||||
bool isParameterOn() const { return getParameter().getValue() >= 0.5f; }
|
||||
|
||||
ToggleButton button;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BooleanParameterComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class SwitchParameterComponent final : public Component,
|
||||
private ParameterListener
|
||||
{
|
||||
public:
|
||||
SwitchParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
|
||||
: ParameterListener (proc, param)
|
||||
{
|
||||
for (auto& button : buttons)
|
||||
{
|
||||
button.setRadioGroupId (293847);
|
||||
button.setClickingTogglesState (true);
|
||||
}
|
||||
|
||||
buttons[0].setButtonText (getParameter().getText (0.0f, 16));
|
||||
buttons[1].setButtonText (getParameter().getText (1.0f, 16));
|
||||
|
||||
buttons[0].setConnectedEdges (Button::ConnectedOnRight);
|
||||
buttons[1].setConnectedEdges (Button::ConnectedOnLeft);
|
||||
|
||||
// Set the initial value.
|
||||
buttons[0].setToggleState (true, dontSendNotification);
|
||||
handleNewParameterValue();
|
||||
|
||||
buttons[1].onStateChange = [this] { rightButtonChanged(); };
|
||||
|
||||
for (auto& button : buttons)
|
||||
addAndMakeVisible (button);
|
||||
}
|
||||
|
||||
void paint (Graphics&) override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto area = getLocalBounds().reduced (0, 8);
|
||||
area.removeFromLeft (8);
|
||||
|
||||
for (auto& button : buttons)
|
||||
button.setBounds (area.removeFromLeft (80));
|
||||
}
|
||||
|
||||
private:
|
||||
void handleNewParameterValue() override
|
||||
{
|
||||
bool newState = isParameterOn();
|
||||
|
||||
if (buttons[1].getToggleState() != newState)
|
||||
{
|
||||
buttons[1].setToggleState (newState, dontSendNotification);
|
||||
buttons[0].setToggleState (! newState, dontSendNotification);
|
||||
}
|
||||
}
|
||||
|
||||
void rightButtonChanged()
|
||||
{
|
||||
auto buttonState = buttons[1].getToggleState();
|
||||
|
||||
if (isParameterOn() != buttonState)
|
||||
{
|
||||
getParameter().beginChangeGesture();
|
||||
|
||||
if (getParameter().getAllValueStrings().isEmpty())
|
||||
{
|
||||
getParameter().setValueNotifyingHost (buttonState ? 1.0f : 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When a parameter provides a list of strings we must set its
|
||||
// value using those strings, rather than a float, because VSTs can
|
||||
// have uneven spacing between the different allowed values and we
|
||||
// want the snapping behaviour to be consistent with what we do with
|
||||
// a combo box.
|
||||
auto selectedText = buttons[buttonState ? 1 : 0].getButtonText();
|
||||
getParameter().setValueNotifyingHost (getParameter().getValueForText (selectedText));
|
||||
}
|
||||
|
||||
getParameter().endChangeGesture();
|
||||
}
|
||||
}
|
||||
|
||||
bool isParameterOn() const
|
||||
{
|
||||
if (getParameter().getAllValueStrings().isEmpty())
|
||||
return getParameter().getValue() > 0.5f;
|
||||
|
||||
auto index = getParameter().getAllValueStrings()
|
||||
.indexOf (getParameter().getCurrentValueAsText());
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
// The parameter is producing some unexpected text, so we'll do
|
||||
// some linear interpolation.
|
||||
index = roundToInt (getParameter().getValue());
|
||||
}
|
||||
|
||||
return index == 1;
|
||||
}
|
||||
|
||||
TextButton buttons[2];
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SwitchParameterComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ChoiceParameterComponent final : public Component,
|
||||
private ParameterListener
|
||||
{
|
||||
public:
|
||||
ChoiceParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
|
||||
: ParameterListener (proc, param),
|
||||
parameterValues (getParameter().getAllValueStrings())
|
||||
{
|
||||
box.addItemList (parameterValues, 1);
|
||||
|
||||
// Set the initial value.
|
||||
handleNewParameterValue();
|
||||
|
||||
box.onChange = [this] { boxChanged(); };
|
||||
addAndMakeVisible (box);
|
||||
}
|
||||
|
||||
void paint (Graphics&) override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto area = getLocalBounds();
|
||||
area.removeFromLeft (8);
|
||||
box.setBounds (area.reduced (0, 10));
|
||||
}
|
||||
|
||||
private:
|
||||
void handleNewParameterValue() override
|
||||
{
|
||||
auto index = parameterValues.indexOf (getParameter().getCurrentValueAsText());
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
// The parameter is producing some unexpected text, so we'll do
|
||||
// some linear interpolation.
|
||||
index = roundToInt (getParameter().getValue() * (float) (parameterValues.size() - 1));
|
||||
}
|
||||
|
||||
box.setSelectedItemIndex (index);
|
||||
}
|
||||
|
||||
void boxChanged()
|
||||
{
|
||||
if (getParameter().getCurrentValueAsText() != box.getText())
|
||||
{
|
||||
getParameter().beginChangeGesture();
|
||||
|
||||
// When a parameter provides a list of strings we must set its
|
||||
// value using those strings, rather than a float, because VSTs can
|
||||
// have uneven spacing between the different allowed values.
|
||||
getParameter().setValueNotifyingHost (getParameter().getValueForText (box.getText()));
|
||||
|
||||
getParameter().endChangeGesture();
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox box;
|
||||
const StringArray parameterValues;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoiceParameterComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class SliderParameterComponent final : public Component,
|
||||
private ParameterListener
|
||||
{
|
||||
public:
|
||||
SliderParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
|
||||
: ParameterListener (proc, param)
|
||||
{
|
||||
if (getParameter().getNumSteps() != AudioProcessor::getDefaultNumParameterSteps())
|
||||
slider.setRange (0.0, 1.0, 1.0 / (getParameter().getNumSteps() - 1.0));
|
||||
else
|
||||
slider.setRange (0.0, 1.0);
|
||||
|
||||
slider.setDoubleClickReturnValue (true, param.getDefaultValue());
|
||||
|
||||
slider.setScrollWheelEnabled (false);
|
||||
addAndMakeVisible (slider);
|
||||
|
||||
valueLabel.setColour (Label::outlineColourId, slider.findColour (Slider::textBoxOutlineColourId));
|
||||
valueLabel.setBorderSize ({ 1, 1, 1, 1 });
|
||||
valueLabel.setJustificationType (Justification::centred);
|
||||
addAndMakeVisible (valueLabel);
|
||||
|
||||
// Set the initial value.
|
||||
handleNewParameterValue();
|
||||
|
||||
slider.onValueChange = [this] { sliderValueChanged(); };
|
||||
slider.onDragStart = [this] { sliderStartedDragging(); };
|
||||
slider.onDragEnd = [this] { sliderStoppedDragging(); };
|
||||
}
|
||||
|
||||
void paint (Graphics&) override {}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto area = getLocalBounds().reduced (0, 10);
|
||||
|
||||
valueLabel.setBounds (area.removeFromRight (80));
|
||||
|
||||
area.removeFromLeft (6);
|
||||
slider.setBounds (area);
|
||||
}
|
||||
|
||||
private:
|
||||
void updateTextDisplay()
|
||||
{
|
||||
valueLabel.setText (getParameter().getCurrentValueAsText(), dontSendNotification);
|
||||
}
|
||||
|
||||
void handleNewParameterValue() override
|
||||
{
|
||||
if (! isDragging)
|
||||
{
|
||||
slider.setValue (getParameter().getValue(), dontSendNotification);
|
||||
updateTextDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
void sliderValueChanged()
|
||||
{
|
||||
auto newVal = (float) slider.getValue();
|
||||
|
||||
if (getParameter().getValue() != newVal)
|
||||
{
|
||||
if (! isDragging)
|
||||
getParameter().beginChangeGesture();
|
||||
|
||||
getParameter().setValueNotifyingHost ((float) slider.getValue());
|
||||
updateTextDisplay();
|
||||
|
||||
if (! isDragging)
|
||||
getParameter().endChangeGesture();
|
||||
}
|
||||
}
|
||||
|
||||
void sliderStartedDragging()
|
||||
{
|
||||
isDragging = true;
|
||||
getParameter().beginChangeGesture();
|
||||
}
|
||||
|
||||
void sliderStoppedDragging()
|
||||
{
|
||||
isDragging = false;
|
||||
getParameter().endChangeGesture();
|
||||
}
|
||||
|
||||
Slider slider { Slider::LinearHorizontal, Slider::TextEntryBoxPosition::NoTextBox };
|
||||
Label valueLabel;
|
||||
bool isDragging = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderParameterComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ParameterDisplayComponent : public Component,
|
||||
private AudioProcessorListener,
|
||||
private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
ParameterDisplayComponent (AudioProcessorEditor& editorIn, AudioProcessorParameter& param)
|
||||
: editor (editorIn), parameter (param)
|
||||
{
|
||||
editor.processor.addListener (this);
|
||||
|
||||
parameterName.setText (parameter.getName (128), dontSendNotification);
|
||||
parameterName.setJustificationType (Justification::centredRight);
|
||||
parameterName.setInterceptsMouseClicks (false, false);
|
||||
addAndMakeVisible (parameterName);
|
||||
|
||||
parameterLabel.setText (parameter.getLabel(), dontSendNotification);
|
||||
parameterLabel.setInterceptsMouseClicks (false, false);
|
||||
addAndMakeVisible (parameterLabel);
|
||||
|
||||
addAndMakeVisible (*(parameterComp = createParameterComp (editor.processor)));
|
||||
|
||||
setSize (400, 40);
|
||||
}
|
||||
|
||||
~ParameterDisplayComponent() override
|
||||
{
|
||||
cancelPendingUpdate();
|
||||
editor.processor.removeListener (this);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto area = getLocalBounds();
|
||||
|
||||
parameterName.setBounds (area.removeFromLeft (100));
|
||||
parameterLabel.setBounds (area.removeFromRight (50));
|
||||
parameterComp->setBounds (area);
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent& e) override
|
||||
{
|
||||
if (e.mods.isRightButtonDown())
|
||||
if (auto* context = editor.getHostContext())
|
||||
if (auto menu = context->getContextMenuForParameterIndex (¶meter))
|
||||
menu->getEquivalentPopupMenu().showMenuAsync (PopupMenu::Options().withTargetComponent (this)
|
||||
.withMousePosition());
|
||||
}
|
||||
|
||||
private:
|
||||
AudioProcessorEditor& editor;
|
||||
AudioProcessorParameter& parameter;
|
||||
Label parameterName, parameterLabel;
|
||||
std::unique_ptr<Component> parameterComp;
|
||||
|
||||
std::unique_ptr<Component> createParameterComp (AudioProcessor& processor) const
|
||||
{
|
||||
// The AU, AUv3 and VST (only via a .vstxml file) SDKs support
|
||||
// marking a parameter as boolean. If you want consistency across
|
||||
// all formats then it might be best to use a
|
||||
// SwitchParameterComponent instead.
|
||||
if (parameter.isBoolean())
|
||||
return std::make_unique<BooleanParameterComponent> (processor, parameter);
|
||||
|
||||
// Most hosts display any parameter with just two steps as a switch.
|
||||
if (parameter.getNumSteps() == 2)
|
||||
return std::make_unique<SwitchParameterComponent> (processor, parameter);
|
||||
|
||||
// If we have a list of strings to represent the different states a
|
||||
// parameter can be in then we should present a dropdown allowing a
|
||||
// user to pick one of them.
|
||||
if (! parameter.getAllValueStrings().isEmpty()
|
||||
&& std::abs (parameter.getNumSteps() - parameter.getAllValueStrings().size()) <= 1)
|
||||
return std::make_unique<ChoiceParameterComponent> (processor, parameter);
|
||||
|
||||
// Everything else can be represented as a slider.
|
||||
return std::make_unique<SliderParameterComponent> (processor, parameter);
|
||||
}
|
||||
|
||||
void audioProcessorParameterChanged (AudioProcessor*, int, float) override {}
|
||||
|
||||
void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override
|
||||
{
|
||||
if (! details.parameterInfoChanged)
|
||||
return;
|
||||
|
||||
if (MessageManager::getInstance()->isThisTheMessageThread())
|
||||
handleAsyncUpdate();
|
||||
else
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
parameterName .setText (parameter.getName (128), dontSendNotification);
|
||||
parameterLabel.setText (parameter.getLabel(), dontSendNotification);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterDisplayComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct ParamControlItem : public TreeViewItem
|
||||
{
|
||||
ParamControlItem (AudioProcessorEditor& editorIn, AudioProcessorParameter& paramIn)
|
||||
: editor (editorIn), param (paramIn) {}
|
||||
|
||||
bool mightContainSubItems() override { return false; }
|
||||
|
||||
std::unique_ptr<Component> createItemComponent() override
|
||||
{
|
||||
return std::make_unique<ParameterDisplayComponent> (editor, param);
|
||||
}
|
||||
|
||||
int getItemHeight() const override { return 40; }
|
||||
|
||||
AudioProcessorEditor& editor;
|
||||
AudioProcessorParameter& param;
|
||||
};
|
||||
|
||||
struct ParameterGroupItem : public TreeViewItem
|
||||
{
|
||||
ParameterGroupItem (AudioProcessorEditor& editor, const AudioProcessorParameterGroup& group)
|
||||
: name (group.getName())
|
||||
{
|
||||
for (auto* node : group)
|
||||
{
|
||||
if (auto* param = node->getParameter())
|
||||
if (param->isAutomatable())
|
||||
addSubItem (new ParamControlItem (editor, *param));
|
||||
|
||||
if (auto* inner = node->getGroup())
|
||||
{
|
||||
auto groupItem = std::make_unique<ParameterGroupItem> (editor, *inner);
|
||||
|
||||
if (groupItem->getNumSubItems() != 0)
|
||||
addSubItem (groupItem.release());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool mightContainSubItems() override { return getNumSubItems() > 0; }
|
||||
|
||||
std::unique_ptr<Component> createItemComponent() override
|
||||
{
|
||||
return std::make_unique<Label> (name, name);
|
||||
}
|
||||
|
||||
String name;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct GenericAudioProcessorEditor::Pimpl
|
||||
{
|
||||
Pimpl (AudioProcessorEditor& editor)
|
||||
: legacyParameters (editor.processor, false),
|
||||
groupItem (editor, legacyParameters.getGroup())
|
||||
{
|
||||
const auto numIndents = getNumIndents (groupItem);
|
||||
const auto width = 400 + view.getIndentSize() * numIndents;
|
||||
|
||||
view.setSize (width, 400);
|
||||
view.setDefaultOpenness (true);
|
||||
view.setRootItemVisible (false);
|
||||
view.setRootItem (&groupItem);
|
||||
}
|
||||
|
||||
static int getNumIndents (const TreeViewItem& item)
|
||||
{
|
||||
int maxInner = 0;
|
||||
|
||||
for (auto i = 0; i < item.getNumSubItems(); ++i)
|
||||
maxInner = jmax (maxInner, 1 + getNumIndents (*item.getSubItem (i)));
|
||||
|
||||
return maxInner;
|
||||
}
|
||||
|
||||
LegacyAudioParametersWrapper legacyParameters;
|
||||
ParameterGroupItem groupItem;
|
||||
TreeView view;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor& p)
|
||||
: AudioProcessorEditor (p), pimpl (std::make_unique<Pimpl> (*this))
|
||||
{
|
||||
auto* viewport = pimpl->view.getViewport();
|
||||
|
||||
setOpaque (true);
|
||||
addAndMakeVisible (pimpl->view);
|
||||
|
||||
setResizable (true, false);
|
||||
setSize (viewport->getViewedComponent()->getWidth() + viewport->getVerticalScrollBar().getWidth(),
|
||||
jlimit (125, 400, viewport->getViewedComponent()->getHeight()));
|
||||
}
|
||||
|
||||
GenericAudioProcessorEditor::~GenericAudioProcessorEditor() = default;
|
||||
|
||||
void GenericAudioProcessorEditor::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
|
||||
}
|
||||
|
||||
void GenericAudioProcessorEditor::resized()
|
||||
{
|
||||
pimpl->view.setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
} // namespace juce
|
65
deps/juce/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h
vendored
Normal file
65
deps/juce/modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.h
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A type of UI component that displays the parameters of an AudioProcessor as
|
||||
a simple list of sliders, combo boxes and switches.
|
||||
|
||||
This can be used for showing an editor for a processor that doesn't supply
|
||||
its own custom editor.
|
||||
|
||||
@see AudioProcessor
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
GenericAudioProcessorEditor (AudioProcessor&);
|
||||
~GenericAudioProcessorEditor() override;
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("This constructor has been changed to take a reference instead of a pointer.")]]
|
||||
GenericAudioProcessorEditor (AudioProcessor* p) : GenericAudioProcessorEditor (*p) {}
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct Pimpl;
|
||||
std::unique_ptr<Pimpl> pimpl;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericAudioProcessorEditor)
|
||||
};
|
||||
|
||||
} // namespace juce
|
114
deps/juce/modules/juce_audio_processors/processors/juce_PluginDescription.cpp
vendored
Normal file
114
deps/juce/modules/juce_audio_processors/processors/juce_PluginDescription.cpp
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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
|
||||
{
|
||||
return pluginFormatName + "-" + name + getPluginDescSuffix (*this, uniqueId);
|
||||
}
|
||||
|
||||
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 ("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);
|
||||
|
||||
deprecatedUid = xml.getStringAttribute ("uid").getHexValue32();
|
||||
uniqueId = xml.getStringAttribute ("uniqueId", "0").getHexValue32();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
177
deps/juce/modules/juce_audio_processors/processors/juce_PluginDescription.h
vendored
Normal file
177
deps/juce/modules/juce_audio_processors/processors/juce_PluginDescription.h
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR 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;
|
||||
|
||||
/** 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
|
Reference in New Issue
Block a user