upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)

This commit is contained in:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -41,7 +41,7 @@ String AudioPluginInstance::getParameterID (int parameterIndex)
// 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 compatibilty you should perform the operation below
// 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
@ -175,7 +175,7 @@ bool AudioPluginInstance::isMetaParameter (int parameterIndex) const
if (auto* param = getParameters()[parameterIndex])
return param->isMetaParameter();
return false;
return false;
}
AudioProcessorParameter::Category AudioPluginInstance::getParameterCategory (int parameterIndex) const

View File

@ -59,7 +59,7 @@ public:
Make sure that you delete any UI components that belong to this plugin before
deleting the plugin.
*/
virtual ~AudioPluginInstance() {}
~AudioPluginInstance() override = default;
//==============================================================================
/** Fills-in the appropriate parts of this plugin description object. */
@ -110,15 +110,15 @@ protected:
struct Parameter : public AudioProcessorParameter
{
Parameter();
virtual ~Parameter();
~Parameter() override;
virtual String getText (float value, int maximumStringLength) const override;
virtual float getValueForText (const String& text) const override;
String getText (float value, int maximumStringLength) const override;
float getValueForText (const String& text) const override;
StringArray onStrings, offStrings;
};
AudioPluginInstance() {}
AudioPluginInstance() = default;
AudioPluginInstance (const BusesProperties& ioLayouts) : AudioProcessor (ioLayouts) {}
template <int numLayouts>
AudioPluginInstance (const short channelLayoutList[numLayouts][2]) : AudioProcessor (channelLayoutList) {}

View File

@ -60,6 +60,11 @@ AudioProcessor::~AudioProcessor()
// or more parameters without having made a corresponding call to endParameterChangeGesture...
jassert (changingParams.countNumberOfSetBits() == 0);
#endif
// The parameters are owned by an AudioProcessorParameterGroup, but we need
// to keep the managedParameters array populated to maintain backwards
// compatibility.
managedParameters.clearQuick (false);
}
//==============================================================================
@ -691,17 +696,36 @@ AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexc
return p;
}
void AudioProcessor::addParameter (AudioProcessorParameter* p)
void AudioProcessor::addParameterInternal (AudioProcessorParameter* param)
{
p->processor = this;
p->parameterIndex = managedParameters.size();
managedParameters.add (p);
param->processor = this;
param->parameterIndex = managedParameters.size();
managedParameters.add (param);
#ifdef JUCE_DEBUG
shouldCheckParamsForDupeIDs = true;
#endif
}
void AudioProcessor::addParameter (AudioProcessorParameter* param)
{
addParameterInternal (param);
parameterTree.addChild (std::unique_ptr<AudioProcessorParameter> (param));
}
void AudioProcessor::addParameterGroup (std::unique_ptr<AudioProcessorParameterGroup> group)
{
for (auto* param : group->getParameters (true))
addParameterInternal (param);
parameterTree.addChild (std::move (group));
}
const AudioProcessorParameterGroup& AudioProcessor::getParameterTree()
{
return parameterTree;
}
#ifdef JUCE_DEBUG
void AudioProcessor::checkForDupedParamIDs()
{
@ -1374,6 +1398,24 @@ int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mai
return (idForAudioSuite ? 0x6a796161 /* 'jyaa' */ : 0x6a636161 /* 'jcaa' */) + uniqueFormatId;
}
//==============================================================================
const char* AudioProcessor::getWrapperTypeDescription (AudioProcessor::WrapperType type) noexcept
{
switch (type)
{
case AudioProcessor::wrapperType_Undefined: return "Undefined";
case AudioProcessor::wrapperType_VST: return "VST";
case AudioProcessor::wrapperType_VST3: return "VST3";
case AudioProcessor::wrapperType_AudioUnit: return "AU";
case AudioProcessor::wrapperType_AudioUnitv3: return "AUv3";
case AudioProcessor::wrapperType_RTAS: return "RTAS";
case AudioProcessor::wrapperType_AAX: return "AAX";
case AudioProcessor::wrapperType_Standalone: return "Standalone";
case AudioProcessor::wrapperType_Unity: return "Unity";
default: jassertfalse; return {};
}
}
//==============================================================================
void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {}
void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {}

