commit 77bd69efec2d4d1e3f90ace5e7c1d4d9fa553919
parent 26373f3c701543a4014569de3c630427cc9baf46
Author: falkTX <falktx@falktx.com>
Date: Wed, 11 Oct 2023 14:40:34 +0200
Add plugin-side parameters to cairoui example
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
8 files changed, 336 insertions(+), 185 deletions(-)
diff --git a/examples/CairoUI/CMakeLists.txt b/examples/CairoUI/CMakeLists.txt
@@ -2,13 +2,12 @@
# ------------------------------ #
dpf_add_plugin(d_cairoui
- TARGETS jack dssi lv2 vst2
+ TARGETS clap dssi jack lv2_sep vst2 vst3
UI_TYPE cairo
FILES_DSP
CairoExamplePlugin.cpp
FILES_UI
Artwork.cpp
- DemoWidgetBanner.cpp
CairoExampleUI.cpp)
target_include_directories(
diff --git a/examples/CairoUI/CairoExamplePlugin.cpp b/examples/CairoUI/CairoExamplePlugin.cpp
@@ -23,33 +23,62 @@ START_NAMESPACE_DISTRHO
class CairoExamplePlugin : public Plugin
{
+ float fParameters[kParameterCount];
+
public:
CairoExamplePlugin()
- : Plugin(0, 0, 0)
+ : Plugin(kParameterCount, 0, 0)
{
+ std::memset(fParameters, 0, sizeof(fParameters));
}
- const char* getLabel() const
+ /**
+ Get the plugin label.@n
+ This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters.
+ */
+ const char* getLabel() const override
+ {
+ return "cairo_ui";
+ }
+
+ /**
+ Get an extensive comment/description about the plugin.
+ */
+ const char* getDescription() const override
{
return "Cairo DPF Example";
}
- const char* getMaker() const
+ /**
+ Get the plugin author/maker.
+ */
+ const char* getMaker() const override
{
- return "Jean Pierre Cimalando";
+ return "DISTRHO";
}
- const char* getLicense() const
+ /**
+ Get the plugin license (a single line of text or a URL).@n
+ For commercial plugins this should return some short copyright information.
+ */
+ const char* getLicense() const override
{
return "ISC";
}
- uint32_t getVersion() const
+ /**
+ Get the plugin version, in hexadecimal.
+ */
+ uint32_t getVersion() const override
{
return d_version(1, 0, 0);
}
- int64_t getUniqueId() const
+ /**
+ Get the plugin unique Id.@n
+ This value is used by LADSPA, DSSI, VST2 and VST3 plugin formats.
+ */
+ int64_t getUniqueId() const override
{
return d_cconst('d', 'C', 'a', 'i');
}
@@ -58,7 +87,7 @@ public:
Initialize the audio port @a index.@n
This function will be called once, shortly after the plugin is created.
*/
- void initAudioPort(bool input, uint32_t index, AudioPort& port) override
+ void initAudioPort(const bool input, const uint32_t index, AudioPort& port) override
{
// treat meter audio ports as stereo
port.groupId = kPortGroupMono;
@@ -67,29 +96,91 @@ public:
Plugin::initAudioPort(input, index, port);
}
- void initParameter(uint32_t index, Parameter& parameter)
+ /**
+ Initialize the parameter @a index.@n
+ This function will be called once, shortly after the plugin is created.
+ */
+ void initParameter(const uint32_t index, Parameter& parameter) override
{
- // unused
- (void)index;
- (void)parameter;
+ /**
+ All parameters in this plugin have the same ranges.
+ */
+ switch (index)
+ {
+ case kParameterKnob:
+ parameter.hints = kParameterIsAutomatable;
+ parameter.name = "Knob";
+ parameter.symbol = "knob";
+ parameter.ranges.min = 0.0f;
+ parameter.ranges.max = 1.0f;
+ parameter.ranges.def = 0.0f;
+ break;
+ case kParameterTriState:
+ parameter.hints = kParameterIsAutomatable|kParameterIsInteger;
+ parameter.name = "Color";
+ parameter.symbol = "color";
+ parameter.ranges.min = 0.0f;
+ parameter.ranges.max = 2.0f;
+ parameter.ranges.def = 0.0f;
+ parameter.enumValues.count = 3;
+ parameter.enumValues.restrictedMode = true;
+ {
+ ParameterEnumerationValue* const values = new ParameterEnumerationValue[3];
+ parameter.enumValues.values = values;
+ values[0].label = "Red";
+ values[0].value = 0;
+ values[1].label = "Green";
+ values[1].value = 1;
+ values[2].label = "Blue";
+ values[2].value = 2;
+ }
+ break;
+ case kParameterButton:
+ parameter.hints = kParameterIsAutomatable|kParameterIsBoolean;
+ parameter.name = "Button";
+ parameter.symbol = "button";
+ parameter.ranges.min = 0.0f;
+ parameter.ranges.max = 1.0f;
+ parameter.ranges.def = 0.0f;
+ parameter.enumValues.count = 2;
+ parameter.enumValues.restrictedMode = true;
+ {
+ ParameterEnumerationValue* const values = new ParameterEnumerationValue[2];
+ parameter.enumValues.values = values;
+ values[0].label = "Off";
+ values[0].value = 0;
+ values[1].label = "On";
+ values[1].value = 1;
+ }
+ break;
+ }
}
- float getParameterValue(uint32_t index) const
+ /**
+ Get the current value of a parameter.@n
+ The host may call this function from any context, including realtime processing.
+ */
+ float getParameterValue(const uint32_t index) const override
{
- return 0;
-
- // unused
- (void)index;
+ return fParameters[index];
}
- void setParameterValue(uint32_t index, float value)
+ /**
+ Change a parameter value.@n
+ The host may call this function from any context, including realtime processing.@n
+ When a parameter is marked as automatable, you must ensure no non-realtime operations are performed.
+ @note This function will only be called for parameter inputs.
+ */
+ void setParameterValue(const uint32_t index, const float value) override
{
- // unused
- (void)index;
- (void)value;
+ fParameters[index] = value;
}
- void run(const float** inputs, float** outputs, uint32_t frames)
+ /**
+ Run/process function for plugins without MIDI input.
+ @note Some parameters might be null if there are no audio inputs or outputs.
+ */
+ void run(const float** const inputs, float** const outputs, const uint32_t frames) override
{
/**
This plugin does nothing, it just demonstrates cairo UI usage.
diff --git a/examples/CairoUI/CairoExampleUI.cpp b/examples/CairoUI/CairoExampleUI.cpp
@@ -23,42 +23,56 @@
START_NAMESPACE_DISTRHO
-/**
- We need a few classes from DGL.
- */
+// We need a few classes from DGL.
using DGL_NAMESPACE::CairoGraphicsContext;
using DGL_NAMESPACE::CairoImage;
-using DGL_NAMESPACE::CairoImageButton;
using DGL_NAMESPACE::CairoImageKnob;
+using DGL_NAMESPACE::CairoImageSwitch;
+
+// And from ourselves
+using DGL_NAMESPACE::DemoWidgetBanner;
-class CairoExampleUI : public UI
+class CairoExampleUI : public UI,
+ public CairoImageKnob::Callback,
+ public CairoImageSwitch::Callback,
+ public DemoWidgetClickable::Callback
{
+ ScopedPointer<CairoImageKnob> fKnob;
+ ScopedPointer<CairoImageSwitch> fButton;
+ ScopedPointer<DemoWidgetBanner> fWidgetBanner;
+ ScopedPointer<DemoWidgetClickable> fWidgetClickable;
+
public:
CairoExampleUI()
- : UI(200, 200)
{
- fWidgetClickable = new DemoWidgetClickable(this);
- fWidgetClickable->setSize(50, 50);
- fWidgetClickable->setAbsolutePos(100, 100);
+ CairoImage knobSkin;
+ knobSkin.loadFromPNG(Artwork::knobData, Artwork::knobDataSize);
fWidgetBanner = new DemoWidgetBanner(this);
- fWidgetBanner->setSize(180, 80);
fWidgetBanner->setAbsolutePos(10, 10);
+ fWidgetBanner->setSize(180, 80);
- CairoImage knobSkin;
- knobSkin.loadFromPNG(Artwork::knobData, Artwork::knobDataSize);
+ fWidgetClickable = new DemoWidgetClickable(this);
+ fWidgetClickable->setAbsolutePos(100, 100);
+ fWidgetClickable->setSize(50, 50);
+ fWidgetClickable->setCallback(this);
+ fWidgetClickable->setId(kParameterTriState);
fKnob = new CairoImageKnob(this, knobSkin);
- fKnob->setSize(80, 80);
fKnob->setAbsolutePos(10, 100);
+ fKnob->setSize(80, 80);
+ fKnob->setCallback(this);
+ fKnob->setId(kParameterKnob);
CairoImage buttonOn, buttonOff;
buttonOn.loadFromPNG(Artwork::buttonOnData, Artwork::buttonOnDataSize);
buttonOff.loadFromPNG(Artwork::buttonOffData, Artwork::buttonOffDataSize);
- fButton = new CairoImageButton(this, buttonOff, buttonOn);
- fButton->setSize(60, 35);
+ fButton = new CairoImageSwitch(this, buttonOff, buttonOn);
fButton->setAbsolutePos(100, 160);
+ fButton->setSize(60, 35);
+ fButton->setCallback(this);
+ fButton->setId(kParameterButton);
#if 0
// we can use this if/when our resources are scalable, for now they are PNGs
@@ -67,7 +81,7 @@ public:
setSize(200 * scaleFactor, 200 * scaleFactor);
#else
// without scalable resources, let DPF handle the scaling internally
- setGeometryConstraints(200, 200, true, true);
+ setGeometryConstraints(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT, true, true);
#endif
}
@@ -101,18 +115,46 @@ protected:
}
#endif
- void parameterChanged(uint32_t index, float value) override
+ void parameterChanged(const uint32_t index, const float value) override
{
- // unused
- (void)index;
- (void)value;
+ switch (index)
+ {
+ case kParameterKnob:
+ fKnob->setValue(value);
+ break;
+ case kParameterTriState:
+ fWidgetClickable->setColorId(static_cast<int>(value + 0.5f));
+ break;
+ case kParameterButton:
+ fButton->setDown(value > 0.5f);
+ break;
+ }
}
-private:
- ScopedPointer<DemoWidgetClickable> fWidgetClickable;
- ScopedPointer<DemoWidgetBanner> fWidgetBanner;
- ScopedPointer<CairoImageKnob> fKnob;
- ScopedPointer<CairoImageButton> fButton;
+ void demoWidgetClicked(DemoWidgetClickable*, const uint8_t colorId) override
+ {
+ setParameterValue(kParameterTriState, colorId);
+ }
+
+ void imageKnobDragStarted(CairoImageKnob*) override
+ {
+ editParameter(kParameterKnob, true);
+ }
+
+ void imageKnobDragFinished(CairoImageKnob*) override
+ {
+ editParameter(kParameterKnob, false);
+ }
+
+ void imageKnobValueChanged(CairoImageKnob*, const float value) override
+ {
+ setParameterValue(kParameterKnob, value);
+ }
+
+ void imageSwitchClicked(CairoImageSwitch*, bool down) override
+ {
+ setParameterValue(kParameterButton, down ? 1.f : 0.f);
+ }
};
UI* createUI()
diff --git a/examples/CairoUI/DemoWidgetBanner.cpp b/examples/CairoUI/DemoWidgetBanner.cpp
@@ -1,99 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
- * Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
- *
- * Permission to use, copy, modify, and/or distribute this software for any purpose with
- * or without fee is hereby granted, provided that the above copyright notice and this
- * permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "DemoWidgetBanner.hpp"
-
-START_NAMESPACE_DGL
-
-// -----------------------------------------------------------------------
-
-static const char* banner =
-" "
-" * * * * * "
-" ** ** * * * * "
-" * * * * * * * "
-" * * * **** *** * **** * * ** **** * *** "
-" * * * * ** * * * * * * ** * "
-" * * ***** * * ****** * * * * * * * "
-" * * * * * * * * * * * * * * "
-" * * * ** * ** * * * * * * * * * * "
-" * * *** * *** * **** ** ** ***** ** * * "
-" "
-" "
-" "
-" ***** **** ***** "
-" * * * * * "
-" * * * * * "
-" * * * * * "
-" * * **** **** "
-" * * * * "
-" * * * * "
-" * * * * "
-" ***** * * "
-" ";
-
-enum
-{
- rows = 23,
- columns = 72,
-};
-
-DemoWidgetBanner::DemoWidgetBanner(SubWidget* parent)
- : CairoSubWidget(parent) {}
-
-DemoWidgetBanner::DemoWidgetBanner(TopLevelWidget* parent)
- : CairoSubWidget(parent) {}
-
-void DemoWidgetBanner::onCairoDisplay(const CairoGraphicsContext& context)
-{
- cairo_t* cr = context.handle;
-
- Size<uint> sz = getSize();
- int w = sz.getWidth();
- int h = sz.getHeight();
-
- double diameter = (double)w / columns;
- double radius = 0.5 * diameter;
- double xoff = 0;
- double yoff = 0.5 * (h - rows * diameter);
- for (int r = 0; r < rows; ++r)
- {
- for (int c = 0; c < columns; ++c)
- {
- double cx = xoff + radius + c * diameter;
- double cy = yoff + radius + r * diameter;
-
- char ch = banner[c + r * columns];
- if (ch != ' ')
- cairo_set_source_rgb(cr, 0.5, 0.9, 0.2);
- else
- cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
-
- cairo_save(cr);
- cairo_translate(cr, cx, cy);
- cairo_scale(cr, radius, radius);
- cairo_arc(cr, 0.0, 0.0, 1.0, 0.0, 2 * M_PI);
- cairo_restore(cr);
-
- cairo_fill(cr);
- }
- }
-}
-
-// -----------------------------------------------------------------------
-
-END_NAMESPACE_DGL
diff --git a/examples/CairoUI/DemoWidgetBanner.hpp b/examples/CairoUI/DemoWidgetBanner.hpp
@@ -1,7 +1,7 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
+ * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
@@ -23,17 +23,84 @@ START_NAMESPACE_DGL
// -----------------------------------------------------------------------
+static constexpr const char banner[] =
+" "
+" * * * * * "
+" ** ** * * * * "
+" * * * * * * * "
+" * * * **** *** * **** * * ** **** * *** "
+" * * * * ** * * * * * * ** * "
+" * * ***** * * ****** * * * * * * * "
+" * * * * * * * * * * * * * * "
+" * * * ** * ** * * * * * * * * * * "
+" * * *** * *** * **** ** ** ***** ** * * "
+" "
+" "
+" "
+" ***** **** ***** "
+" * * * * * "
+" * * * * * "
+" * * * * * "
+" * * **** **** "
+" * * * * "
+" * * * * "
+" * * * * "
+" ***** * * "
+" ";
+
+enum {
+ rows = 23,
+ columns = 72,
+};
+
class DemoWidgetBanner : public CairoSubWidget
{
public:
- explicit DemoWidgetBanner(SubWidget* parent);
- explicit DemoWidgetBanner(TopLevelWidget* parent);
+ explicit DemoWidgetBanner(SubWidget* const parent)
+ : CairoSubWidget(parent) {}
+
+ explicit DemoWidgetBanner(TopLevelWidget* const parent)
+ : CairoSubWidget(parent) {}
+
protected:
- void onCairoDisplay(const CairoGraphicsContext& context) override;
+ void onCairoDisplay(const CairoGraphicsContext& context) override
+ {
+ cairo_t* const cr = context.handle;
+
+ Size<uint> sz = getSize();
+ int w = sz.getWidth();
+ int h = sz.getHeight();
+
+ const double diameter = (double)w / columns;
+ const double radius = 0.5 * diameter;
+ const double xoff = 0;
+ const double yoff = 0.5 * (h - rows * diameter);
+
+ for (int r = 0; r < rows; ++r)
+ {
+ for (int c = 0; c < columns; ++c)
+ {
+ double cx = xoff + radius + c * diameter;
+ double cy = yoff + radius + r * diameter;
+
+ char ch = banner[c + r * columns];
+ if (ch != ' ')
+ cairo_set_source_rgb(cr, 0.5, 0.9, 0.2);
+ else
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+
+ cairo_save(cr);
+ cairo_translate(cr, cx, cy);
+ cairo_scale(cr, radius, radius);
+ cairo_arc(cr, 0.0, 0.0, 1.0, 0.0, 2 * M_PI);
+ cairo_restore(cr);
+
+ cairo_fill(cr);
+ }
+ }
+ }
};
// -----------------------------------------------------------------------
END_NAMESPACE_DGL
-
-using DGL_NAMESPACE::DemoWidgetBanner;
diff --git a/examples/CairoUI/DemoWidgetClickable.hpp b/examples/CairoUI/DemoWidgetClickable.hpp
@@ -1,7 +1,7 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
+ * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
@@ -23,16 +23,51 @@ START_NAMESPACE_DGL
// -----------------------------------------------------------------------
-class DemoWidgetClickable : public CairoSubWidget
+class DemoWidgetClickable : public CairoSubWidget,
+ public ButtonEventHandler,
+ public ButtonEventHandler::Callback
{
public:
+ class Callback
+ {
+ public:
+ virtual ~Callback() {}
+ virtual void demoWidgetClicked(DemoWidgetClickable* widget, uint8_t colorId) = 0;
+ };
+
explicit DemoWidgetClickable(SubWidget* const parent)
: CairoSubWidget(parent),
- colorId(0) {}
+ ButtonEventHandler(this),
+ fCallback(nullptr),
+ fColorId(0)
+ {
+ ButtonEventHandler::setCallback(this);
+ }
explicit DemoWidgetClickable(TopLevelWidget* const parent)
: CairoSubWidget(parent),
- colorId(0) {}
+ ButtonEventHandler(this),
+ fCallback(nullptr),
+ fColorId(0)
+ {
+ ButtonEventHandler::setCallback(this);
+ }
+
+ void setCallback(Callback* const callback) noexcept
+ {
+ fCallback = callback;
+ }
+
+ uint8_t getColorId() const noexcept
+ {
+ return fColorId;
+ }
+
+ void setColorId(uint8_t colorId) noexcept
+ {
+ fColorId = colorId;
+ repaint();
+ }
protected:
void onCairoDisplay(const CairoGraphicsContext& context) override
@@ -43,7 +78,7 @@ protected:
const int w = sz.getWidth();
const int h = sz.getHeight();
- switch (colorId)
+ switch (fColorId)
{
case 0:
cairo_set_source_rgb(cr, 0.75, 0.0, 0.0);
@@ -72,26 +107,21 @@ protected:
bool onMouse(const MouseEvent& event) override
{
- if (event.press)
- {
- const int w = getWidth();
- const int h = getHeight();
- const int mx = event.pos.getX();
- const int my = event.pos.getY();
-
- // inside
- if (mx >= 0 && my >= 0 && mx < w && my < h)
- {
- colorId = (colorId + 1) % 3;
- repaint();
- }
- }
+ return ButtonEventHandler::mouseEvent(event);
+ }
+
+ void buttonClicked(SubWidget*, int) override
+ {
+ fColorId = (fColorId + 1) % 3;
+ repaint();
- return CairoSubWidget::onMouse(event);
+ if (fCallback != nullptr)
+ fCallback->demoWidgetClicked(this, fColorId);
}
private:
- uint colorId;
+ Callback* fCallback;
+ uint8_t fColorId;
};
// -----------------------------------------------------------------------
diff --git a/examples/CairoUI/DistrhoPluginInfo.h b/examples/CairoUI/DistrhoPluginInfo.h
@@ -118,10 +118,36 @@
#define DISTRHO_UI_USE_NANOVG 0
/**
- The %UI URI when exporting in LV2 format.@n
- By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix.
+ Default UI width to use when creating initial and temporary windows.@n
+ Setting this macro allows to skip a temporary UI from being created in certain VST2 and VST3 hosts.
+ (which would normally be done for knowing the UI size before host creates a window for it)
+
+ Value must match 1x scale factor.
+
+ When this macro is defined, the companion DISTRHO_UI_DEFAULT_HEIGHT macro must be defined as well.
*/
-#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"
+#define DISTRHO_UI_DEFAULT_WIDTH 200
-#define DISTRHO_UI_FILE_BROWSER 0
+/**
+ Default UI height to use when creating initial and temporary windows.@n
+ Setting this macro allows to skip a temporary UI from being created in certain VST2 and VST3 hosts.
+ (which would normally be done for knowing the UI size before host creates a window for it)
+
+ Value must match 1x scale factor.
+
+ When this macro is defined, the companion DISTRHO_UI_DEFAULT_WIDTH macro must be defined as well.
+ */
+#define DISTRHO_UI_DEFAULT_HEIGHT 200
+
+// TODO document this
#define DISTRHO_UI_USE_CAIRO 1
+
+// TODO document this
+#define DISTRHO_UI_FILE_BROWSER 0
+
+enum Parameters {
+ kParameterKnob,
+ kParameterTriState,
+ kParameterButton,
+ kParameterCount
+};
diff --git a/examples/CairoUI/Makefile b/examples/CairoUI/Makefile
@@ -17,7 +17,6 @@ FILES_DSP = \
FILES_UI = \
Artwork.cpp \
- DemoWidgetBanner.cpp \
CairoExampleUI.cpp
# --------------------------------------------------------------
@@ -29,11 +28,7 @@ include ../../Makefile.plugins.mk
# --------------------------------------------------------------
# Enable all possible plugin types
-TARGETS += clap
-TARGETS += dssi
-TARGETS += jack
-TARGETS += lv2_sep
-TARGETS += vst2
+TARGETS = clap dssi jack lv2_sep vst2 vst3
all: $(TARGETS)