diff --git a/dpf/FEATURES.md b/dpf/FEATURES.md
new file mode 100644
index 0000000..3bba8f1
--- /dev/null
+++ b/dpf/FEATURES.md
@@ -0,0 +1,93 @@
+# DPF - DISTRHO Plugin Framework
+
+This file describes the available features for each plugin format.
+The limitations could be due to the plugin format itself or within DPF.
+If the limitation is within DPF, a link is provided to a description below on the reason for it.
+
+| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | Feature |
+|---------------------|---------------------------------------|-------------------------|---------------------|-------------------------------|--------------------------------|----------------------------------|---------------------|
+| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Audio port groups |
+| Audio port as CV | Yes | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Audio port as CV |
+| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | Audio sidechan |
+| Bypass control | No | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | Bypass control |
+| MIDI input | Yes | No | Yes | Yes | Yes | Yes | MIDI input |
+| MIDI output | Yes | No | No | Yes | Yes | Yes | MIDI output |
+| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Parameter changes |
+| Parameter groups | No | No | No | Yes | Yes | [No*](#vst3-is-work-in-progress) | Parameter groups |
+| Parameter outputs | No | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Parameter outputs |
+| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers |
+| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-programs) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | Programs |
+| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | States |
+| Full/internal state | Yes | No | No | Yes | Yes | Yes | Full/internal state |
+| Time position | Yes | No | No | Yes | Yes | Yes | Time position |
+| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | UI |
+| UI bg/fg colors | No | No | No | Yes | No | No? | UI bg/fg colors |
+| UI direct access | Yes | No | No | Yes | Yes | Yes | UI direct access |
+| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | UI host-filebrowser |
+| UI host-resize | Yes | No | Yes | Yes | No | [No*](#vst3-is-work-in-progress) | UI host-resize |
+| UI remote control | No | No | Yes | Yes | No | Yes | UI remote control |
+| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | UI send midi note |
+
+For things that could be unclear:
+
+- "States" refers to DPF API support, supporting key-value string pairs for internal state saving
+- "Full state" refers to plugins updating their state internally without outside intervention (like host or UI)
+- "UI direct access" means `DISTRHO_PLUGIN_WANT_DIRECT_ACCESS` is possible, that is, running DSP and UI on the same process
+- "UI remote control" means running the UI on a separate machine (for example over the network)
+- An external UI on this table means that it cannot be embed into the host window, but the plugin can still provide one
+
+# Special notes
+
+## Parameter triggers
+
+Trigger-style parameters (parameters which value is reset to its default every run) are only supported in JACK and LV2.
+For all other plugin formats DPF will simulate the behaviour through a parameter change request.
+
+## JACK audio port groups
+
+DPF will set JACK metadata information for grouping audio ports.
+This is not supported by most JACK applications at the moment.
+
+## JACK parameters and programs
+
+Under JACK/Stanlone mode, MIDI input events will trigger program and parameter changes.
+MIDI program change events work as expected (that is, MIDI program change 0 will load 1st plugin program).
+MIDI CCs are used for parameter changes (matching the `midiCC` value you set on each parameter).
+
+## JACK custom UI only
+
+There is no generic plugin editor view.
+If your plugin has no custom UI, the standalone executable will run but not show any window.
+
+## LADSPA programs
+
+Programs for LADSPA could be done via LRDF but this is not supported in DPF.
+
+## DSSI State
+
+DSSI only supports state changes when called via UI, no "full state" possible.
+This also makes it impossibe to use programs and state at the same time with DSSI,
+because in DPF changing programs can lead to state changes but there is no way to fetch this information on DSSI plugins.
+
+To make it simpler to understand, think of DSSI programs and states as UI properties.
+Because in DPF changing the state happens from UI to DSP side, regular DSSI can be supported.
+But if we involve programs, they would need to pass through the UI in order to work. Which goes against DPF's design.
+
+## LV2 parameter changes
+
+Although this is already implemented in DPF (through a custom extension), this is not implemented on most hosts.
+So for now you can pretty much treat it as if not supported.
+
+## VST2 potential support
+
+Not supported in DPF at the moment.
+It could eventually be, but likely not due to VST2 being phased out by Steinberg.
+Contact DPF authors if you require such a feature.
+
+## VST2 programs
+
+VST2 program support requires saving state of all programs in memory, which is very expensive and thus not done in DPF.
+
+## VST3 is work in progress
+
+Feature is possible, just not implemented yet in DPF.
diff --git a/dpf/LICENSING.md b/dpf/LICENSING.md
new file mode 100644
index 0000000..ad0a4c4
--- /dev/null
+++ b/dpf/LICENSING.md
@@ -0,0 +1,47 @@
+# DPF - DISTRHO Plugin Framework
+
+Even though DPF is quite liberally licensed, not all plugin formats follow the same ideals.
+This is usually due to plugin APIs/headers being tied to a specific license or having commercial restrictions.
+This file describes the licensing that applies to each individual plugin format as a way to make it clear what is possible and compatible.
+Note that if you are making GPLv2+ licensed plugins this does not apply to you, as so far everything is GPLv2+ compatible.
+
+Regardless of target format, DPF itself needs to be mentioned in attribution.
+See the [LICENSE](LICENSE) file for copyright details.
+
+| Target | License(s) | License restrictions | Additional attribution |
+|-----------------|----------------------|-----------------------|------------------------|
+| JACK/Standalone | MIT (RtAudio) | Copyright attribution | **RtAudio**: 2001-2019 Gary P. Scavone |
+| LADSPA | LGPLv2.1+ | ??? (*) | 2000-2002 Richard W. E. Furse, Paul Barton-Davis, Stefan Westerfeld |
+| DSSI | LGPLv2.1+ | ??? (*) | **DSSI**: 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton;
**ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai |
+| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;
2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld |
+| VST2 | GPLv2+ or commercial | Must be GPLv2+ compatible or alternatively use Steinberg VST2 SDK (no longer available for new plugins) | GPLv2+ compatible license or custom agreement with Steinberg |
+| VST3 | ISC | Copyright attribution | (none, only DPF files used) |
+
+### LADSPA and DSSI special note
+
+The header files on LADSPA and DSSI are LGPLv2.1+ licensed, which is unusual for pure APIs without libraries.
+LADSPA authors mention this on ladspa.org homepage:
+
+> LADSPA has been released under LGPL (GNU Lesser General Public License).
+> This is not intended to be the final license for LADSPA.
+> In the long term it is hoped that LADSPA will have a public license that is even less restrictive, so that commercial applications can use it (in a protected way) without having to use a derived LGPL library.
+> It may be that LGPL is already free enough for this, but we aren't sure.
+
+So the situation for LADSPA/DSSI plugins is unclear for commercial plugins.
+These formats are very limited and not much used anymore anyway, feel free to skip them if this situation is a potential issue for you.
+
+### VST2 special note
+
+By default DPF uses the free reverse-engineered [vestige header](distrho/src/vestige/vestige.h) file.
+This file is GPLv2+ licensed, so that applies to plugins built with it as well.
+You can alternatively build DPF-based VST2 plugins using the official Steinberg VST2 SDK,
+simply set the `VESTIGE_HEADER` compiler macro to `0` during build.
+You will need to provide your own VST2 SDK files then, as DPF does not ship with them.
+Note there are legal issues surrounding releasing new VST2 plugins using the official SDK, as that is no longer supported by Steinberg.
+
+### VST3 special note
+
+Contrary to most plugins, DPF does not use the official VST3 SDK.
+Instead, the API definitions are provided by the [travesty](distrho/src/travesty/) sub-project, licensed in the same way as DPF.
+This allows us to freely build plugins without being encumbered by restrictive licensing deals.
+It makes the internal implementation much harder for DPF, but this is not an issue for external developers.
diff --git a/dpf/Makefile.plugins.mk b/dpf/Makefile.plugins.mk
index 8114387..0ba0ce4 100644
--- a/dpf/Makefile.plugins.mk
+++ b/dpf/Makefile.plugins.mk
@@ -33,7 +33,6 @@ endif
BUILD_C_FLAGS += -I.
BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl
-BUILD_CXX_FLAGS += -Wno-pmf-conversions
ifeq ($(HAVE_ALSA),true)
BASE_FLAGS += -DHAVE_ALSA
@@ -128,7 +127,7 @@ SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def
SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def
SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def
SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def
-else
+else ifneq ($(DEBUG),true)
SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version
SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version
SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version
@@ -224,6 +223,13 @@ endif
# TODO split dsp and ui object build flags
BASE_FLAGS += $(DGL_FLAGS)
+# ---------------------------------------------------------------------------------------------------------------------
+# Runtime test build
+
+ifeq ($(DPF_RUNTIME_TESTING),true)
+BUILD_CXX_FLAGS += -DDPF_RUNTIME_TESTING -Wno-pmf-conversions
+endif
+
# ---------------------------------------------------------------------------------------------------------------------
# all needs to be first
@@ -386,7 +392,11 @@ endif
vst3: $(vst3)
+ifeq ($(HAVE_DGL),true)
+$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB)
+else
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o
+endif
-@mkdir -p $(shell dirname $@)
@echo "Creating VST3 plugin for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@
diff --git a/dpf/README.md b/dpf/README.md
index 0392faa..18dbc65 100644
--- a/dpf/README.md
+++ b/dpf/README.md
@@ -19,6 +19,12 @@ Getting time information from the host is possible.
It uses the same format as the JACK Transport API, making porting some code easier.
+## Licensing
+
+DPF is released under ISC, which basically means you can do whatever you want as long as you credit the original authors.
+Some plugin formats may have additional restrictions, see [LICENSING.md](LICENSING.md) for details.
+
+
## Help and documentation
Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues).
diff --git a/dpf/dgl/Application.hpp b/dpf/dgl/Application.hpp
index 0979987..87937cc 100644
--- a/dpf/dgl/Application.hpp
+++ b/dpf/dgl/Application.hpp
@@ -107,6 +107,7 @@ public:
private:
struct PrivateData;
PrivateData* const pData;
+ friend class PluginApplication;
friend class Window;
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application)
diff --git a/dpf/dgl/Base.hpp b/dpf/dgl/Base.hpp
index d726c6f..0288cb0 100644
--- a/dpf/dgl/Base.hpp
+++ b/dpf/dgl/Base.hpp
@@ -49,16 +49,16 @@ enum Modifier {
/**
Keyboard key codepoints.
- All keys are identified by a Unicode code point in PuglEventKey::key. This
- enumeration defines constants for special keys that do not have a standard
- code point, and some convenience constants for control characters. Note
- that all keys are handled in the same way, this enumeration is just for
+ All keys are identified by a Unicode code point in Widget::KeyboardEvent::key.
+ This enumeration defines constants for special keys that do not have a standard
+ code point, and some convenience constants for control characters.
+ Note that all keys are handled in the same way, this enumeration is just for
convenience when writing hard-coded key bindings.
Keys that do not have a standard code point use values in the Private Use
- Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications
- must take care to not interpret these values beyond key detection, the
- mapping used here is arbitrary and specific to DPF.
+ Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`).
+ Applications must take care to not interpret these values beyond key detection,
+ the mapping used here is arbitrary and specific to DPF.
*/
enum Key {
// Convenience symbols for ASCII control characters
@@ -116,7 +116,7 @@ enum Key {
/**
Common flags for all events.
*/
-enum Flag {
+enum EventFlag {
kFlagSendEvent = 1, ///< Event is synthetic
kFlagIsHint = 2 ///< Event is a hint (not direct user input)
};
diff --git a/dpf/dgl/NanoVG.hpp b/dpf/dgl/NanoVG.hpp
index cf693d3..af33ab8 100644
--- a/dpf/dgl/NanoVG.hpp
+++ b/dpf/dgl/NanoVG.hpp
@@ -903,7 +903,7 @@ public:
Constructor for a NanoSubWidget.
@see CreateFlags
*/
- explicit NanoBaseWidget(Widget* const parentGroupWidget, int flags = CREATE_ANTIALIAS);
+ explicit NanoBaseWidget(Widget* parentGroupWidget, int flags = CREATE_ANTIALIAS);
/**
Constructor for a NanoTopLevelWidget.
@@ -912,16 +912,16 @@ public:
explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS);
/**
- Constructor for a NanoStandaloneWindow without parent window.
+ Constructor for a NanoStandaloneWindow without transient parent window.
@see CreateFlags
*/
explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS);
/**
- Constructor for a NanoStandaloneWindow with parent window.
+ Constructor for a NanoStandaloneWindow with transient parent window.
@see CreateFlags
*/
- explicit NanoBaseWidget(Application& app, Window& parentWindow, int flags = CREATE_ANTIALIAS);
+ explicit NanoBaseWidget(Application& app, Window& transientParentWindow, int flags = CREATE_ANTIALIAS);
/**
Destructor.
diff --git a/dpf/dgl/TopLevelWidget.hpp b/dpf/dgl/TopLevelWidget.hpp
index 6c01429..5441dbc 100644
--- a/dpf/dgl/TopLevelWidget.hpp
+++ b/dpf/dgl/TopLevelWidget.hpp
@@ -117,7 +117,6 @@ public:
protected:
bool onKeyboard(const KeyboardEvent&) override;
- bool onSpecial(const SpecialEvent&) override;
bool onCharacterInput(const CharacterInputEvent&) override;
bool onMouse(const MouseEvent&) override;
bool onMotion(const MotionEvent&) override;
diff --git a/dpf/dgl/Widget.hpp b/dpf/dgl/Widget.hpp
index 904e005..463f7c9 100644
--- a/dpf/dgl/Widget.hpp
+++ b/dpf/dgl/Widget.hpp
@@ -58,7 +58,7 @@ public:
These are the fields present on all Widget events.
@a mod Currently active keyboard modifiers, @see Modifier.
- @a mod Event flags, @see Flag.
+ @a mod Event flags, @see EventFlag.
@a time Event timestamp (if any).
*/
struct BaseEvent {
@@ -107,14 +107,10 @@ public:
/**
Special keyboard event.
- This event allows the use of keys that do not have unicode points.
- Note that some are non-printable keys.
-
- @a press True if the key was pressed, false if released.
- @a key The key pressed.
- @see onSpecial
+ DEPRECATED This used to be part of DPF due to pugl, but now deprecated and simply non-functional.
+ All events go through KeyboardEvent or CharacterInputEvent, use those instead.
*/
- struct SpecialEvent : BaseEvent {
+ struct DISTRHO_DEPRECATED_BY("KeyboardEvent") SpecialEvent : BaseEvent {
bool press;
Key key;
@@ -398,12 +394,6 @@ protected:
*/
virtual bool onKeyboard(const KeyboardEvent&);
- /**
- A function called when a special key is pressed or released.
- @return True to stop event propagation, false otherwise.
- */
- virtual bool onSpecial(const SpecialEvent&);
-
/**
A function called when an UTF-8 character is received.
@return True to stop event propagation, false otherwise.
@@ -433,6 +423,24 @@ protected:
*/
virtual void onResize(const ResizeEvent&);
+ /**
+ A function called when a special key is pressed or released.
+ DEPRECATED use onKeyboard or onCharacterInput
+ */
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ virtual bool onSpecial(const SpecialEvent&) { return false; }
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
+# pragma GCC diagnostic pop
+#endif
+
private:
struct PrivateData;
PrivateData* const pData;
diff --git a/dpf/dgl/Window.hpp b/dpf/dgl/Window.hpp
index 9effa69..27e72dc 100644
--- a/dpf/dgl/Window.hpp
+++ b/dpf/dgl/Window.hpp
@@ -157,10 +157,10 @@ public:
explicit Window(Application& app);
/**
- Constructor for a modal window, by having another window as its parent.
+ Constructor for a modal window, by having another window as its transient parent.
The Application instance must be the same between the 2 windows.
*/
- explicit Window(Application& app, Window& parent);
+ explicit Window(Application& app, Window& transientParentWindow);
/**
Constructor for an embed Window without known size,
@@ -369,7 +369,7 @@ public:
This function does not block the event loop.
*/
- bool openFileBrowser(const FileBrowserOptions& options);
+ bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions());
#endif
/**
diff --git a/dpf/dgl/src/.kdev_include_paths b/dpf/dgl/src/.kdev_include_paths
new file mode 100644
index 0000000..2103f66
--- /dev/null
+++ b/dpf/dgl/src/.kdev_include_paths
@@ -0,0 +1 @@
+pugl-upstream/include/
diff --git a/dpf/dgl/src/ApplicationPrivateData.cpp b/dpf/dgl/src/ApplicationPrivateData.cpp
index 1de1fc7..f573c2f 100644
--- a/dpf/dgl/src/ApplicationPrivateData.cpp
+++ b/dpf/dgl/src/ApplicationPrivateData.cpp
@@ -118,6 +118,11 @@ void Application::PrivateData::idle(const uint timeoutInMs)
puglUpdate(world, timeoutInSeconds);
}
+ triggerIdleCallbacks();
+}
+
+void Application::PrivateData::triggerIdleCallbacks()
+{
for (std::list::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it)
{
IdleCallback* const idleCallback(*it);
diff --git a/dpf/dgl/src/ApplicationPrivateData.hpp b/dpf/dgl/src/ApplicationPrivateData.hpp
index e35328d..0d2993c 100644
--- a/dpf/dgl/src/ApplicationPrivateData.hpp
+++ b/dpf/dgl/src/ApplicationPrivateData.hpp
@@ -84,6 +84,9 @@ struct Application::PrivateData {
/** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */
void idle(uint timeoutInMs);
+ /** Run each idle callback without updating pugl world. */
+ void triggerIdleCallbacks();
+
/** Set flag indicating application is quitting, and close all windows in reverse order of registration.
For standalone mode only. */
void quit();
diff --git a/dpf/dgl/src/TopLevelWidget.cpp b/dpf/dgl/src/TopLevelWidget.cpp
index e044b03..d714324 100644
--- a/dpf/dgl/src/TopLevelWidget.cpp
+++ b/dpf/dgl/src/TopLevelWidget.cpp
@@ -100,11 +100,6 @@ bool TopLevelWidget::onKeyboard(const KeyboardEvent&)
return false;
}
-bool TopLevelWidget::onSpecial(const SpecialEvent&)
-{
- return false;
-}
-
bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&)
{
return false;
diff --git a/dpf/dgl/src/TopLevelWidgetPrivateData.cpp b/dpf/dgl/src/TopLevelWidgetPrivateData.cpp
index 618cf35..29514bb 100644
--- a/dpf/dgl/src/TopLevelWidgetPrivateData.cpp
+++ b/dpf/dgl/src/TopLevelWidgetPrivateData.cpp
@@ -50,20 +50,6 @@ bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev)
return selfw->pData->giveKeyboardEventForSubWidgets(ev);
}
-bool TopLevelWidget::PrivateData::specialEvent(const SpecialEvent& ev)
-{
- // ignore event if we are not visible
- if (! selfw->pData->visible)
- return false;
-
- // give top-level widget chance to catch this event first
- if (self->onSpecial(ev))
- return true;
-
- // propagate event to all subwidgets recursively
- return selfw->pData->giveSpecialEventForSubWidgets(ev);
-}
-
bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev)
{
// ignore event if we are not visible
diff --git a/dpf/dgl/src/TopLevelWidgetPrivateData.hpp b/dpf/dgl/src/TopLevelWidgetPrivateData.hpp
index 6c88286..7105b2f 100644
--- a/dpf/dgl/src/TopLevelWidgetPrivateData.hpp
+++ b/dpf/dgl/src/TopLevelWidgetPrivateData.hpp
@@ -34,7 +34,6 @@ struct TopLevelWidget::PrivateData {
~PrivateData();
void display();
bool keyboardEvent(const KeyboardEvent& ev);
- bool specialEvent(const SpecialEvent& ev);
bool characterInputEvent(const CharacterInputEvent& ev);
bool mouseEvent(const MouseEvent& ev);
bool motionEvent(const MotionEvent& ev);
diff --git a/dpf/dgl/src/Widget.cpp b/dpf/dgl/src/Widget.cpp
index e6e41d5..8aaa90d 100644
--- a/dpf/dgl/src/Widget.cpp
+++ b/dpf/dgl/src/Widget.cpp
@@ -167,11 +167,6 @@ bool Widget::onKeyboard(const KeyboardEvent& ev)
return pData->giveKeyboardEventForSubWidgets(ev);
}
-bool Widget::onSpecial(const SpecialEvent& ev)
-{
- return pData->giveSpecialEventForSubWidgets(ev);
-}
-
bool Widget::onCharacterInput(const CharacterInputEvent& ev)
{
return pData->giveCharacterInputEventForSubWidgets(ev);
diff --git a/dpf/dgl/src/WidgetPrivateData.cpp b/dpf/dgl/src/WidgetPrivateData.cpp
index 304ad6e..3cbe644 100644
--- a/dpf/dgl/src/WidgetPrivateData.cpp
+++ b/dpf/dgl/src/WidgetPrivateData.cpp
@@ -87,24 +87,6 @@ bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const KeyboardEvent& ev
return false;
}
-bool Widget::PrivateData::giveSpecialEventForSubWidgets(const SpecialEvent& ev)
-{
- if (! visible)
- return false;
- if (subWidgets.size() == 0)
- return false;
-
- FOR_EACH_SUBWIDGET_INV(rit)
- {
- SubWidget* const widget(*rit);
-
- if (widget->isVisible() && widget->onSpecial(ev))
- return true;
- }
-
- return false;
-}
-
bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev)
{
if (! visible)
diff --git a/dpf/dgl/src/WidgetPrivateData.hpp b/dpf/dgl/src/WidgetPrivateData.hpp
index ab38852..15b8409 100644
--- a/dpf/dgl/src/WidgetPrivateData.hpp
+++ b/dpf/dgl/src/WidgetPrivateData.hpp
@@ -44,7 +44,6 @@ struct Widget::PrivateData {
void displaySubWidgets(uint width, uint height, double autoScaleFactor);
bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev);
- bool giveSpecialEventForSubWidgets(const SpecialEvent& ev);
bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev);
bool giveMouseEventForSubWidgets(MouseEvent& ev);
bool giveMotionEventForSubWidgets(MotionEvent& ev);
diff --git a/dpf/dgl/src/Window.cpp b/dpf/dgl/src/Window.cpp
index c9d12df..6f2a7da 100644
--- a/dpf/dgl/src/Window.cpp
+++ b/dpf/dgl/src/Window.cpp
@@ -66,8 +66,8 @@ Window::Window(Application& app)
pData->initPost();
}
-Window::Window(Application& app, Window& parent)
- : pData(new PrivateData(app, this, parent.pData))
+Window::Window(Application& app, Window& transientParentWindow)
+ : pData(new PrivateData(app, this, transientParentWindow.pData))
{
pData->initPost();
}
@@ -407,22 +407,6 @@ void Window::setTransientWinId(const uintptr_t winId)
{
puglSetTransientFor(pData->view, winId);
}
-
-// -----------------------------------------------------------------------
-
-bool Window::handlePluginKeyboard(const bool press, const uint key)
-{
- // TODO
- return false;
- // return pData->handlePluginKeyboard(press, key);
-}
-
-bool Window::handlePluginSpecial(const bool press, const Key key)
-{
- // TODO
- return false;
- // return pData->handlePluginSpecial(press, key);
-}
#endif
// -----------------------------------------------------------------------
diff --git a/dpf/dgl/src/WindowPrivateData.cpp b/dpf/dgl/src/WindowPrivateData.cpp
index 6a1b5ed..15a1d28 100644
--- a/dpf/dgl/src/WindowPrivateData.cpp
+++ b/dpf/dgl/src/WindowPrivateData.cpp
@@ -33,7 +33,11 @@
#define DGL_DEBUG_EVENTS
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
-# include
+# ifdef DISTRHO_PROPER_CPP11_SUPPORT
+# include
+# else
+# include
+# endif
#endif
START_NAMESPACE_DGL
@@ -820,24 +824,6 @@ void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev)
#endif
}
-void Window::PrivateData::onPuglSpecial(const Widget::SpecialEvent& ev)
-{
- DGL_DBGp("onPuglSpecial : %i %u\n", ev.press, ev.key);
-
- if (modal.child != nullptr)
- return modal.child->focus();
-
-#ifndef DPF_TEST_WINDOW_CPP
- FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
- {
- TopLevelWidget* const widget(*rit);
-
- if (widget->isVisible() && widget->pData->specialEvent(ev))
- break;
- }
-#endif
-}
-
void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev)
{
DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string);
@@ -982,7 +968,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
case PUGL_KEY_RELEASE:
{
// unused x, y, xRoot, yRoot (double)
- // TODO special keys?
Widget::KeyboardEvent ev;
ev.mod = event->key.state;
ev.flags = event->key.flags;
@@ -990,8 +975,14 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
ev.press = event->type == PUGL_KEY_PRESS;
ev.key = event->key.key;
ev.keycode = event->key.keycode;
- if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z')
- ev.key -= 'a' - 'A'; // a-z -> A-Z
+
+ // keyboard events must always be lowercase
+ if (ev.key >= 'A' && ev.key <= 'Z')
+ {
+ ev.key += 'a' - 'A'; // A-Z -> a-z
+ ev.mod |= kModifierShift;
+ }
+
pData->onPuglKey(ev);
break;
}
diff --git a/dpf/dgl/src/WindowPrivateData.hpp b/dpf/dgl/src/WindowPrivateData.hpp
index 5f9f898..d8e0f8c 100644
--- a/dpf/dgl/src/WindowPrivateData.hpp
+++ b/dpf/dgl/src/WindowPrivateData.hpp
@@ -178,7 +178,6 @@ struct Window::PrivateData : IdleCallback {
void onPuglClose();
void onPuglFocus(bool focus, CrossingMode mode);
void onPuglKey(const Widget::KeyboardEvent& ev);
- void onPuglSpecial(const Widget::SpecialEvent& ev);
void onPuglText(const Widget::CharacterInputEvent& ev);
void onPuglMouse(const Widget::MouseEvent& ev);
void onPuglMotion(const Widget::MotionEvent& ev);
diff --git a/dpf/distrho/DistrhoInfo.hpp b/dpf/distrho/DistrhoInfo.hpp
index c70752e..6805f4a 100644
--- a/dpf/distrho/DistrhoInfo.hpp
+++ b/dpf/distrho/DistrhoInfo.hpp
@@ -106,13 +106,6 @@ START_NAMESPACE_DISTRHO
return d_cconst('M', 'u', 't', 'e');
}
- /* ----------------------------------------------------------------------------------------
- * This example has no parameters, so skip parameter stuff */
-
- void initParameter(uint32_t, Parameter&) override {}
- float getParameterValue(uint32_t) const override { return 0.0f; }
- void setParameterValue(uint32_t, float) override {}
-
/* ----------------------------------------------------------------------------------------
* Audio/MIDI Processing */
@@ -507,6 +500,20 @@ START_NAMESPACE_DISTRHO
*/
#define DISTRHO_PLUGIN_IS_SYNTH 1
+/**
+ Request the minimum buffer size for the input and output event ports.@n
+ Currently only used in LV2, with a default value of 2048 if unset.
+ */
+#define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048
+
+/**
+ Whether the plugin has an LV2 modgui.
+
+ This will simply add a "rdfs:seeAlso " on the LV2 manifest.@n
+ It is up to you to create this file.
+ */
+#define DISTRHO_PLUGIN_USES_MODGUI 0
+
/**
Enable direct access between the %UI and plugin code.
@see UI::getPluginInstancePointer()
@@ -613,6 +620,158 @@ START_NAMESPACE_DISTRHO
*/
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"
+/**
+ Custom LV2 category for the plugin.@n
+ This can be one of the following values:
+
+ - lv2:Plugin
+ - lv2:AllpassPlugin
+ - lv2:AmplifierPlugin
+ - lv2:AnalyserPlugin
+ - lv2:BandpassPlugin
+ - lv2:ChorusPlugin
+ - lv2:CombPlugin
+ - lv2:CompressorPlugin
+ - lv2:ConstantPlugin
+ - lv2:ConverterPlugin
+ - lv2:DelayPlugin
+ - lv2:DistortionPlugin
+ - lv2:DynamicsPlugin
+ - lv2:EQPlugin
+ - lv2:EnvelopePlugin
+ - lv2:ExpanderPlugin
+ - lv2:FilterPlugin
+ - lv2:FlangerPlugin
+ - lv2:FunctionPlugin
+ - lv2:GatePlugin
+ - lv2:GeneratorPlugin
+ - lv2:HighpassPlugin
+ - lv2:InstrumentPlugin
+ - lv2:LimiterPlugin
+ - lv2:LowpassPlugin
+ - lv2:MIDIPlugin
+ - lv2:MixerPlugin
+ - lv2:ModulatorPlugin
+ - lv2:MultiEQPlugin
+ - lv2:OscillatorPlugin
+ - lv2:ParaEQPlugin
+ - lv2:PhaserPlugin
+ - lv2:PitchPlugin
+ - lv2:ReverbPlugin
+ - lv2:SimulatorPlugin
+ - lv2:SpatialPlugin
+ - lv2:SpectralPlugin
+ - lv2:UtilityPlugin
+ - lv2:WaveshaperPlugin
+
+ See http://lv2plug.in/ns/lv2core for more information.
+ */
+#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:Plugin"
+
+/**
+ Custom VST3 categories for the plugin.@n
+ This is a list of categories, separated by a @c |.
+
+ Each effect category can be one of the following values:
+
+ - Fx
+ - Fx|Ambisonics
+ - Fx|Analyzer
+ - Fx|Delay
+ - Fx|Distortion
+ - Fx|Dynamics
+ - Fx|EQ
+ - Fx|Filter
+ - Fx|Instrument
+ - Fx|Instrument|External
+ - Fx|Spatial
+ - Fx|Generator
+ - Fx|Mastering
+ - Fx|Modulation
+ - Fx|Network
+ - Fx|Pitch Shift
+ - Fx|Restoration
+ - Fx|Reverb
+ - Fx|Surround
+ - Fx|Tools
+
+ Each instrument category can be one of the following values:
+
+ - Instrument
+ - Instrument|Drum
+ - Instrument|External
+ - Instrument|Piano
+ - Instrument|Sampler
+ - Instrument|Synth
+ - Instrument|Synth|Sampler
+
+ @note DPF will automatically set Mono and Stereo categories when appropriate.
+ */
+#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx"
+
+/** @} */
+
+/* ------------------------------------------------------------------------------------------------------------
+ * Plugin Macros */
+
+/**
+ @defgroup ExtraPluginMacros Extra Plugin Macros
+
+ C Macros to customize DPF behaviour.
+
+ These are macros that do not set plugin features or information, but instead change DPF internals.
+ They are all optional.
+
+ Unless stated otherwise, values are assumed to be a simple/empty define.
+ @{
+ */
+
+/**
+ Whether to enable runtime plugin tests.@n
+ This will check, during initialization of the plugin, if parameters, programs and states are setup properly.@n
+ Useful to enable as part of CI, can safely be skipped.@n
+ Under DPF makefiles this can be enabled by using `make DPF_RUNTIME_TESTING=true`.
+
+ @note Some checks are only available with the GCC compiler,
+ for detecting if a virtual function has been reimplemented.
+ */
+#define DPF_RUNTIME_TESTING
+
+/**
+ Whether to show parameter outputs in the VST2 plugins.@n
+ This is disabled (unset) by default, as the VST2 format has no notion of read-only parameters.
+ */
+#define DPF_VST_SHOW_PARAMETER_OUTPUTS
+
+/**
+ Disable all file browser related code.@n
+ Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_FILE_BROWSER_DISABLED"`)
+ */
+#define DGL_FILE_BROWSER_DISABLED
+
+/**
+ Disable resource files, like internally used fonts.@n
+ Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_NO_SHARED_RESOURCES"`)
+ */
+#define DGL_NO_SHARED_RESOURCES
+
+/**
+ Whether to use OpenGL3 instead of the default OpenGL2 compatility profile.
+ Under DPF makefiles this can be enabled by using `make USE_OPENGL3=true` on the dgl build step.
+
+ @note This is experimental and incomplete, contributions are welcome and appreciated.
+ */
+#define DGL_USE_OPENGL3
+
+/**
+ Whether to use the GPLv2+ vestige header instead of the official Steinberg VST2 SDK.@n
+ This is a boolean, and enabled (set to 1) by default.@n
+ Set this to 0 in order to create non-GPL binaries.
+ (but then at your own discretion in regards to Steinberg licensing)@n
+ When set to 0, DPF will import the VST2 definitions from `"vst/aeffectx.h"` (not shipped with DPF).
+ */
+#define VESTIGE_HEADER 1
+
/** @} */
// -----------------------------------------------------------------------------------------------------------
diff --git a/dpf/distrho/DistrhoPlugin.hpp b/dpf/distrho/DistrhoPlugin.hpp
index 048fb93..e0b7ccb 100644
--- a/dpf/distrho/DistrhoPlugin.hpp
+++ b/dpf/distrho/DistrhoPlugin.hpp
@@ -40,7 +40,9 @@ START_NAMESPACE_DISTRHO
static const uint32_t kAudioPortIsCV = 0x1;
/**
- Audio port should be used as sidechan (LV2 only).
+ Audio port should be used as sidechan (LV2 and VST3 only).
+ This hint should not be used with CV style ports.
+ @note non-sidechain audio ports must exist in the plugin if this flag is set.
*/
static const uint32_t kAudioPortIsSidechain = 0x2;
@@ -632,6 +634,9 @@ struct MidiEvent {
/**
MIDI data.@n
If size > kDataSize, dataExt is used (otherwise null).
+
+ When dataExt is used, the event holder is responsible for
+ keeping the pointer valid during the entirety of the run function.
*/
uint8_t data[kDataSize];
const uint8_t* dataExt;
diff --git a/dpf/distrho/DistrhoUIMain.cpp b/dpf/distrho/DistrhoUIMain.cpp
index 0be2e2a..ef3aba2 100644
--- a/dpf/distrho/DistrhoUIMain.cpp
+++ b/dpf/distrho/DistrhoUIMain.cpp
@@ -27,7 +27,7 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST2)
// nothing
#elif defined(DISTRHO_PLUGIN_TARGET_VST3)
-// nothing
+# include "src/DistrhoUIVST3.cpp"
#else
# error unsupported format
#endif
diff --git a/dpf/distrho/extra/LeakDetector.hpp b/dpf/distrho/extra/LeakDetector.hpp
index 765e467..11ede47 100644
--- a/dpf/distrho/extra/LeakDetector.hpp
+++ b/dpf/distrho/extra/LeakDetector.hpp
@@ -23,7 +23,25 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------
// The following code was based from juce-core LeakDetector class
-// Copyright (C) 2013 Raw Material Software Ltd.
+
+/**
+ Copyright (C) 2013 Raw Material Software Ltd.
+
+ Permission is granted to use this software under the terms of the ISC license
+ http://www.isc.org/downloads/software-support-policy/isc-license/
+
+ 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 ISC DISCLAIMS ALL WARRANTIES WITH REGARD
+ TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS. IN NO EVENT SHALL ISC 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.
+*/
/** A good old-fashioned C macro concatenation helper.
This combines two items (which may themselves be macros) into a single string,
diff --git a/dpf/distrho/extra/ScopedPointer.hpp b/dpf/distrho/extra/ScopedPointer.hpp
index c756a1a..6349199 100644
--- a/dpf/distrho/extra/ScopedPointer.hpp
+++ b/dpf/distrho/extra/ScopedPointer.hpp
@@ -25,7 +25,25 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------
// The following code was based from juce-core ScopedPointer class
-// Copyright (C) 2013 Raw Material Software Ltd.
+
+/**
+ Copyright (C) 2013 Raw Material Software Ltd.
+
+ Permission is granted to use this software under the terms of the ISC license
+ http://www.isc.org/downloads/software-support-policy/isc-license/
+
+ 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 ISC DISCLAIMS ALL WARRANTIES WITH REGARD
+ TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS. IN NO EVENT SHALL ISC 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.
+*/
//==============================================================================
/**
diff --git a/dpf/distrho/extra/String.hpp b/dpf/distrho/extra/String.hpp
index 04a959b..88a7501 100644
--- a/dpf/distrho/extra/String.hpp
+++ b/dpf/distrho/extra/String.hpp
@@ -516,7 +516,7 @@ public:
*/
String& replace(const char before, const char after) noexcept
{
- DISTRHO_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this);
+ DISTRHO_SAFE_ASSERT_RETURN(before != '\0' /* && after != '\0' */, *this);
for (std::size_t i=0; i < fBufferLen; ++i)
{
diff --git a/dpf/distrho/src/DistrhoDefines.h b/dpf/distrho/src/DistrhoDefines.h
index afff900..281031c 100644
--- a/dpf/distrho/src/DistrhoDefines.h
+++ b/dpf/distrho/src/DistrhoDefines.h
@@ -109,7 +109,7 @@
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; }
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; }
-#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value); break; }
+#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); break; }
#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); continue; }
#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); return ret; }
@@ -117,7 +117,7 @@
#define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; }
#define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; }
-#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value); break; }
+#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); break; }
#define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); continue; }
#define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); return ret; }
@@ -199,6 +199,9 @@ private: \
# pragma warning(disable:4244) /* possible loss of data */
#endif
+/* Useful macros */
+#define ARRAY_SIZE(ARRAY) sizeof(ARRAY)/sizeof(ARRAY[0])
+
/* Useful typedefs */
typedef unsigned char uchar;
typedef unsigned short int ushort;
diff --git a/dpf/distrho/src/DistrhoPlugin.cpp b/dpf/distrho/src/DistrhoPlugin.cpp
index c517abf..693c491 100644
--- a/dpf/distrho/src/DistrhoPlugin.cpp
+++ b/dpf/distrho/src/DistrhoPlugin.cpp
@@ -29,7 +29,7 @@ bool d_lastCanRequestParameterValueChanges = false;
* Static fallback data, see DistrhoPluginInternal.hpp */
const String PluginExporter::sFallbackString;
-const AudioPort PluginExporter::sFallbackAudioPort;
+/* */ AudioPortWithBusId PluginExporter::sFallbackAudioPort;
const ParameterRanges PluginExporter::sFallbackRanges;
const ParameterEnumerationValues PluginExporter::sFallbackEnumValues;
const PortGroupWithId PluginExporter::sFallbackPortGroup;
@@ -41,7 +41,7 @@ Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCou
: pData(new PrivateData())
{
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- pData->audioPorts = new AudioPort[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS];
+ pData->audioPorts = new AudioPortWithBusId[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS];
#endif
#ifdef DPF_ABORT_ON_ERROR
diff --git a/dpf/distrho/src/DistrhoPluginChecks.h b/dpf/distrho/src/DistrhoPluginChecks.h
index b885dd7..dfcda68 100644
--- a/dpf/distrho/src/DistrhoPluginChecks.h
+++ b/dpf/distrho/src/DistrhoPluginChecks.h
@@ -173,7 +173,6 @@
# error DISTRHO_UI_IS_STANDALONE must not be defined
#endif
-
// -----------------------------------------------------------------------
#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED
diff --git a/dpf/distrho/src/DistrhoPluginInternal.hpp b/dpf/distrho/src/DistrhoPluginInternal.hpp
index 78066fd..753d3e0 100644
--- a/dpf/distrho/src/DistrhoPluginInternal.hpp
+++ b/dpf/distrho/src/DistrhoPluginInternal.hpp
@@ -44,6 +44,14 @@ typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, floa
// -----------------------------------------------------------------------
// Helpers
+struct AudioPortWithBusId : AudioPort {
+ uint32_t busId;
+
+ AudioPortWithBusId()
+ : AudioPort(),
+ busId(0) {}
+};
+
struct PortGroupWithId : PortGroup {
uint32_t groupId;
@@ -78,7 +86,7 @@ struct Plugin::PrivateData {
bool isProcessing;
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- AudioPort* audioPorts;
+ AudioPortWithBusId* audioPorts;
#endif
uint32_t parameterCount;
@@ -162,6 +170,15 @@ struct Plugin::PrivateData {
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
parameterOffset += 1;
# endif
+#endif
+
+#ifdef DISTRHO_PLUGIN_TARGET_VST3
+# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+ parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend
+# endif
+# if DISTRHO_PLUGIN_WANT_PROGRAMS
+ parameterOffset += 1;
+# endif
#endif
}
@@ -247,30 +264,26 @@ public:
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
- /* Verify that virtual functions are overriden if parameters, programs or states are in use.
+#if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__)
+ /* Run-time testing build.
+ * Verify that virtual functions are overriden if parameters, programs or states are in use.
* This does not work on all compilers, but we use it purely as informational check anyway. */
-#if defined(__GNUC__) && !defined(__clang__)
-# ifdef DPF_ABORT_ON_ERROR
-# define DPF_ABORT abort();
-# else
-# define DPF_ABORT
-# endif
if (fData->parameterCount != 0)
{
if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter)
{
d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`");
- DPF_ABORT
+ abort();
}
if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue)
{
d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`");
- DPF_ABORT
+ abort();
}
if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue)
{
d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`");
- DPF_ABORT
+ abort();
}
}
@@ -280,12 +293,12 @@ public:
if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName)
{
d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`");
- DPF_ABORT
+ abort();
}
if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram)
{
d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`");
- DPF_ABORT
+ abort();
}
}
# endif
@@ -296,13 +309,13 @@ public:
if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState)
{
d_stderr2("DPF warning: Plugins with state must implement `initState`");
- DPF_ABORT
+ abort();
}
if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState)
{
d_stderr2("DPF warning: Plugins with state must implement `setState`");
- DPF_ABORT
+ abort();
}
}
# endif
@@ -313,17 +326,15 @@ public:
if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState)
{
d_stderr2("DPF warning: Plugins with full state must implement `getState`");
- DPF_ABORT
+ abort();
}
}
else
{
d_stderr2("DPF warning: Plugins with full state must have at least 1 state");
- DPF_ABORT
+ abort();
}
# endif
-
-# undef DPF_ABORT
#endif
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
@@ -469,7 +480,7 @@ public:
#endif
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
- const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept
+ AudioPortWithBusId& getAudioPort(const bool input, const uint32_t index) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort);
@@ -488,6 +499,11 @@ public:
return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)];
}
+
+ uint32_t getAudioPortHints(const bool input, const uint32_t index) const noexcept
+ {
+ return getAudioPort(input, index).hints;
+ }
#endif
uint32_t getParameterCount() const noexcept
@@ -528,6 +544,11 @@ public:
return (getParameterHints(index) & kParameterIsOutput) != 0x0;
}
+ bool isParameterTrigger(const uint32_t index) const noexcept
+ {
+ return (getParameterHints(index) & kParameterIsTrigger) == kParameterIsTrigger;
+ }
+
bool isParameterOutputOrTrigger(const uint32_t index) const noexcept
{
const uint32_t hints = getParameterHints(index);
@@ -603,6 +624,14 @@ public:
return fData->parameters[index].groupId;
}
+ float getParameterDefault(const uint32_t index) const
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
+ DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);
+
+ return fData->parameters[index].ranges.def;
+ }
+
float getParameterValue(const uint32_t index) const
{
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
@@ -888,7 +917,7 @@ private:
// Static fallback data, see DistrhoPlugin.cpp
static const String sFallbackString;
- static const AudioPort sFallbackAudioPort;
+ static /* */ AudioPortWithBusId sFallbackAudioPort;
static const ParameterRanges sFallbackRanges;
static const ParameterEnumerationValues sFallbackEnumValues;
static const PortGroupWithId sFallbackPortGroup;
diff --git a/dpf/distrho/src/DistrhoPluginVST2.cpp b/dpf/distrho/src/DistrhoPluginVST2.cpp
index 784d89f..841dab4 100644
--- a/dpf/distrho/src/DistrhoPluginVST2.cpp
+++ b/dpf/distrho/src/DistrhoPluginVST2.cpp
@@ -261,7 +261,6 @@ public:
using namespace DGL_NAMESPACE;
- int special = 0;
switch (value)
{
// convert some VST special values to normal keys
@@ -304,37 +303,37 @@ public:
- kKeyCapsLock
- kKeyPrintScreen
*/
- case 40: special = kKeyF1; break;
- case 41: special = kKeyF2; break;
- case 42: special = kKeyF3; break;
- case 43: special = kKeyF4; break;
- case 44: special = kKeyF5; break;
- case 45: special = kKeyF6; break;
- case 46: special = kKeyF7; break;
- case 47: special = kKeyF8; break;
- case 48: special = kKeyF9; break;
- case 49: special = kKeyF10; break;
- case 50: special = kKeyF11; break;
- case 51: special = kKeyF12; break;
- case 11: special = kKeyLeft; break;
- case 12: special = kKeyUp; break;
- case 13: special = kKeyRight; break;
- case 14: special = kKeyDown; break;
- case 15: special = kKeyPageUp; break;
- case 16: special = kKeyPageDown; break;
- case 10: special = kKeyHome; break;
- case 9: special = kKeyEnd; break;
- case 21: special = kKeyInsert; break;
- case 54: special = kKeyShift; break;
- case 55: special = kKeyControl; break;
- case 56: special = kKeyAlt; break;
- case 58: special = kKeyMenu; break;
- case 52: special = kKeyNumLock; break;
- case 53: special = kKeyScrollLock; break;
- case 5: special = kKeyPause; break;
+ case 40: index = kKeyF1; break;
+ case 41: index = kKeyF2; break;
+ case 42: index = kKeyF3; break;
+ case 43: index = kKeyF4; break;
+ case 44: index = kKeyF5; break;
+ case 45: index = kKeyF6; break;
+ case 46: index = kKeyF7; break;
+ case 47: index = kKeyF8; break;
+ case 48: index = kKeyF9; break;
+ case 49: index = kKeyF10; break;
+ case 50: index = kKeyF11; break;
+ case 51: index = kKeyF12; break;
+ case 11: index = kKeyLeft; break;
+ case 12: index = kKeyUp; break;
+ case 13: index = kKeyRight; break;
+ case 14: index = kKeyDown; break;
+ case 15: index = kKeyPageUp; break;
+ case 16: index = kKeyPageDown; break;
+ case 10: index = kKeyHome; break;
+ case 9: index = kKeyEnd; break;
+ case 21: index = kKeyInsert; break;
+ case 54: index = kKeyShift; break;
+ case 55: index = kKeyControl; break;
+ case 56: index = kKeyAlt; break;
+ case 58: index = kKeyMenu; break;
+ case 52: index = kKeyNumLock; break;
+ case 53: index = kKeyScrollLock; break;
+ case 5: index = kKeyPause; break;
}
- switch (special)
+ switch (index)
{
case kKeyShift:
if (down)
@@ -356,15 +355,26 @@ public:
break;
}
- if (special != 0)
- {
- fUI.handlePluginSpecial(down, static_cast(special), fKeyboardModifiers);
- return 1;
- }
-
if (index > 0)
{
- fUI.handlePluginKeyboard(down, static_cast(index), fKeyboardModifiers);
+ // keyboard events must always be lowercase
+ bool needsShiftRevert = false;
+ if (index >= 'A' && index <= 'Z')
+ {
+ index += 'a' - 'A'; // A-Z -> a-z
+
+ if ((fKeyboardModifiers & kModifierShift) == 0x0)
+ {
+ needsShiftRevert = true;
+ fKeyboardModifiers |= kModifierShift;
+ }
+ }
+
+ fUI.handlePluginKeyboardVST2(down, static_cast(index), fKeyboardModifiers);
+
+ if (needsShiftRevert)
+ fKeyboardModifiers &= ~kModifierShift;
+
return 1;
}
@@ -1056,7 +1066,7 @@ public:
void vst_setParameter(const int32_t index, const float value)
{
- const uint32_t hints(fPlugin.getParameterHints(index));
+ const uint32_t hints = fPlugin.getParameterHints(index);
const ParameterRanges& ranges(fPlugin.getParameterRanges(index));
// TODO figure out how to detect kVstParameterUsesIntegerMinMax host support, and skip normalization
@@ -1104,7 +1114,7 @@ public:
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying);
fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0);
- // ticksPerBeat is not possible with VST
+ // ticksPerBeat is not possible with VST2
fTimePosition.bbt.ticksPerBeat = 1920.0;
if (vstTimeInfo->flags & kVstTempoValid)
diff --git a/dpf/distrho/src/DistrhoPluginVST3.cpp b/dpf/distrho/src/DistrhoPluginVST3.cpp
index a86c7d5..f8b3de2 100644
--- a/dpf/distrho/src/DistrhoPluginVST3.cpp
+++ b/dpf/distrho/src/DistrhoPluginVST3.cpp
@@ -17,280 +17,3691 @@
#include "DistrhoPluginInternal.hpp"
#include "../extra/ScopedPointer.hpp"
+#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
+# undef DISTRHO_PLUGIN_HAS_UI
+# define DISTRHO_PLUGIN_HAS_UI 0
+#endif
+
+#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
+# undef DISTRHO_PLUGIN_HAS_UI
+# define DISTRHO_PLUGIN_HAS_UI 0
+#endif
+
+#if DISTRHO_PLUGIN_HAS_UI
+# include "../extra/RingBuffer.hpp"
+#endif
+
#include "travesty/audio_processor.h"
#include "travesty/component.h"
#include "travesty/edit_controller.h"
#include "travesty/factory.h"
+#include "travesty/host.h"
+
+#ifdef DISTRHO_PROPER_CPP11_SUPPORT
+# include
+#else
+// quick and dirty std::atomic replacement for the things we need
+namespace std {
+ struct atomic_int {
+ volatile int value;
+ explicit atomic_int(volatile int v) noexcept : value(v) {}
+ int operator++() volatile noexcept { return __atomic_add_fetch(&value, 1, __ATOMIC_RELAXED); }
+ int operator--() volatile noexcept { return __atomic_sub_fetch(&value, 1, __ATOMIC_RELAXED); }
+ operator int() volatile noexcept { return __atomic_load_n(&value, __ATOMIC_RELAXED); }
+ };
+}
+#endif
+
+#include