View File

@ -412,8 +412,8 @@ public:
@param currentLayout If non-null, pretend that the current layout of the AudioProcessor is
currentLayout. On exit, currentLayout will be modified to
to represent the buses layouts of the AudioProcessor as if the layout
of the reciever had been succesfully changed. This is useful as changing
the layout of the reciever may change the bus layout of other buses.
of the receiver had been successfully changed. This is useful as changing
the layout of the receiver may change the bus layout of other buses.
@see AudioChannelSet
*/
@ -898,7 +898,7 @@ public:
/** Returns the parameter that controls the AudioProcessor's bypass state.
If this method returns a nullptr then you can still control the bypass by
calling processBlockBypassed instaed of processBlock. On the other hand,
calling processBlockBypassed instead of processBlock. On the other hand,
if this method returns a non-null value, you should never call
processBlockBypassed but use the returned parameter to conrol the bypass
state instead.
@ -1205,12 +1205,25 @@ public:
void updateHostDisplay();
//==============================================================================
/** Adds a parameter to the list.
The parameter object will be managed and deleted automatically by the list
when no longer needed.
/** Adds a parameter to the AudioProcessor.
The parameter object will be managed and deleted automatically by the
AudioProcessor when no longer needed.
*/
void addParameter (AudioProcessorParameter*);
/** Adds a group of parameters to the AudioProcessor.
All the parameter objects contained within the group will be managed and
deleted automatically by the AudioProcessor when no longer needed.
@see addParameter
*/
void addParameterGroup (std::unique_ptr<AudioProcessorParameterGroup>);
/** Returns the group of parameters managed by this AudioProcessor. */
const AudioProcessorParameterGroup& getParameterTree();
/** Returns the current list of parameters. */
const OwnedArray<AudioProcessorParameter>& getParameters() const noexcept;
@ -1338,6 +1351,34 @@ public:
const AudioChannelSet& mainOutputLayout,
bool idForAudioSuite) const;
//==============================================================================
/** Some plug-ins support sharing response curve data with the host so that it can
display this curve on a console or in the mixer panel. For example, ProTools
allows you to see the total EQ curve of a track. It does this by interrogating
each plug-in for their internal EQ curve. */
struct CurveData
{
enum class Type : int
{
EQ, // an EQ curve - input is in Hz, output is in dB
Dynamics, // a dynamics curve - input and output is in dB
GainReduction, // a gain reduction curve - input and output is in dB
Unknown = -1
};
std::function<float (float)> curve; // a function which represents your curve (such as an eq)
Range<float> xRange, yRange; // the data range of your curve
// For some curve types, your plug-in may already measure the current input and output values.
// An host can use to indicate where on the curve the current signal is (for example
// by putting a dot on the curve). Simply leave these strings empty if you do not want to
// support this.
String xMeterID, yMeterID;
};
virtual CurveData getResponseCurve (CurveData::Type /*curveType*/) const { return {}; }
//==============================================================================
/** Not for public use - this is called before deleting an editor component. */
void editorBeingDeleted (AudioProcessorEditor*) noexcept;
@ -1352,7 +1393,8 @@ public:
wrapperType_AudioUnitv3,
wrapperType_RTAS,
wrapperType_AAX,
wrapperType_Standalone
wrapperType_Standalone,
wrapperType_Unity
};
/** When loaded by a plugin wrapper, this flag will be set to indicate the type
@ -1360,6 +1402,10 @@ public:
*/
WrapperType wrapperType;
/** Returns a textual description of a WrapperType value */
static const char* getWrapperTypeDescription (AudioProcessor::WrapperType) noexcept;
/** A struct containing information about the DAW track inside which your
AudioProcessor is loaded. */
struct TrackProperties
@ -1526,7 +1572,7 @@ protected:
When adding a bus, isAddingBuses will be true and the plug-in is
expected to fill out outNewBusProperties with the properties of the
bus which will be created just after the succesful return of this callback.
bus which will be created just after the successful return of this callback.
Implementations of AudioProcessor will rarely need to override this
method. Only override this method if your processor supports adding
@ -1551,22 +1597,23 @@ protected:
void sendParamChangeMessageToListeners (int parameterIndex, float newValue);
private:
//==============================================================================
void addParameterInternal (AudioProcessorParameter*);
//==============================================================================
struct InOutChannelPair
{
int16 inChannels = 0, outChannels = 0;
InOutChannelPair() = default;
InOutChannelPair() noexcept {}
InOutChannelPair (const InOutChannelPair& o) noexcept : inChannels (o.inChannels), outChannels (o.outChannels) {}
InOutChannelPair (int16 inCh, int16 outCh) noexcept : inChannels (inCh), outChannels (outCh) {}
InOutChannelPair (const int16 (&config)[2]) noexcept : inChannels (config[0]), outChannels (config[1]) {}
InOutChannelPair& operator= (const InOutChannelPair& o) noexcept { inChannels = o.inChannels; outChannels = o.outChannels; return *this; }
bool operator== (const InOutChannelPair& other) const noexcept
{
return other.inChannels == inChannels && other.outChannels == outChannels;
}
int16 inChannels = 0, outChannels = 0;
};
template <int numLayouts>
@ -1617,6 +1664,8 @@ private:
OwnedArray<AudioProcessorParameter> managedParameters;
AudioProcessorParameter* getParamChecked (int) const noexcept;
AudioProcessorParameterGroup parameterTree { {}, {}, {} };
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
BigInteger changingParams;
#endif
@ -1640,6 +1689,7 @@ private:
friend class JuceVST3EditController;
friend class JuceVST3Component;
friend class VST3PluginInstance;
friend class AudioUnitPluginInstance;
friend class LADSPAPluginInstance;

