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)
juceParameters.params.add (bypassParameter);
juceParameters.addNonOwning (bypassParameter);
int parameterIndex = 0;
for (auto* juceParam : juceParameters.params)
for (auto* juceParam : juceParameters)
{
auto isBypassParameter = (juceParam == bypassParameter);
@@ -2102,7 +2102,7 @@ namespace AAXClasses
int meterIdx = 0;
for (auto* param : params.params)
for (auto* param : params)
{
auto category = param->getCategory();


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

@@ -2058,7 +2058,7 @@ private:
}
else
{
for (auto* param : juceParameters.params)
for (auto* param : juceParameters)
{
const AudioUnitParameterID auParamID = generateAUParameterID (param);
@@ -2075,14 +2075,14 @@ private:
#if JUCE_DEBUG
// Some hosts can't handle the huge numbers of discrete parameter values created when
// using the default number of steps.
for (auto* param : juceParameters.params)
for (auto* param : juceParameters)
if (param->isDiscrete())
jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps());
#endif
parameterValueStringArrays.ensureStorageAllocated (numParams);
for (auto* param : juceParameters.params)
for (auto* param : juceParameters)
{
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)
{
numParams = juceParameters.params.size();
numParams = (int) juceParameters.size();
parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams),
sizeof (UnityAudioParameterDefinition))));
@@ -374,7 +374,7 @@ public:
for (int i = 0; i < numParams; ++i)
{
auto* parameter = juceParameters.params[i];
auto* parameter = juceParameters.getParamForIndex (i);
auto& paramDef = parametersPtr.get()[i];
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
// 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)
juceParameters.params.add (bypassParameter);
juceParameters.addNonOwning (bypassParameter);
int i = 0;
for (auto* juceParam : juceParameters.params)
for (auto* juceParam : juceParameters)
{
bool isBypassParameter = (juceParam == bypassParameter);
@@ -568,7 +568,7 @@ private:
0, numPrograms - 1,
audioProcessor->getCurrentProgram());
juceParameters.params.add (ownedProgramParameter.get());
juceParameters.addNonOwning (ownedProgramParameter.get());
if (forceLegacyParamIDs)
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;
}
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();
if (auto* paramWithID = dynamic_cast<AudioProcessorParameterWithID*> (param))
if (auto* paramWithID = dynamic_cast<const AudioProcessorParameterWithID*> (param))
{
if (! forceLegacyParamIDs)
return paramWithID->paramID;
@@ -120,6 +120,13 @@ public:
class LegacyAudioParametersWrapper
{
public:
LegacyAudioParametersWrapper() = default;
LegacyAudioParametersWrapper (AudioProcessor& audioProcessor, bool forceLegacyParamIDs)
{
update (audioProcessor, forceLegacyParamIDs);
}
void update (AudioProcessor& audioProcessor, bool forceLegacyParamIDs)
{
clear();
@@ -131,15 +138,28 @@ public:
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);
}
processorGroup = usingManagedParameters ? &audioProcessor.getParameterTree()
: nullptr;
}
void clear()
{
legacy.clear();
ownedGroup = AudioProcessorParameterGroup();
params.clear();
}
@@ -159,13 +179,34 @@ public:
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; }
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:
OwnedArray<LegacyAudioParameter> legacy;
const AudioProcessorParameterGroup* processorGroup = nullptr;
AudioProcessorParameterGroup ownedGroup;
Array<AudioProcessorParameter*> params;
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
{
public:
ParameterDisplayComponent (AudioProcessor& processor, AudioProcessorParameter& param)
: parameter (param)
ParameterDisplayComponent (AudioProcessorEditor& editorIn, AudioProcessorParameter& param)
: editor (editorIn), parameter (param)
{
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 (processor)));
addAndMakeVisible (*(parameterComp = createParameterComp (editor.processor)));
setSize (400, 40);
}
void paint (Graphics&) override {}
void resized() override
{
auto area = getLocalBounds();
@@ -435,7 +435,22 @@ public:
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:
PopupMenu::Options getMenuOptions()
{
return PopupMenu::Options().withTargetComponent (this)
.withTargetScreenArea ({ Desktop::getMousePosition(), Desktop::getMousePosition() });
}
AudioProcessorEditor& editor;
AudioProcessorParameter& parameter;
Label parameterName, parameterLabel;
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
{
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;
Viewport view;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
ParameterGroupItem groupItem;
TreeView view;
};
//==============================================================================
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)
{
@@ -571,7 +586,7 @@ void GenericAudioProcessorEditor::paint (Graphics& g)
void GenericAudioProcessorEditor::resized()
{
pimpl->resize (getLocalBounds());
pimpl->view.setBounds (getLocalBounds());
}
} // namespace juce

Loading…
Cancel
Save