Browse Source

GenericAudioProcessorEditor: Add support for grouped parameters

v6.1.6
reuk 4 years ago
parent
commit
cfec0b5356
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
6 changed files with 143 additions and 87 deletions
  1. +3
    -3
      modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp
  2. +3
    -3
      modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  3. +2
    -2
      modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp
  4. +4
    -4
      modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  5. +49
    -8
      modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp
  6. +82
    -67
      modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp

+ 3
- 3
modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp View File

@@ -1548,11 +1548,11 @@ namespace AAXClasses
} }
if (! bypassPartOfRegularParams) if (! bypassPartOfRegularParams)
juceParameters.params.add (bypassParameter);
juceParameters.addNonOwning (bypassParameter);
int parameterIndex = 0; int parameterIndex = 0;
for (auto* juceParam : juceParameters.params)
for (auto* juceParam : juceParameters)
{ {
auto isBypassParameter = (juceParam == bypassParameter); auto isBypassParameter = (juceParam == bypassParameter);
@@ -2102,7 +2102,7 @@ namespace AAXClasses
int meterIdx = 0; int meterIdx = 0;
for (auto* param : params.params)
for (auto* param : params)
{ {
auto category = param->getCategory(); auto category = param->getCategory();


+ 3
- 3
modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -2058,7 +2058,7 @@ private:
} }
else else
{ {
for (auto* param : juceParameters.params)
for (auto* param : juceParameters)
{ {
const AudioUnitParameterID auParamID = generateAUParameterID (param); const AudioUnitParameterID auParamID = generateAUParameterID (param);
@@ -2075,14 +2075,14 @@ private:
#if JUCE_DEBUG #if JUCE_DEBUG
// Some hosts can't handle the huge numbers of discrete parameter values created when // Some hosts can't handle the huge numbers of discrete parameter values created when
// using the default number of steps. // using the default number of steps.
for (auto* param : juceParameters.params)
for (auto* param : juceParameters)
if (param->isDiscrete()) if (param->isDiscrete())
jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps()); jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps());
#endif #endif
parameterValueStringArrays.ensureStorageAllocated (numParams); parameterValueStringArrays.ensureStorageAllocated (numParams);
for (auto* param : juceParameters.params)
for (auto* param : juceParameters)
{ {
OwnedArray<const __CFString>* stringValues = nullptr; OwnedArray<const __CFString>* stringValues = nullptr;


+ 2
- 2
modules/juce_audio_plugin_client/Unity/juce_Unity_Wrapper.cpp View File

@@ -365,7 +365,7 @@ public:
if (parametersPtr == nullptr) if (parametersPtr == nullptr)
{ {
numParams = juceParameters.params.size();
numParams = (int) juceParameters.size();
parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams), parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams),
sizeof (UnityAudioParameterDefinition)))); sizeof (UnityAudioParameterDefinition))));
@@ -374,7 +374,7 @@ public:
for (int i = 0; i < numParams; ++i) for (int i = 0; i < numParams; ++i)
{ {
auto* parameter = juceParameters.params[i];
auto* parameter = juceParameters.getParamForIndex (i);
auto& paramDef = parametersPtr.get()[i]; auto& paramDef = parametersPtr.get()[i];
const auto nameLength = (size_t) numElementsInArray (paramDef.name); const auto nameLength = (size_t) numElementsInArray (paramDef.name);


+ 4
- 4
modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -530,13 +530,13 @@ private:
// if the bypass parameter is not part of the exported parameters that the plug-in supports // if the bypass parameter is not part of the exported parameters that the plug-in supports
// then add it to the end of the list as VST3 requires the bypass parameter to be exported! // then add it to the end of the list as VST3 requires the bypass parameter to be exported!
bypassIsRegularParameter = juceParameters.params.contains (audioProcessor->getBypassParameter());
bypassIsRegularParameter = juceParameters.contains (audioProcessor->getBypassParameter());
if (! bypassIsRegularParameter) if (! bypassIsRegularParameter)
juceParameters.params.add (bypassParameter);
juceParameters.addNonOwning (bypassParameter);
int i = 0; int i = 0;
for (auto* juceParam : juceParameters.params)
for (auto* juceParam : juceParameters)
{ {
bool isBypassParameter = (juceParam == bypassParameter); bool isBypassParameter = (juceParam == bypassParameter);
@@ -568,7 +568,7 @@ private:
0, numPrograms - 1, 0, numPrograms - 1,
audioProcessor->getCurrentProgram()); audioProcessor->getCurrentProgram());
juceParameters.params.add (ownedProgramParameter.get());
juceParameters.addNonOwning (ownedProgramParameter.get());
if (forceLegacyParamIDs) if (forceLegacyParamIDs)
programParamID = static_cast<Vst::ParamID> (i++); programParamID = static_cast<Vst::ParamID> (i++);


+ 49
- 8
modules/juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp View File

@@ -98,12 +98,12 @@ public:
return -1; return -1;
} }
static String getParamID (AudioProcessorParameter* param, bool forceLegacyParamIDs) noexcept
static String getParamID (const AudioProcessorParameter* param, bool forceLegacyParamIDs) noexcept
{ {
if (auto* legacy = dynamic_cast<LegacyAudioParameter*> (param))
if (auto* legacy = dynamic_cast<const LegacyAudioParameter*> (param))
return forceLegacyParamIDs ? String (legacy->parameterIndex) : legacy->getParamID(); return forceLegacyParamIDs ? String (legacy->parameterIndex) : legacy->getParamID();
if (auto* paramWithID = dynamic_cast<AudioProcessorParameterWithID*> (param))
if (auto* paramWithID = dynamic_cast<const AudioProcessorParameterWithID*> (param))
{ {
if (! forceLegacyParamIDs) if (! forceLegacyParamIDs)
return paramWithID->paramID; return paramWithID->paramID;
@@ -120,6 +120,13 @@ public:
class LegacyAudioParametersWrapper class LegacyAudioParametersWrapper
{ {
public: public:
LegacyAudioParametersWrapper() = default;
LegacyAudioParametersWrapper (AudioProcessor& audioProcessor, bool forceLegacyParamIDs)
{
update (audioProcessor, forceLegacyParamIDs);
}
void update (AudioProcessor& audioProcessor, bool forceLegacyParamIDs) void update (AudioProcessor& audioProcessor, bool forceLegacyParamIDs)
{ {
clear(); clear();
@@ -131,15 +138,28 @@ public:
for (int i = 0; i < numParameters; ++i) for (int i = 0; i < numParameters; ++i)
{ {
AudioProcessorParameter* param = usingManagedParameters ? audioProcessor.getParameters()[i]
: (legacy.add (new LegacyAudioParameter (audioProcessor, i)));
auto* param = [&]() -> AudioProcessorParameter*
{
if (usingManagedParameters)
return audioProcessor.getParameters()[i];
auto newParam = std::make_unique<LegacyAudioParameter> (audioProcessor, i);
auto* result = newParam.get();
ownedGroup.addChild (std::move (newParam));
return result;
}();
params.add (param); params.add (param);
} }
processorGroup = usingManagedParameters ? &audioProcessor.getParameterTree()
: nullptr;
} }
void clear() void clear()
{ {
legacy.clear();
ownedGroup = AudioProcessorParameterGroup();
params.clear(); params.clear();
} }
@@ -159,13 +179,34 @@ public:
return String (idx); return String (idx);
} }
const AudioProcessorParameterGroup& getGroup() const
{
return processorGroup != nullptr ? *processorGroup
: ownedGroup;
}
void addNonOwning (AudioProcessorParameter* param)
{
params.add (param);
}
size_t size() const noexcept { return (size_t) params.size(); }
bool isUsingManagedParameters() const noexcept { return usingManagedParameters; } bool isUsingManagedParameters() const noexcept { return usingManagedParameters; }
int getNumParameters() const noexcept { return params.size(); } int getNumParameters() const noexcept { return params.size(); }
Array<AudioProcessorParameter*> params;
AudioProcessorParameter* const* begin() const { return params.begin(); }
AudioProcessorParameter* const* end() const { return params.end(); }
bool contains (AudioProcessorParameter* param) const
{
return params.contains (param);
}
private: private:
OwnedArray<LegacyAudioParameter> legacy;
const AudioProcessorParameterGroup* processorGroup = nullptr;
AudioProcessorParameterGroup ownedGroup;
Array<AudioProcessorParameter*> params;
bool legacyParamIDs = false, usingManagedParameters = false; bool legacyParamIDs = false, usingManagedParameters = false;
}; };


+ 82
- 67
modules/juce_audio_processors/processors/juce_GenericAudioProcessorEditor.cpp View File

@@ -409,23 +409,23 @@ private:
class ParameterDisplayComponent : public Component class ParameterDisplayComponent : public Component
{ {
public: public:
ParameterDisplayComponent (AudioProcessor& processor, AudioProcessorParameter& param)
: parameter (param)
ParameterDisplayComponent (AudioProcessorEditor& editorIn, AudioProcessorParameter& param)
: editor (editorIn), parameter (param)
{ {
parameterName.setText (parameter.getName (128), dontSendNotification); parameterName.setText (parameter.getName (128), dontSendNotification);
parameterName.setJustificationType (Justification::centredRight); parameterName.setJustificationType (Justification::centredRight);
parameterName.setInterceptsMouseClicks (false, false);
addAndMakeVisible (parameterName); addAndMakeVisible (parameterName);
parameterLabel.setText (parameter.getLabel(), dontSendNotification); parameterLabel.setText (parameter.getLabel(), dontSendNotification);
parameterLabel.setInterceptsMouseClicks (false, false);
addAndMakeVisible (parameterLabel); addAndMakeVisible (parameterLabel);
addAndMakeVisible (*(parameterComp = createParameterComp (processor)));
addAndMakeVisible (*(parameterComp = createParameterComp (editor.processor)));
setSize (400, 40); setSize (400, 40);
} }
void paint (Graphics&) override {}
void resized() override void resized() override
{ {
auto area = getLocalBounds(); auto area = getLocalBounds();
@@ -435,7 +435,22 @@ public:
parameterComp->setBounds (area); parameterComp->setBounds (area);
} }
void mouseDown (const MouseEvent& e) override
{
if (e.mods.isRightButtonDown())
if (auto* context = editor.getHostContext())
if (auto menu = context->getContextMenuForParameterIndex (&parameter))
menu->getEquivalentPopupMenu().showMenuAsync (getMenuOptions());
}
private: private:
PopupMenu::Options getMenuOptions()
{
return PopupMenu::Options().withTargetComponent (this)
.withTargetScreenArea ({ Desktop::getMousePosition(), Desktop::getMousePosition() });
}
AudioProcessorEditor& editor;
AudioProcessorParameter& parameter; AudioProcessorParameter& parameter;
Label parameterName, parameterLabel; Label parameterName, parameterLabel;
std::unique_ptr<Component> parameterComp; std::unique_ptr<Component> parameterComp;
@@ -468,101 +483,101 @@ private:
}; };
//============================================================================== //==============================================================================
class ParametersPanel : public Component
struct ParamControlItem : public TreeViewItem
{ {
public:
ParametersPanel (AudioProcessor& processor, const Array<AudioProcessorParameter*>& parameters)
ParamControlItem (AudioProcessorEditor& editorIn, AudioProcessorParameter& paramIn)
: editor (editorIn), param (paramIn) {}
bool mightContainSubItems() override { return false; }
std::unique_ptr<Component> createItemComponent() override
{ {
for (auto* param : parameters)
if (param->isAutomatable())
addAndMakeVisible (paramComponents.add (new ParameterDisplayComponent (processor, *param)));
return std::make_unique<ParameterDisplayComponent> (editor, param);
}
int maxWidth = 400;
int height = 0;
int getItemHeight() const override { return 40; }
for (auto& comp : paramComponents)
AudioProcessorEditor& editor;
AudioProcessorParameter& param;
};
struct ParameterGroupItem : public TreeViewItem
{
ParameterGroupItem (AudioProcessorEditor& editor, const AudioProcessorParameterGroup& group)
: name (group.getName())
{
for (auto* node : group)
{ {
maxWidth = jmax (maxWidth, comp->getWidth());
height += comp->getHeight();
}
if (auto* param = node->getParameter())
if (param->isAutomatable())
addSubItem (new ParamControlItem (editor, *param));
setSize (maxWidth, jmax (height, 125));
}
if (auto* inner = node->getGroup())
{
auto groupItem = std::make_unique<ParameterGroupItem> (editor, *inner);
~ParametersPanel() override
{
paramComponents.clear();
if (groupItem->getNumSubItems() != 0)
addSubItem (groupItem.release());
}
}
} }
void paint (Graphics& g) override
{
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
}
bool mightContainSubItems() override { return getNumSubItems() > 0; }
void resized() override
std::unique_ptr<Component> createItemComponent() override
{ {
auto area = getLocalBounds();
for (auto* comp : paramComponents)
comp->setBounds (area.removeFromTop (comp->getHeight()));
return std::make_unique<Label> (name, name);
} }
private:
OwnedArray<ParameterDisplayComponent> paramComponents;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParametersPanel)
String name;
}; };
//============================================================================== //==============================================================================
struct GenericAudioProcessorEditor::Pimpl struct GenericAudioProcessorEditor::Pimpl
{ {
Pimpl (GenericAudioProcessorEditor& parent) : owner (parent)
Pimpl (AudioProcessorEditor& editor)
: legacyParameters (editor.processor, false),
groupItem (editor, legacyParameters.getGroup())
{ {
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
auto* p = parent.getAudioProcessor();
jassert (p != nullptr);
legacyParameters.update (*p, false);
const auto numIndents = getNumIndents (groupItem);
const auto width = 400 + view.getIndentSize() * numIndents;
owner.setOpaque (true);
view.setViewedComponent (new ParametersPanel (*p, legacyParameters.params));
owner.addAndMakeVisible (view);
view.setScrollBarsShown (true, false);
JUCE_END_IGNORE_WARNINGS_MSVC
view.setSize (width, 400);
view.setDefaultOpenness (true);
view.setRootItemVisible (false);
view.setRootItem (&groupItem);
} }
~Pimpl()
static int getNumIndents (const TreeViewItem& item)
{ {
view.setViewedComponent (nullptr, false);
}
int maxInner = 0;
void resize (Rectangle<int> size)
{
view.setBounds (size);
auto content = view.getViewedComponent();
content->setSize (view.getMaximumVisibleWidth(), content->getHeight());
for (auto i = 0; i < item.getNumSubItems(); ++i)
maxInner = jmax (maxInner, 1 + getNumIndents (*item.getSubItem (i)));
return maxInner;
} }
//==============================================================================
GenericAudioProcessorEditor& owner;
LegacyAudioParametersWrapper legacyParameters; LegacyAudioParametersWrapper legacyParameters;
Viewport view;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
ParameterGroupItem groupItem;
TreeView view;
}; };
//============================================================================== //==============================================================================
GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor& p) GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor& p)
: AudioProcessorEditor (p), pimpl (new Pimpl (*this))
: AudioProcessorEditor (p), pimpl (std::make_unique<Pimpl> (*this))
{ {
setSize (pimpl->view.getViewedComponent()->getWidth() + pimpl->view.getVerticalScrollBar().getWidth(),
jmin (pimpl->view.getViewedComponent()->getHeight(), 400));
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() {}
GenericAudioProcessorEditor::~GenericAudioProcessorEditor() = default;
void GenericAudioProcessorEditor::paint (Graphics& g) void GenericAudioProcessorEditor::paint (Graphics& g)
{ {
@@ -571,7 +586,7 @@ void GenericAudioProcessorEditor::paint (Graphics& g)
void GenericAudioProcessorEditor::resized() void GenericAudioProcessorEditor::resized()
{ {
pimpl->resize (getLocalBounds());
pimpl->view.setBounds (getLocalBounds());
} }
} // namespace juce } // namespace juce

Loading…
Cancel
Save