View File

@ -88,18 +88,13 @@ void AudioProcessorEditor::setResizable (const bool shouldBeResizable, const boo
{
resizable = shouldBeResizable;
if (! resizable)
if (! resizable && constrainer == &defaultConstrainer)
{
setConstrainer (&defaultConstrainer);
auto width = getWidth();
auto height = getHeight();
if (auto w = getWidth())
{
if (auto h = getHeight())
{
defaultConstrainer.setSizeLimits (w, h, w, h);
resized();
}
}
if (width > 0 && height > 0)
defaultConstrainer.setSizeLimits (width, height, width, height);
}
}
@ -146,7 +141,10 @@ void AudioProcessorEditor::setConstrainer (ComponentBoundsConstrainer* newConstr
{
if (constrainer != newConstrainer)
{
resizable = true;
if (newConstrainer != nullptr)
resizable = (newConstrainer->getMinimumWidth() != newConstrainer->getMaximumWidth()
|| newConstrainer->getMinimumHeight() != newConstrainer->getMaximumHeight());
attachConstrainer (newConstrainer);
}
}
@ -207,4 +205,23 @@ void AudioProcessorEditor::setScaleFactor (float newScale)
editorResized (true);
}
//==============================================================================
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
createUnityPeerFunctionType juce_createUnityPeerFn = nullptr;
#endif
ComponentPeer* AudioProcessorEditor::createNewPeer (int styleFlags, void* nativeWindow)
{
#if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client && JucePlugin_Build_Unity
if (juce_createUnityPeerFn != nullptr)
{
ignoreUnused (styleFlags, nativeWindow);
return juce_createUnityPeerFn (*this);
}
#endif
return Component::createNewPeer (styleFlags, nativeWindow);
}
} // namespace juce

View File

@ -53,7 +53,7 @@ protected:
public:
/** Destructor. */
~AudioProcessorEditor();
~AudioProcessorEditor() override;
//==============================================================================
@ -193,6 +193,8 @@ private:
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditorListener)
};
ComponentPeer* createNewPeer (int styleFlags, void*) override;
//==============================================================================
void initialise();
void editorResized (bool wasResized);

View File

@ -191,13 +191,13 @@ private:
{
struct LambdaOp : public RenderingOp
{
LambdaOp (LambdaType&& f) : function (static_cast<LambdaType&&> (f)) {}
LambdaOp (LambdaType&& f) : function (std::move (f)) {}
void perform (const Context& c) override { function (c); }
LambdaType function;
};
renderOps.add (new LambdaOp (static_cast<LambdaType&&> (fn)));
renderOps.add (new LambdaOp (std::move (fn)));
}
//==============================================================================
@ -359,23 +359,20 @@ struct RenderSequenceBuilder
{
AudioProcessorGraph::NodeAndChannel channel;
static AssignedBuffer createReadOnlyEmpty() noexcept { return { { (NodeID) zeroNodeID, 0 } }; }
static AssignedBuffer createFree() noexcept { return { { (NodeID) freeNodeID, 0 } }; }
static AssignedBuffer createReadOnlyEmpty() noexcept { return { { zeroNodeID(), 0 } }; }
static AssignedBuffer createFree() noexcept { return { { freeNodeID(), 0 } }; }
bool isReadOnlyEmpty() const noexcept { return channel.nodeID == (NodeID) zeroNodeID; }
bool isFree() const noexcept { return channel.nodeID == (NodeID) freeNodeID; }
bool isReadOnlyEmpty() const noexcept { return channel.nodeID == zeroNodeID(); }
bool isFree() const noexcept { return channel.nodeID == freeNodeID(); }
bool isAssigned() const noexcept { return ! (isReadOnlyEmpty() || isFree()); }
void setFree() noexcept { channel = { (NodeID) freeNodeID, 0 }; }
void setAssignedToNonExistentNode() noexcept { channel = { (NodeID) anonNodeID, 0 }; }
void setFree() noexcept { channel = { freeNodeID(), 0 }; }
void setAssignedToNonExistentNode() noexcept { channel = { anonNodeID(), 0 }; }
private:
enum
{
anonNodeID = 0x7ffffffd,
zeroNodeID = 0x7ffffffe,
freeNodeID = 0x7fffffff
};
static NodeID anonNodeID() { return NodeID (0x7ffffffd); }
static NodeID zeroNodeID() { return NodeID (0x7ffffffe); }
static NodeID freeNodeID() { return NodeID (0x7fffffff); }
};
Array<AssignedBuffer> audioBuffers, midiBuffers;
@ -388,12 +385,12 @@ struct RenderSequenceBuilder
int delay;
};
HashMap<NodeID, int> delays;
HashMap<uint32, int> delays;
int totalLatency = 0;
int getNodeDelay (NodeID nodeID) const noexcept
{
return delays[nodeID];
return delays[nodeID.uid];
}
int getInputLatencyForNode (NodeID nodeID) const
@ -681,12 +678,12 @@ struct RenderSequenceBuilder
if (processor.producesMidi())
midiBuffers.getReference (midiBufferToUse).channel = { node.nodeID, AudioProcessorGraph::midiChannelIndex };
delays.set (node.nodeID, maxLatency + processor.getLatencySamples());
delays.set (node.nodeID.uid, maxLatency + processor.getLatencySamples());
if (numOuts == 0)
totalLatency = maxLatency;
sequence.addProcessOp (&node, audioChannelsToUse, totalChans, midiBufferToUse);
sequence.addProcessOp (node, audioChannelsToUse, totalChans, midiBufferToUse);
}
//==============================================================================
@ -896,6 +893,8 @@ void AudioProcessorGraph::topologyChanged()
void AudioProcessorGraph::clear()
{
const ScopedLock sl (getCallbackLock());
if (nodes.isEmpty())
return;
@ -920,8 +919,8 @@ AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (AudioProcessor* new
return {};
}
if (nodeID == 0)
nodeID = ++lastNodeID;
if (nodeID == NodeID())
nodeID.uid = ++(lastNodeID.uid);
for (auto* n : nodes)
{
@ -932,13 +931,13 @@ AudioProcessorGraph::Node::Ptr AudioProcessorGraph::addNode (AudioProcessor* new
}
}
if (nodeID > lastNodeID)
if (lastNodeID < nodeID)
lastNodeID = nodeID;
newProcessor->setPlayHead (getPlayHead());
Node::Ptr n (new Node (nodeID, newProcessor));
nodes.add (n);
nodes.add (n.get());
n->setParentGraph (this);
topologyChanged();
return n;
@ -1242,16 +1241,15 @@ void AudioProcessorGraph::handleAsyncUpdate()
}
//==============================================================================
void AudioProcessorGraph::prepareToPlay (double /*sampleRate*/, int estimatedSamplesPerBlock)
void AudioProcessorGraph::prepareToPlay (double sampleRate, int estimatedSamplesPerBlock)
{
if (renderSequenceFloat != nullptr)
renderSequenceFloat->prepareBuffers (estimatedSamplesPerBlock);
if (renderSequenceDouble != nullptr)
renderSequenceDouble->prepareBuffers (estimatedSamplesPerBlock);
setRateAndBufferSizeDetails (sampleRate, estimatedSamplesPerBlock);
clearRenderingSequence();
triggerAsyncUpdate();
if (isNonRealtime() && MessageManager::getInstance()->isThisTheMessageThread())
handleAsyncUpdate();
else
triggerAsyncUpdate();
}
bool AudioProcessorGraph::supportsDoublePrecisionProcessing() const
@ -1261,6 +1259,8 @@ bool AudioProcessorGraph::supportsDoublePrecisionProcessing() const
void AudioProcessorGraph::releaseResources()
{
const ScopedLock sl (getCallbackLock());
isPrepared = 0;
for (auto* n : nodes)

View File

@ -55,10 +55,20 @@ public:
/** Destructor.
Any processor objects that have been added to the graph will also be deleted.
*/
~AudioProcessorGraph();
~AudioProcessorGraph() override;
/** Each node in the graph has a UID of this type. */
using NodeID = uint32;
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.
@ -185,7 +195,7 @@ public:
This will return nullptr if the index is out of range.
@see getNodeForId
*/
Node* getNode (int index) const noexcept { return nodes [index]; }
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.
@ -312,7 +322,7 @@ public:
//==============================================================================
AudioGraphIOProcessor (IODeviceType);
~AudioGraphIOProcessor();
~AudioGraphIOProcessor() override;
const String getName() const override;
void fillInPluginDescription (PluginDescription&) const override;

View File

@ -42,12 +42,12 @@ class JUCE_API AudioProcessorListener
public:
//==============================================================================
/** Destructor. */
virtual ~AudioProcessorListener() {}
virtual ~AudioProcessorListener() = default;
//==============================================================================
/** Receives a callback when a parameter is changed.
IMPORTANT NOTE: this will be called synchronously when a parameter changes, and
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
@ -61,7 +61,7 @@ public:
/** 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
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
@ -76,7 +76,7 @@ public:
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
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
@ -93,7 +93,7 @@ public:
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
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

View File

@ -147,12 +147,12 @@ public:
*/
virtual bool isBoolean() const;
/** Returns a textual version of the supplied parameter value.
/** 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 value, int /*maximumStringLength*/) const;
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;
@ -216,7 +216,7 @@ public:
/** 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 funtion to
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.
@ -238,11 +238,11 @@ public:
{
public:
/** Destructor. */
virtual ~Listener() {}
virtual ~Listener() = default;
/** Receives a callback when a parameter has been changed.
IMPORTANT NOTE: this will be called synchronously when a parameter changes, and
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
@ -257,7 +257,7 @@ public:
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
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

View File

@ -0,0 +1,163 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
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 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-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
{
#if JUCE_UNIT_TESTS
class ParameterGroupTests : public UnitTest
{
public:
ParameterGroupTests() : UnitTest ("ParameterGroups", "Parameters") {}
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> ("p11", "p11", NormalisableRange<float> (0.0f, 2.0f), 0.5f),
std::make_unique<AudioProcessorParameterGroup> ("g7", "g7", " | ",
std::make_unique<AudioParameterFloat> ("p12", "p12", NormalisableRange<float> (0.0f, 2.0f), 0.5f)),
std::make_unique<AudioParameterFloat> ("p13", "p13", 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 {}
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

View File

@ -0,0 +1,299 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
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 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-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:
//==============================================================================
/** Returns the parent group or nullptr if this is a top-level group. */
AudioProcessorParameterGroup* getParent() const { return parent; }
/** Returns a pointer to a parameter if this node contains a parameter, nullptr otherwise. */
AudioProcessorParameter* getParameter() const { return parameter.get(); }
/** Returns a pointer to a group if this node contains a group, nullptr otherwise. */
AudioProcessorParameterGroup* getGroup() const { return group.get(); }
private:
//==============================================================================
AudioProcessorParameterNode (std::unique_ptr<AudioProcessorParameter> param,
AudioProcessorParameterGroup* parentGroup)
: parameter (std::move (param)), parent (parentGroup)
{}
AudioProcessorParameterNode (std::unique_ptr<AudioProcessorParameterGroup> grp,
AudioProcessorParameterGroup* parentGroup)
: group (std::move (grp)), parent (parentGroup)
{
group->parent = parent;
}
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.
@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 (const String& groupID, const String& groupName, const String& subgroupSeparator)
: identifier (groupID), name (groupName), separator (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 ChildType>
AudioProcessorParameterGroup (const String& groupID, const String& groupName, const String& subgroupSeparator,
std::unique_ptr<ChildType> 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 ChildType, typename... Args>
AudioProcessorParameterGroup (const String& groupID, const String& groupName, const String& subgroupSeparator,
std::unique_ptr<ChildType> firstChild, Args&&... remainingChildren)
: AudioProcessorParameterGroup (groupID, groupName, subgroupSeparator, std::move (firstChild))
{
addChild (std::forward<Args> (remainingChildren)...);
}
//==============================================================================
/** Returns the group's ID. */
String getID() const { return identifier; }
/** Returns the group's name. */
String getName() const { return name; }
/** Returns the group's separator string. */
String getSeparator() const { return separator; }
/** Returns the parent of the group, or nullptr if this is a top-levle group. */
const AudioProcessorParameterGroup* getParent() const noexcept { return parent; }
//==============================================================================
const AudioProcessorParameterNode** begin() const noexcept { return children.begin(); }
const AudioProcessorParameterNode** end() const noexcept { return children.end(); }
//==============================================================================
/** Swaps the content of this group with another. */
void swapWith (AudioProcessorParameterGroup& other) noexcept
{
children.swapWith (other.children);
auto refreshParentPtr = [] (AudioProcessorParameterGroup& parentGroup)
{
for (auto* child : parentGroup)
if (auto* group = child->getGroup())
group->parent = &parentGroup;
};
refreshParentPtr (*this);
refreshParentPtr (other);
}
//==============================================================================
/** 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
{
Array<const AudioProcessorParameterGroup*> groups;
getSubgroups (groups, recursive);
return groups;
}
/** 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
{
Array<AudioProcessorParameter*> parameters;
getParameters (parameters, recursive);
return parameters;
}
/** Searches this group recursively for a parameter and returns a depth ordered
list of the groups it belongs to.
*/
Array<const AudioProcessorParameterGroup*> getGroupsForParameter (AudioProcessorParameter* parameter) const
{
Array<const AudioProcessorParameterGroup*> groups;
if (auto* group = getGroupForParameter (parameter))
{
while (group != this)
{
groups.insert (0, group);
group = group->getParent();
}
}
return groups;
}
//==============================================================================
/** Adds a child to the group. */
template <typename ChildType>
void addChild (std::unique_ptr<ChildType> 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.
children.add (new AudioProcessorParameterNode (std::move (child), this));
}
/** Adds multiple children to the group. */
template <typename ChildType, typename... Args>
void addChild (std::unique_ptr<ChildType> firstChild, Args&&... remainingChildren)
{
addChild (std::move (firstChild));
addChild (std::forward<Args> (remainingChildren)...);
}
private:
//==============================================================================
void 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 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* 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;
}
//==============================================================================
const String identifier, name, separator;
OwnedArray<const AudioProcessorParameterNode> children;
AudioProcessorParameterGroup* parent = nullptr;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameterGroup)
};
} // namespace juce

View File

@ -32,8 +32,8 @@ class ParameterListener : private AudioProcessorParameter::Listener,
private Timer
{
public:
ParameterListener (AudioProcessor& p, AudioProcessorParameter& param)
: processor (p), parameter (param)
ParameterListener (AudioProcessor& proc, AudioProcessorParameter& param)
: processor (proc), parameter (param)
{
if (LegacyAudioParameter::isLegacy (&parameter))
processor.addListener (this);
@ -43,7 +43,7 @@ public:
startTimer (100);
}
virtual ~ParameterListener()
~ParameterListener() override
{
if (LegacyAudioParameter::isLegacy (&parameter))
processor.removeListener (this);
@ -101,8 +101,8 @@ class BooleanParameterComponent final : public Component,
private ParameterListener
{
public:
BooleanParameterComponent (AudioProcessor& processor, AudioProcessorParameter& param)
: ParameterListener (processor, param)
BooleanParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
: ParameterListener (proc, param)
{
// Set the initial value.
handleNewParameterValue();
@ -154,8 +154,8 @@ class SwitchParameterComponent final : public Component,
private ParameterListener
{
public:
SwitchParameterComponent (AudioProcessor& processor, AudioProcessorParameter& param)
: ParameterListener (processor, param)
SwitchParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
: ParameterListener (proc, param)
{
auto* leftButton = buttons.add (new TextButton());
auto* rightButton = buttons.add (new TextButton());
@ -259,8 +259,8 @@ class ChoiceParameterComponent final : public Component,
private ParameterListener
{
public:
ChoiceParameterComponent (AudioProcessor& processor, AudioProcessorParameter& param)
: ParameterListener (processor, param),
ChoiceParameterComponent (AudioProcessor& proc, AudioProcessorParameter& param)
: ParameterListener (proc, param),
parameterValues (getParameter().getAllValueStrings())
{
box.addItemList (parameterValues, 1);
@ -321,8 +321,8 @@ class SliderParameterComponent final : public Component,
private ParameterListener
{
public:
SliderParameterComponent (AudioProcessor& processor, AudioProcessorParameter& param)
: ParameterListener (processor, param)
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));
@ -506,7 +506,7 @@ private:
};
//==============================================================================
struct GenericAudioProcessorEditor::Pimpl
struct GenericAudioProcessorEditor::Pimpl
{
Pimpl (GenericAudioProcessorEditor& parent)
: owner (parent)

View File

@ -44,7 +44,7 @@ class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor
public:
//==============================================================================
GenericAudioProcessorEditor (AudioProcessor* owner);
~GenericAudioProcessorEditor();
~GenericAudioProcessorEditor() override;
//==============================================================================
void paint (Graphics&) override;