diff --git a/Makefile b/Makefile index c8c9235..a108278 100644 --- a/Makefile +++ b/Makefile @@ -79,18 +79,26 @@ ifneq ($(HAVE_PROJECTM),true) ln -sf $(CURDIR)/plugins/ProM/projectM/presets/presets_* bin/ProM.lv2/resources/presets/ ifeq ($(MACOS),true) - # VST2 fonts + # CLAP + VST2 fonts + install -d bin/ProM.clap/Contents/Resources/fonts install -d bin/ProM.vst/Contents/Resources/fonts + ln -sf $(CURDIR)/plugins/ProM/projectM/fonts/*.ttf bin/ProM.clap/Contents/Resources/fonts/ ln -sf $(CURDIR)/plugins/ProM/projectM/fonts/*.ttf bin/ProM.vst/Contents/Resources/fonts/ - # VST2 presets + # CLAP + VST2 presets + install -d bin/ProM.clap/Contents/Resources/presets install -d bin/ProM.vst/Contents/Resources/presets + ln -sf $(CURDIR)/plugins/ProM/projectM/presets/presets_* bin/ProM.clap/Contents/Resources/presets/ ln -sf $(CURDIR)/plugins/ProM/projectM/presets/presets_* bin/ProM.vst/Contents/Resources/presets/ else - # VST2 fonts + # CLAP + VST2 fonts + install -d bin/ProM.clap/resources/fonts install -d bin/ProM.vst/resources/fonts + ln -sf $(CURDIR)/plugins/ProM/projectM/fonts/*.ttf bin/ProM.clap/resources/fonts/ ln -sf $(CURDIR)/plugins/ProM/projectM/fonts/*.ttf bin/ProM.vst/resources/fonts/ - # VST2 presets + # CLAP + VST2 presets + install -d bin/ProM.clap/resources/presets install -d bin/ProM.vst/resources/presets + ln -sf $(CURDIR)/plugins/ProM/projectM/presets/presets_* bin/ProM.clap/resources/presets/ ln -sf $(CURDIR)/plugins/ProM/projectM/presets/presets_* bin/ProM.vst/resources/presets/ endif @@ -160,6 +168,7 @@ install: install -d $(DESTDIR)$(PREFIX)/lib/lv2/ install -d $(DESTDIR)$(PREFIX)/lib/vst/ install -d $(DESTDIR)$(PREFIX)/lib/vst3/ + install -d $(DESTDIR)$(PREFIX)/lib/clap/ install -d $(DESTDIR)$(PREFIX)/bin/ install -m 644 bin/*-ladspa.* $(DESTDIR)$(PREFIX)/lib/ladspa/ @@ -176,6 +185,7 @@ ifeq ($(HAVE_OPENGL),true) cp -rL bin/*.vst $(DESTDIR)$(PREFIX)/lib/vst/ endif # HAVE_OPENGL cp -rL bin/*.vst3 $(DESTDIR)$(PREFIX)/lib/vst3/ + cp -rL bin/*.clap $(DESTDIR)$(PREFIX)/lib/clap/ install -m 755 bin/Kars$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/ install -m 755 bin/3BandEQ$(APP_EXT) $(DESTDIR)$(PREFIX)/bin/ diff --git a/dpf/LICENSING.md b/dpf/LICENSING.md index ad0a4c4..3759580 100644 --- a/dpf/LICENSING.md +++ b/dpf/LICENSING.md @@ -2,8 +2,7 @@ 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. +This file describes the licensing that applies to each individual plugin format as a way to make it clear what is possible and compatible. Regardless of target format, DPF itself needs to be mentioned in attribution. See the [LICENSE](LICENSE) file for copyright details. @@ -14,8 +13,9 @@ See the [LICENSE](LICENSE) file for copyright details. | 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 | +| VST2 | BSD-3 | Copyright attribution | 2020-2022 Michael Fabian 'Xaymar' Dirks | | VST3 | ISC | Copyright attribution | (none, only DPF files used) | +| CLAP | MIT | Copyright attribution | 2014-2022 Alexandre Bique | ### LADSPA and DSSI special note @@ -32,12 +32,9 @@ These formats are very limited and not much used anymore anyway, feel free to sk ### 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. +The DPF's VST2 implementation uses https://github.com/Xaymar/vst2sdk which is a liberally-licensed "clean room" untainted reverse engineered "SDK" for the VST2 interface. +Previously "vestige" was used, but was problematic due to it being GPLv2 licensed. +With the Xaymar's work, both open-source and proprietary plugins can be created from the same source, which helps in maintenance on DPF side. ### VST3 special note diff --git a/dpf/Makefile.base.mk b/dpf/Makefile.base.mk index 4c56955..eacd699 100644 --- a/dpf/Makefile.base.mk +++ b/dpf/Makefile.base.mk @@ -35,7 +35,11 @@ DPF_MAKEFILE_BASE_INCLUDED = true # --------------------------------------------------------------------------------------------------------------------- # Auto-detect target compiler if not defined +ifeq ($(shell echo '\#test' | grep -- '\#test'),\#test) TARGET_COMPILER = $(shell echo '\#ifdef __clang__\nclang\n\#else\ngcc\n\#endif' | $(CC) -E -P -x c - 2>/dev/null) +else +TARGET_COMPILER = $(shell echo '#ifdef __clang__\nclang\n#else\ngcc\n#endif' | $(CC) -E -P -x c - 2>/dev/null) +endif ifneq ($(CLANG),true) ifneq ($(GCC),true) @@ -119,6 +123,9 @@ ifneq (,$(filter aarch64%,$(TARGET_PROCESSOR))) CPU_ARM64 = true CPU_ARM_OR_ARM64 = true endif +ifneq (,$(filter riscv64%,$(TARGET_PROCESSOR))) +CPU_RISCV64 = true +endif ifeq ($(CPU_ARM),true) ifneq ($(CPU_ARM64),true) @@ -246,8 +253,7 @@ else ifeq ($(WASM),true) LINK_OPTS += -O3 LINK_OPTS += -Wl,--gc-sections else -LINK_OPTS += -Wl,-O1,--gc-sections -LINK_OPTS += -Wl,--as-needed +LINK_OPTS += -Wl,-O1,--as-needed,--gc-sections endif ifneq ($(SKIP_STRIPPING),true) @@ -658,6 +664,8 @@ features: $(call print_available,CPU_ARM_OR_ARM64) $(call print_available,CPU_I386) $(call print_available,CPU_I386_OR_X86_64) + $(call print_available,CPU_RISCV64) + $(call print_available,CPU_X86_64) @echo === Detected OS $(call print_available,BSD) $(call print_available,HAIKU) @@ -677,6 +685,7 @@ features: $(call print_available,HAVE_DBUS) $(call print_available,HAVE_CAIRO) $(call print_available,HAVE_DGL) + $(call print_available,HAVE_JACK) $(call print_available,HAVE_LIBLO) $(call print_available,HAVE_OPENGL) $(call print_available,HAVE_PULSEAUDIO) @@ -689,6 +698,53 @@ features: $(call print_available,HAVE_XEXT) $(call print_available,HAVE_XRANDR) +# --------------------------------------------------------------------------------------------------------------------- +# Extra rules for MOD Audio stuff + +# NOTE: note path must be absolute +MOD_WORKDIR ?= $(HOME)/mod-workdir +MOD_ENVIRONMENT = \ + AR=${1}/host/usr/bin/${2}-gcc-ar \ + CC=${1}/host/usr/bin/${2}-gcc \ + CPP=${1}/host/usr/bin/${2}-cpp \ + CXX=${1}/host/usr/bin/${2}-g++ \ + LD=${1}/host/usr/bin/${2}-ld \ + PKG_CONFIG=${1}/host/usr/bin/pkg-config \ + STRIP=${1}/host/usr/bin/${2}-strip \ + CFLAGS="-I${1}/staging/usr/include $(EXTRA_MOD_FLAGS)" \ + CPPFLAGS= \ + CXXFLAGS="-I${1}/staging/usr/include $(EXTRA_MOD_FLAGS)" \ + LDFLAGS="-L${1}/staging/usr/lib $(EXTRA_MOD_FLAGS)" \ + EXE_WRAPPER="qemu-${3}-static -L ${1}/target" \ + NOOPT=true + +modduo: + $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) + +modduox: + $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) + +moddwarf: + $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) + +modpush: + tar -C bin -cz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo + +ifneq (,$(findstring modduo-,$(MAKECMDGOALS))) +$(MAKECMDGOALS): + $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo,arm-mod-linux-gnueabihf,arm) $(subst modduo-,,$(MAKECMDGOALS)) +endif + +ifneq (,$(findstring modduox-,$(MAKECMDGOALS))) +$(MAKECMDGOALS): + $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox,aarch64-mod-linux-gnueabi,aarch64) $(subst modduox-,,$(MAKECMDGOALS)) +endif + +ifneq (,$(findstring moddwarf-,$(MAKECMDGOALS))) +$(MAKECMDGOALS): + $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) $(subst moddwarf-,,$(MAKECMDGOALS)) +endif + # --------------------------------------------------------------------------------------------------------------------- # Protect against multiple inclusion diff --git a/dpf/README.md b/dpf/README.md index 95003a9..998c0af 100644 --- a/dpf/README.md +++ b/dpf/README.md @@ -7,7 +7,7 @@ DPF is designed to make development of new plugins an easy and enjoyable task. The framework facilitates exporting various different plugin formats from the same code-base.
-DPF can build for LADSPA, DSSI, LV2, VST2 and VST3 formats.
+DPF can build for LADSPA, DSSI, LV2, VST2, VST3 and CLAP formats.
All current plugin format implementations are complete.
A JACK/Standalone mode is also available, allowing you to quickly test plugins.
@@ -44,6 +44,7 @@ Online help and discussion about DPF happens in the [kx.studio chat, DPF room](h - [DISTRHO ProM](https://github.com/DISTRHO/ProM) - [Dragonfly Reverb](https://michaelwillis.github.io/dragonfly-reverb) - [Fogpad-port](https://github.com/linuxmao-org/fogpad-port) + - [master_me](https://github.com/trummerschlunk/master_me) - [Ninjas2](https://github.com/rghvdberg/ninjas2) - [osamc-lv2-workshop](https://github.com/osamc-lv2-workshop/lv2-workshop) (simple plugins code examples) - [QuadraFuzz](https://github.com/jpcima/quadrafuzz) diff --git a/dpf/dgl/NanoVG.hpp b/dpf/dgl/NanoVG.hpp index ebafdb9..a1fab23 100644 --- a/dpf/dgl/NanoVG.hpp +++ b/dpf/dgl/NanoVG.hpp @@ -319,10 +319,9 @@ public: /** Constructor reusing a NanoVG context, used for subwidgets. + Context will not be deleted on class destructor. */ - /* - NanoVG(NanoWidget* groupWidget); - */ + explicit NanoVG(NVGcontext* context); /** Destructor. @@ -917,7 +916,17 @@ public: Constructor for a NanoSubWidget. @see CreateFlags */ - explicit NanoBaseWidget(Widget* parentGroupWidget, int flags = CREATE_ANTIALIAS); + explicit NanoBaseWidget(Widget* parentWidget, int flags = CREATE_ANTIALIAS); + + /** + Constructor for a NanoSubWidget reusing a parent subwidget nanovg context. + */ + explicit NanoBaseWidget(NanoBaseWidget* parentWidget); + + /** + Constructor for a NanoSubWidget reusing a parent top-level-widget nanovg context. + */ + explicit NanoBaseWidget(NanoBaseWidget* parentWidget); /** Constructor for a NanoTopLevelWidget. @@ -954,13 +963,7 @@ private: Widget display function. Implemented internally to wrap begin/endFrame() automatically. */ - inline void onDisplay() override - { - // NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? - NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); - onNanoDisplay(); - NanoVG::endFrame(); - } + void onDisplay() override; // these should not be used void beginFrame(uint,uint) {} @@ -969,6 +972,12 @@ private: void cancelFrame() {} void endFrame() {} + /** @internal */ + const bool fUsingParentContext; + void displayChildren(); + friend class NanoBaseWidget; + friend class NanoBaseWidget; + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoBaseWidget) }; diff --git a/dpf/dgl/Window.hpp b/dpf/dgl/Window.hpp index c32ba0f..9971988 100644 --- a/dpf/dgl/Window.hpp +++ b/dpf/dgl/Window.hpp @@ -541,7 +541,7 @@ private: uint height, double scaleFactor, bool resizable, - bool isVST3, + bool usesSizeRequest, bool doPostInit); DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window) diff --git a/dpf/dgl/src/NanoVG.cpp b/dpf/dgl/src/NanoVG.cpp index f5f0b9f..f3fd71d 100644 --- a/dpf/dgl/src/NanoVG.cpp +++ b/dpf/dgl/src/NanoVG.cpp @@ -327,6 +327,14 @@ NanoVG::NanoVG(int flags) DISTRHO_CUSTOM_SAFE_ASSERT("Failed to create NanoVG context, expect a black screen", fContext != nullptr); } +NanoVG::NanoVG(NVGcontext* const context) + : fContext(context), + fInFrame(false), + fIsSubWidget(true) +{ + DISTRHO_CUSTOM_SAFE_ASSERT("Failed to create NanoVG context, expect a black screen", fContext != nullptr); +} + NanoVG::~NanoVG() { DISTRHO_CUSTOM_SAFE_ASSERT("Destroying NanoVG context with still active frame", ! fInFrame); @@ -1057,17 +1065,73 @@ bool NanoVG::loadSharedResources() } #endif +// ----------------------------------------------------------------------- + +template +void NanoBaseWidget::displayChildren() +{ + std::list children(BaseWidget::getChildren()); + + for (std::list::iterator it = children.begin(); it != children.end(); ++it) + { + if (NanoSubWidget* const subwidget = dynamic_cast(*it)) + { + if (subwidget->fUsingParentContext && subwidget->isVisible()) + subwidget->onDisplay(); + } + } +} + // ----------------------------------------------------------------------- // NanoSubWidget template <> -NanoBaseWidget::NanoBaseWidget(Widget* const parent, int flags) - : SubWidget(parent), - NanoVG(flags) +NanoBaseWidget::NanoBaseWidget(Widget* const parentWidget, int flags) + : SubWidget(parentWidget), + NanoVG(flags), + fUsingParentContext(false) { setNeedsViewportScaling(); } +template <> +NanoBaseWidget::NanoBaseWidget(NanoSubWidget* const parentWidget) + : SubWidget(parentWidget), + NanoVG(parentWidget->getContext()), + fUsingParentContext(true) +{ + setSkipDrawing(); +} + +template <> +NanoBaseWidget::NanoBaseWidget(NanoTopLevelWidget* const parentWidget) + : SubWidget(parentWidget), + NanoVG(parentWidget->getContext()), + fUsingParentContext(true) +{ + setSkipDrawing(); +} + +template <> +inline void NanoBaseWidget::onDisplay() +{ + if (fUsingParentContext) + { + NanoVG::save(); + translate(SubWidget::getAbsoluteX(), SubWidget::getAbsoluteY()); + onNanoDisplay(); + NanoVG::restore(); + displayChildren(); + } + else + { + NanoVG::beginFrame(SubWidget::getWidth(), SubWidget::getHeight()); + onNanoDisplay(); + displayChildren(); + NanoVG::endFrame(); + } +} + template class NanoBaseWidget; // ----------------------------------------------------------------------- @@ -1076,7 +1140,17 @@ template class NanoBaseWidget; template <> NanoBaseWidget::NanoBaseWidget(Window& windowToMapTo, int flags) : TopLevelWidget(windowToMapTo), - NanoVG(flags) {} + NanoVG(flags), + fUsingParentContext(false) {} + +template <> +inline void NanoBaseWidget::onDisplay() +{ + NanoVG::beginFrame(TopLevelWidget::getWidth(), TopLevelWidget::getHeight()); + onNanoDisplay(); + displayChildren(); + NanoVG::endFrame(); +} template class NanoBaseWidget; @@ -1086,12 +1160,23 @@ template class NanoBaseWidget; template <> NanoBaseWidget::NanoBaseWidget(Application& app, int flags) : StandaloneWindow(app), - NanoVG(flags) {} + NanoVG(flags), + fUsingParentContext(false) {} template <> NanoBaseWidget::NanoBaseWidget(Application& app, Window& parentWindow, int flags) : StandaloneWindow(app, parentWindow), - NanoVG(flags) {} + NanoVG(flags), + fUsingParentContext(false) {} + +template <> +inline void NanoBaseWidget::onDisplay() +{ + NanoVG::beginFrame(Window::getWidth(), Window::getHeight()); + onNanoDisplay(); + displayChildren(); + NanoVG::endFrame(); +} template class NanoBaseWidget; diff --git a/dpf/dgl/src/WindowPrivateData.cpp b/dpf/dgl/src/WindowPrivateData.cpp index 6b32e0c..2105670 100644 --- a/dpf/dgl/src/WindowPrivateData.cpp +++ b/dpf/dgl/src/WindowPrivateData.cpp @@ -184,7 +184,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, Window::PrivateData::PrivateData(Application& a, Window* const s, const uintptr_t parentWindowHandle, const uint width, const uint height, - const double scale, const bool resizable, const bool isVST3) + const double scale, const bool resizable, const bool usesSizeRequest_) : app(a), appData(a.pData), self(s), @@ -193,7 +193,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, isClosed(parentWindowHandle == 0), isVisible(parentWindowHandle != 0 && view != nullptr), isEmbed(parentWindowHandle != 0), - usesSizeRequest(isVST3), + usesSizeRequest(usesSizeRequest_), scaleFactor(scale != 0.0 ? scale : getScaleFactorFromParent(view)), autoScaling(false), autoScaleFactor(1.0), diff --git a/dpf/distrho/DistrhoInfo.hpp b/dpf/distrho/DistrhoInfo.hpp index d1b8bda..050cbd3 100644 --- a/dpf/distrho/DistrhoInfo.hpp +++ b/dpf/distrho/DistrhoInfo.hpp @@ -31,7 +31,7 @@ START_NAMESPACE_DISTRHO It allows developers to create plugins with custom UIs using a simple C++ API.@n The framework facilitates exporting various different plugin formats from the same code-base. - DPF can build for LADSPA, DSSI, LV2, VST2 and VST3 formats.@n + DPF can build for LADSPA, DSSI, LV2, VST2, VST3 and CLAP formats.@n A JACK/Standalone mode is also available, allowing you to quickly test plugins. @section Macros @@ -341,11 +341,11 @@ START_NAMESPACE_DISTRHO switch (index) { - case 0; + case 0: parameter.name = "Gain Right"; parameter.symbol = "gainR"; break; - case 1; + case 1: parameter.name = "Gain Left"; parameter.symbol = "gainL"; break; @@ -373,12 +373,12 @@ START_NAMESPACE_DISTRHO { switch (index) { - case 0; + case 0: return fGainL; - case 1; + case 1: return fGainR; - default: - return 0.f; + default: + return 0.f; } } @@ -389,10 +389,10 @@ START_NAMESPACE_DISTRHO { switch (index) { - case 0; + case 0: fGainL = value; break; - case 1; + case 1: fGainR = value; break; } @@ -475,6 +475,8 @@ START_NAMESPACE_DISTRHO - @ref DISTRHO_PLUGIN_NUM_INPUTS - @ref DISTRHO_PLUGIN_NUM_OUTPUTS - @ref DISTRHO_PLUGIN_URI + + Additionally, @ref DISTRHO_PLUGIN_CLAP_ID is required if building CLAP plugins. @{ */ @@ -628,6 +630,8 @@ START_NAMESPACE_DISTRHO 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_DEFAULT_WIDTH 300 @@ -637,6 +641,8 @@ START_NAMESPACE_DISTRHO 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 300 @@ -810,6 +816,12 @@ START_NAMESPACE_DISTRHO */ #define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "stereo" +/** + The plugin id when exporting in CLAP format, in reverse URI form. + @note This macro is required when building CLAP plugins +*/ +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.effect" + /** @} */ /* ------------------------------------------------------------------------------------------------------------ @@ -864,15 +876,6 @@ START_NAMESPACE_DISTRHO */ #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/DistrhoUI.hpp b/dpf/distrho/DistrhoUI.hpp index 950077b..1b25748 100644 --- a/dpf/distrho/DistrhoUI.hpp +++ b/dpf/distrho/DistrhoUI.hpp @@ -51,6 +51,9 @@ typedef DGL_NAMESPACE::TopLevelWidget UIWidget; #if DISTRHO_UI_FILE_BROWSER # include "extra/FileBrowserDialog.hpp" #endif +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include +#endif START_NAMESPACE_DISTRHO diff --git a/dpf/distrho/src/DistrhoPlugin.cpp b/dpf/distrho/src/DistrhoPlugin.cpp index 03902fe..1128e9f 100644 --- a/dpf/distrho/src/DistrhoPlugin.cpp +++ b/dpf/distrho/src/DistrhoPlugin.cpp @@ -125,7 +125,7 @@ const TimePosition& Plugin::getTimePosition() const noexcept #endif #if DISTRHO_PLUGIN_WANT_LATENCY -void Plugin::setLatency(uint32_t frames) noexcept +void Plugin::setLatency(const uint32_t frames) noexcept { pData->latency = frames; } diff --git a/dpf/distrho/src/DistrhoPluginCLAP.cpp b/dpf/distrho/src/DistrhoPluginCLAP.cpp index 64847b7..2226b3f 100644 --- a/dpf/distrho/src/DistrhoPluginCLAP.cpp +++ b/dpf/distrho/src/DistrhoPluginCLAP.cpp @@ -17,24 +17,57 @@ #include "DistrhoPluginInternal.hpp" #include "extra/ScopedPointer.hpp" +#ifndef DISTRHO_PLUGIN_CLAP_ID +# error DISTRHO_PLUGIN_CLAP_ID undefined! +#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 "DistrhoUIInternal.hpp" -# include "extra/Mutex.hpp" +# include "../extra/Mutex.hpp" #endif +#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT +# include "../extra/RingBuffer.hpp" +#endif + +#include +#include + #include "clap/entry.h" #include "clap/plugin-factory.h" #include "clap/ext/audio-ports.h" +#include "clap/ext/latency.h" #include "clap/ext/gui.h" +#include "clap/ext/note-ports.h" #include "clap/ext/params.h" +#include "clap/ext/state.h" +#include "clap/ext/thread-check.h" +#include "clap/ext/timer-support.h" + +#if (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# define DPF_CLAP_USING_HOST_TIMER 0 +#else +# define DPF_CLAP_USING_HOST_TIMER 1 +#endif + +#ifndef DPF_CLAP_TIMER_INTERVAL +# define DPF_CLAP_TIMER_INTERVAL 16 /* ~60 fps */ +#endif START_NAMESPACE_DISTRHO // -------------------------------------------------------------------------------------------------------------------- +typedef std::map StringMap; + struct ClapEventQueue { - #if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_HAS_UI enum EventType { kEventGestureBegin, kEventGestureEnd, @@ -81,11 +114,22 @@ struct ClapEventQueue std::memcpy(&events[used++], &event, sizeof(Event)); } } fEventQueue; + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + SmallStackBuffer fNotesBuffer; #endif + #endif - #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_PROGRAMS + uint32_t fCurrentProgram; + #endif + + #if DISTRHO_PLUGIN_WANT_STATE + StringMap fStateMap; + #if DISTRHO_PLUGIN_HAS_UI virtual void setStateFromUI(const char* key, const char* value) = 0; #endif + #endif struct CachedParameters { uint numParams; @@ -93,7 +137,8 @@ struct ClapEventQueue float* values; CachedParameters() - : changed(nullptr), + : numParams(0), + changed(nullptr), values(nullptr) {} ~CachedParameters() @@ -116,6 +161,19 @@ struct ClapEventQueue } } fCachedParameters; + ClapEventQueue() + #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT + : fNotesBuffer(StackBuffer_INIT) + #endif + { + #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT && ! defined(DISTRHO_PROPER_CPP11_SUPPORT) + std::memset(&fNotesBuffer, 0, sizeof(fNotesBuffer)); + #endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS + fCurrentProgram = 0; + #endif + } + virtual ~ClapEventQueue() {} }; @@ -136,31 +194,54 @@ static constexpr const sendNoteFunc sendNoteCallback = nullptr; class ClapUI : public DGL_NAMESPACE::IdleCallback { public: - ClapUI(PluginExporter& plugin, ClapEventQueue* const eventQueue, const bool isFloating) + ClapUI(PluginExporter& plugin, + ClapEventQueue* const eventQueue, + const clap_host_t* const host, + const clap_host_gui_t* const hostGui, + #if DPF_CLAP_USING_HOST_TIMER + const clap_host_timer_support_t* const hostTimer, + #endif + const bool isFloating) : fPlugin(plugin), fPluinEventQueue(eventQueue), fEventQueue(eventQueue->fEventQueue), fCachedParameters(eventQueue->fCachedParameters), - fUI(), - fIsFloating(isFloating), + #if DISTRHO_PLUGIN_WANT_PROGRAMS + fCurrentProgram(eventQueue->fCurrentProgram), + #endif + #if DISTRHO_PLUGIN_WANT_STATE + fStateMap(eventQueue->fStateMap), + #endif + fHost(host), + fHostGui(hostGui), + #if DPF_CLAP_USING_HOST_TIMER + fTimerId(0), + fHostTimer(hostTimer), + #else fCallbackRegistered(false), + #endif + fIsFloating(isFloating), fScaleFactor(0.0), fParentWindow(0), fTransientWindow(0) { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + fNotesRingBuffer.setRingBuffer(&eventQueue->fNotesBuffer, false); + #endif } ~ClapUI() override { - if (fCallbackRegistered) - { - #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) - if (UIExporter* const ui = fUI.get()) - ui->removeIdleCallbackForVST3(this); - #endif - } + #if DPF_CLAP_USING_HOST_TIMER + if (fTimerId != 0) + fHostTimer->unregister_timer(fHost, fTimerId); + #else + if (fCallbackRegistered && fUI != nullptr) + fUI->removeIdleCallbackForNativeIdle(this); + #endif } + #ifndef DISTRHO_OS_MAC bool setScaleFactor(const double scaleFactor) { if (d_isEqual(fScaleFactor, scaleFactor)) @@ -173,6 +254,7 @@ public: return true; } + #endif bool getSize(uint32_t* const width, uint32_t* const height) const { @@ -180,21 +262,35 @@ public: { *width = ui->getWidth(); *height = ui->getHeight(); + #ifdef DISTRHO_OS_MAC + const double scaleFactor = ui->getScaleFactor(); + *width /= scaleFactor; + *height /= scaleFactor; + #endif return true; } + double scaleFactor = fScaleFactor; #if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT) *width = DISTRHO_UI_DEFAULT_WIDTH; *height = DISTRHO_UI_DEFAULT_HEIGHT; + if (d_isZero(scaleFactor)) + scaleFactor = 1.0; #else UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, - fPlugin.getInstancePointer(), fScaleFactor); + fPlugin.getInstancePointer(), scaleFactor); *width = tmpUI.getWidth(); *height = tmpUI.getHeight(); + scaleFactor = tmpUI.getScaleFactor(); tmpUI.quit(); #endif + #ifdef DISTRHO_OS_MAC + *width /= scaleFactor; + *height /= scaleFactor; + #endif + return true; } @@ -215,6 +311,12 @@ public: bool keepAspectRatio; fUI->getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); + #ifdef DISTRHO_OS_MAC + const double scaleFactor = fUI->getScaleFactor(); + minimumWidth /= scaleFactor; + minimumHeight /= scaleFactor; + #endif + hints->can_resize_horizontally = true; hints->can_resize_vertically = true; hints->preserve_aspect_ratio = keepAspectRatio; @@ -241,6 +343,12 @@ public: bool keepAspectRatio; fUI->getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio); + #ifdef DISTRHO_OS_MAC + const double scaleFactor = fUI->getScaleFactor(); + minimumWidth /= scaleFactor; + minimumHeight /= scaleFactor; + #endif + if (keepAspectRatio) { if (*width < 1) @@ -273,10 +381,15 @@ public: return false; } - bool setSizeFromHost(const uint32_t width, const uint32_t height) + bool setSizeFromHost(uint32_t width, uint32_t height) { if (UIExporter* const ui = fUI.get()) { + #ifdef DISTRHO_OS_MAC + const double scaleFactor = ui->getScaleFactor(); + width *= scaleFactor; + height *= scaleFactor; + #endif ui->setWindowSizeFromHost(width, height); return true; } @@ -291,10 +404,11 @@ public: fParentWindow = window->uptr; - /* - if (fUI != nullptr) + if (fUI == nullptr) + { createUI(); - */ + fHostGui->resize_hints_changed(fHost); + } return true; } @@ -326,15 +440,20 @@ public: bool show() { if (fUI == nullptr) + { createUI(); + fHostGui->resize_hints_changed(fHost); + } if (fIsFloating) fUI->setWindowVisible(true); - #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) - fUI->addIdleCallbackForVST3(this, 16); - #endif + #if DPF_CLAP_USING_HOST_TIMER + fHostTimer->register_timer(fHost, DPF_CLAP_TIMER_INTERVAL, &fTimerId); + #else fCallbackRegistered = true; + fUI->addIdleCallbackForNativeIdle(this, DPF_CLAP_TIMER_INTERVAL); + #endif return true; } @@ -343,10 +462,13 @@ public: if (UIExporter* const ui = fUI.get()) { ui->setWindowVisible(false); - #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) - ui->removeIdleCallbackForVST3(this); - #endif + #if DPF_CLAP_USING_HOST_TIMER + fHostTimer->unregister_timer(fHost, fTimerId); + fTimerId = 0; + #else + ui->removeIdleCallbackForNativeIdle(this); fCallbackRegistered = false; + #endif } return true; @@ -354,18 +476,81 @@ public: // ---------------------------------------------------------------------------------------------------------------- + void idleCallback() override + { + if (UIExporter* const ui = fUI.get()) + { + #if DPF_CLAP_USING_HOST_TIMER + ui->plugin_idle(); + #else + ui->idleFromNativeIdle(); + #endif + + for (uint i=0; iparameterChanged(i, fCachedParameters.values[i]); + } + } + } + } + + // ---------------------------------------------------------------------------------------------------------------- + + void setParameterValueFromPlugin(const uint index, const float value) + { + if (UIExporter* const ui = fUI.get()) + ui->parameterChanged(index, value); + } + + #if DISTRHO_PLUGIN_WANT_PROGRAMS + void setProgramFromPlugin(const uint index) + { + if (UIExporter* const ui = fUI.get()) + ui->programLoaded(index); + } + #endif + + #if DISTRHO_PLUGIN_WANT_STATE + void setStateFromPlugin(const char* const key, const char* const value) + { + if (UIExporter* const ui = fUI.get()) + ui->stateChanged(key, value); + } + #endif + + // ---------------------------------------------------------------------------------------------------------------- + private: // Plugin and UI PluginExporter& fPlugin; ClapEventQueue* const fPluinEventQueue; ClapEventQueue::Queue& fEventQueue; ClapEventQueue::CachedParameters& fCachedParameters; + #if DISTRHO_PLUGIN_WANT_PROGRAMS + uint32_t& fCurrentProgram; + #endif + #if DISTRHO_PLUGIN_WANT_STATE + StringMap& fStateMap; + #endif + const clap_host_t* const fHost; + const clap_host_gui_t* const fHostGui; + #if DPF_CLAP_USING_HOST_TIMER + clap_id fTimerId; + const clap_host_timer_support_t* const fHostTimer; + #else + bool fCallbackRegistered; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + RingBufferControl fNotesRingBuffer; + #endif ScopedPointer fUI; const bool fIsFloating; // Temporary data - bool fCallbackRegistered; double fScaleFactor; uintptr_t fParentWindow; uintptr_t fTransientWindow; @@ -390,6 +575,39 @@ private: fPlugin.getInstancePointer(), fScaleFactor); + #if DISTRHO_PLUGIN_WANT_PROGRAMS + fUI->programLoaded(fCurrentProgram); + #endif + + #if DISTRHO_PLUGIN_WANT_FULL_STATE + // Update current state from plugin side + for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) + { + const String& key = cit->first; + fStateMap[key] = fPlugin.getStateValue(key); + } + #endif + + #if DISTRHO_PLUGIN_WANT_STATE + // Set state + for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) + { + const String& key = cit->first; + const String& value = cit->second; + + // TODO skip DSP only states + + fUI->stateChanged(key, value); + } + #endif + + for (uint32_t i=0; iparameterChanged(i, value); + } + if (fIsFloating) { if (fWindowTitle.isNotEmpty()) @@ -400,32 +618,13 @@ private: } } - void idleCallback() override - { - #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) - if (UIExporter* const ui = fUI.get()) - { - ui->idleForVST3(); - - for (uint i=0; iparameterChanged(i, fCachedParameters.values[i]); - } - } - } - #endif - } - // ---------------------------------------------------------------------------------------------------------------- // DPF callbacks void editParameter(const uint32_t rindex, const bool started) const { const ClapEventQueue::Event ev = { - started ? ClapEventQueue::kEventGestureBegin : ClapEventQueue::kEventGestureBegin, + started ? ClapEventQueue::kEventGestureBegin : ClapEventQueue::kEventGestureEnd, rindex, 0.f }; fEventQueue.addEventFromUI(ev); @@ -450,8 +649,21 @@ private: static_cast(ptr)->setParameterValue(rindex, value); } - void setSizeFromPlugin(uint, uint) + void setSizeFromPlugin(const uint width, const uint height) { + DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); + + #ifdef DISTRHO_OS_MAC + const double scaleFactor = fUI->getScaleFactor(); + const uint hostWidth = width / scaleFactor; + const uint hostHeight = height / scaleFactor; + #else + const uint hostWidth = width; + const uint hostHeight = height; + #endif + + if (fHostGui->request_resize(fHost, hostWidth, hostHeight)) + fUI->setWindowSizeFromHost(width, height); } static void setSizeCallback(void* const ptr, const uint width, const uint height) @@ -474,6 +686,12 @@ private: #if DISTRHO_PLUGIN_WANT_MIDI_INPUT void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity) { + uint8_t midiData[3]; + midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel; + midiData[1] = note; + midiData[2] = velocity; + fNotesRingBuffer.writeCustomData(midiData, 3); + fNotesRingBuffer.commitWrite(); } static void sendNoteCallback(void* const ptr, const uint8_t channel, const uint8_t note, const uint8_t velocity) @@ -521,21 +739,59 @@ public: requestParameterValueChangeCallback, updateStateValueCallback), fHost(host), - fOutputEvents(nullptr) + fOutputEvents(nullptr), + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + fUsingCV(false), + #endif + #if DISTRHO_PLUGIN_WANT_LATENCY + fLatencyChanged(false), + fLastKnownLatency(0), + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + fMidiEventCount(0), + #endif + fHostExtensions(host) { fCachedParameters.setup(fPlugin.getParameterCount()); + + #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT + fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true); + #endif + + #if DISTRHO_PLUGIN_WANT_STATE + for (uint32_t i=0, count=fPlugin.getStateCount(); i(); + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + fillInBusInfoDetails(); + #endif + #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + fillInBusInfoPairs(); + #endif } // ---------------------------------------------------------------------------------------------------------------- // core + template + const T* getHostExtension(const char* const extensionId) const + { + return static_cast(fHost->get_extension(fHost, extensionId)); + } + bool init() { if (!clap_version_is_compatible(fHost->clap_version)) return false; - // TODO check host features - return true; + return fHostExtensions.init(); } void activate(const double sampleRate, const uint32_t maxFramesCount) @@ -548,10 +804,18 @@ public: void deactivate() { fPlugin.deactivate(); + #if DISTRHO_PLUGIN_WANT_LATENCY + checkForLatencyChanges(false, true); + reportLatencyChangeIfNeeded(); + #endif } bool process(const clap_process_t* const process) { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + fMidiEventCount = 0; + #endif + #if DISTRHO_PLUGIN_HAS_UI if (const clap_output_events_t* const outputEvents = process->out_events) { @@ -603,7 +867,8 @@ public: #if DISTRHO_PLUGIN_WANT_TIMEPOS if (const clap_event_transport_t* const transport = process->transport) { - fTimePosition.playing = transport->flags & CLAP_TRANSPORT_IS_PLAYING; + fTimePosition.playing = (transport->flags & CLAP_TRANSPORT_IS_PLAYING) != 0 && + (transport->flags & CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL) == 0; fTimePosition.frame = process->steady_time >= 0 ? process->steady_time : 0; @@ -615,27 +880,28 @@ public: // ticksPerBeat is not possible with CLAP fTimePosition.bbt.ticksPerBeat = 1920.0; - // TODO verify if this works or makes any sense if ((transport->flags & (CLAP_TRANSPORT_HAS_BEATS_TIMELINE|CLAP_TRANSPORT_HAS_TIME_SIGNATURE)) == (CLAP_TRANSPORT_HAS_BEATS_TIMELINE|CLAP_TRANSPORT_HAS_TIME_SIGNATURE)) { - const double ppqPos = std::abs(transport->song_pos_beats); - const int ppqPerBar = transport->tsig_num * 4 / transport->tsig_denom; - const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * transport->tsig_num; - const double rest = std::fmod(barBeats, 1.0); + if (transport->song_pos_beats >= 0) + { + const int64_t clapPos = std::abs(transport->song_pos_beats); + const int64_t clapBeats = clapPos >> 31; + const double clapRest = static_cast(clapPos & 0x7fffffff) / CLAP_BEATTIME_FACTOR; + + fTimePosition.bbt.bar = static_cast(clapBeats) / transport->tsig_num + 1; + fTimePosition.bbt.beat = static_cast(clapBeats % transport->tsig_num) + 1; + fTimePosition.bbt.tick = clapRest * fTimePosition.bbt.ticksPerBeat; + } + else + { + fTimePosition.bbt.bar = 1; + fTimePosition.bbt.beat = 1; + fTimePosition.bbt.tick = 0.0; + } fTimePosition.bbt.valid = true; - fTimePosition.bbt.bar = static_cast(ppqPos) / ppqPerBar + 1; - fTimePosition.bbt.beat = static_cast(barBeats - rest + 0.5) + 1; - fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat; fTimePosition.bbt.beatsPerBar = transport->tsig_num; fTimePosition.bbt.beatType = transport->tsig_denom; - - if (transport->song_pos_beats < 0.0) - { - --fTimePosition.bbt.bar; - fTimePosition.bbt.beat = transport->tsig_num - fTimePosition.bbt.beat + 1; - fTimePosition.bbt.tick = fTimePosition.bbt.ticksPerBeat - fTimePosition.bbt.tick - 1; - } } else { @@ -676,11 +942,20 @@ public: { const clap_event_header_t* const event = inputEvents->get(inputEvents, i); - // event->time switch (event->type) { case CLAP_EVENT_NOTE_ON: + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // BUG: even though we only report CLAP_NOTE_DIALECT_MIDI as supported, Bitwig sends us this anyway + addNoteEvent(static_cast(static_cast(event)), true); + #endif + break; case CLAP_EVENT_NOTE_OFF: + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + // BUG: even though we only report CLAP_NOTE_DIALECT_MIDI as supported, Bitwig sends us this anyway + addNoteEvent(static_cast(static_cast(event)), false); + #endif + break; case CLAP_EVENT_NOTE_CHOKE: case CLAP_EVENT_NOTE_END: case CLAP_EVENT_NOTE_EXPRESSION: @@ -695,6 +970,12 @@ public: case CLAP_EVENT_PARAM_GESTURE_END: case CLAP_EVENT_TRANSPORT: case CLAP_EVENT_MIDI: + DISTRHO_SAFE_ASSERT_UINT2_BREAK(event->size == sizeof(clap_event_midi_t), + event->size, sizeof(clap_event_midi_t)); + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + addMidiEvent(static_cast(static_cast(event))); + #endif + break; case CLAP_EVENT_MIDI_SYSEX: case CLAP_EVENT_MIDI2: break; @@ -703,27 +984,90 @@ public: } } + #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT + if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading()) + { + uint8_t midiData[3]; + const uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount-1].frame : 0; + + while (fNotesRingBuffer.isDataAvailableForReading()) + { + if (! fNotesRingBuffer.readCustomData(midiData, 3)) + break; + + MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]); + midiEvent.frame = frame; + midiEvent.size = 3; + std::memcpy(midiEvent.data, midiData, 3); + + if (fMidiEventCount == kMaxMidiEvents) + break; + } + } + #endif + if (const uint32_t frames = process->frames_count) { - // TODO multi-port bus stuff - DISTRHO_SAFE_ASSERT_UINT_RETURN(process->audio_inputs_count == 0 || process->audio_inputs_count == 1, - process->audio_inputs_count, false); - DISTRHO_SAFE_ASSERT_UINT_RETURN(process->audio_outputs_count == 0 || process->audio_outputs_count == 1, - process->audio_outputs_count, false); - - const float** inputs = process->audio_inputs != nullptr - ? const_cast(process->audio_inputs[0].data32) - : nullptr; - /**/ float** outputs = process->audio_outputs != nullptr - ? process->audio_outputs[0].data32 - : nullptr; + #if DISTRHO_PLUGIN_NUM_INPUTS != 0 + const float** const audioInputs = fAudioInputs; + + uint32_t in=0; + for (uint32_t i=0; iaudio_inputs_count; ++i) + { + const clap_audio_buffer_t& inputs(process->audio_inputs[i]); + DISTRHO_SAFE_ASSERT_CONTINUE(inputs.channel_count != 0); + + for (uint32_t j=0; j(inputs.data32[j]); + } + + if (fUsingCV) + { + for (; inaudio_inputs_count, false); + } + #else + constexpr const float** const audioInputs = nullptr; + #endif + + #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + float** const audioOutputs = fAudioOutputs; + + uint32_t out=0; + for (uint32_t i=0; iaudio_outputs_count; ++i) + { + const clap_audio_buffer_t& outputs(process->audio_outputs[i]); + DISTRHO_SAFE_ASSERT_CONTINUE(outputs.channel_count != 0); + + for (uint32_t j=0; jout_events; #if DISTRHO_PLUGIN_WANT_MIDI_INPUT - fPlugin.run(inputs, outputs, frames, nullptr, 0); + fPlugin.run(audioInputs, audioOutputs, frames, fMidiEvents, fMidiEventCount); #else - fPlugin.run(inputs, outputs, frames); + fPlugin.run(audioInputs, audioOutputs, frames); #endif // TODO set last frame @@ -732,9 +1076,20 @@ public: fOutputEvents = nullptr; } + #if DISTRHO_PLUGIN_WANT_LATENCY + checkForLatencyChanges(true, false); + #endif + return true; } + void onMainThread() + { + #if DISTRHO_PLUGIN_WANT_LATENCY + reportLatencyChangeIfNeeded(); + #endif + } + // ---------------------------------------------------------------------------------------------------------------- // parameters @@ -855,13 +1210,6 @@ public: return true; } - void setParameterValueFromEvent(const clap_event_param_value* const param) - { - fCachedParameters.values[param->param_id] = param->value; - fCachedParameters.changed[param->param_id] = true; - fPlugin.setParameterValue(param->param_id, param->value); - } - void flushParameters(const clap_input_events_t* const in, const clap_output_events_t* const out) { if (const uint32_t len = in != nullptr ? in->size(in) : 0) @@ -906,70 +1254,769 @@ public: } } } + + #if DISTRHO_PLUGIN_WANT_LATENCY + const bool active = fPlugin.isActive(); + checkForLatencyChanges(active, !active); + #endif } // ---------------------------------------------------------------------------------------------------------------- - // gui - #if DISTRHO_PLUGIN_HAS_UI - bool createUI(const bool isFloating) + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + void addNoteEvent(const clap_event_note_t* const event, const bool isOn) noexcept { - fUI = new ClapUI(fPlugin, this, isFloating); - return true; - } + DISTRHO_SAFE_ASSERT_UINT_RETURN(event->port_index == 0, event->port_index,); - void destroyUI() - { - fUI = nullptr; - } + if (fMidiEventCount == kMaxMidiEvents) + return; - ClapUI* getUI() const noexcept - { - return fUI.get(); + MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]); + midiEvent.frame = event->header.time; + midiEvent.size = 3; + midiEvent.data[0] = (isOn ? 0x90 : 0x80) | (event->channel & 0x0F); + midiEvent.data[1] = std::max(0, std::min(127, static_cast(event->key))); + midiEvent.data[2] = std::max(0, std::min(127, static_cast(event->velocity * 127 + 0.5))); } - #endif - #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_STATE - void setStateFromUI(const char* const key, const char* const value) override + void addMidiEvent(const clap_event_midi_t* const event) noexcept { - fPlugin.setState(key, value); - - // TODO check if we want to save this key, and save it - } - #endif + DISTRHO_SAFE_ASSERT_UINT_RETURN(event->port_index == 0, event->port_index,); - // ---------------------------------------------------------------------------------------------------------------- + if (fMidiEventCount == kMaxMidiEvents) + return; -private: - // Plugin and UI - PluginExporter fPlugin; - #if DISTRHO_PLUGIN_HAS_UI - ScopedPointer fUI; + MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]); + midiEvent.frame = event->header.time; + midiEvent.size = 3; + std::memcpy(midiEvent.data, event->data, 3); + } #endif - // CLAP stuff - const clap_host_t* const fHost; - const clap_output_events_t* fOutputEvents; - #if DISTRHO_PLUGIN_WANT_TIMEPOS - TimePosition fTimePosition; - #endif + void setParameterValueFromEvent(const clap_event_param_value* const event) + { + fCachedParameters.values[event->param_id] = event->value; + fCachedParameters.changed[event->param_id] = true; + fPlugin.setParameterValue(event->param_id, event->value); + } // ---------------------------------------------------------------------------------------------------------------- - // DPF callbacks + // audio ports - #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - bool writeMidi(const MidiEvent&) + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + template + uint32_t getAudioPortCount() const noexcept { - return true; + return (isInput ? fAudioInputBuses : fAudioOutputBuses).size(); } - static bool writeMidiCallback(void* const ptr, const MidiEvent& midiEvent) + template + bool getAudioPortInfo(const uint32_t index, clap_audio_port_info_t* const info) const noexcept { - return static_cast(ptr)->writeMidi(midiEvent); - } - #endif + const std::vector& busInfos(isInput ? fAudioInputBuses : fAudioOutputBuses); + DISTRHO_SAFE_ASSERT_RETURN(index < busInfos.size(), false); - #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST + const BusInfo& busInfo(busInfos[index]); + + info->id = busInfo.groupId; + DISTRHO_NAMESPACE::strncpy(info->name, busInfo.name, CLAP_NAME_SIZE); + + info->flags = busInfo.isMain ? CLAP_AUDIO_PORT_IS_MAIN : 0x0; + info->channel_count = busInfo.numChannels; + + switch (busInfo.groupId) + { + case kPortGroupMono: + info->port_type = CLAP_PORT_MONO; + break; + case kPortGroupStereo: + info->port_type = CLAP_PORT_STEREO; + break; + default: + info->port_type = nullptr; + break; + } + + info->in_place_pair = busInfo.hasPair ? busInfo.groupId : CLAP_INVALID_ID; + return true; + } + #endif + + // ---------------------------------------------------------------------------------------------------------------- + // latency + + #if DISTRHO_PLUGIN_WANT_LATENCY + uint32_t getLatency() const noexcept + { + return fPlugin.getLatency(); + } + + void checkForLatencyChanges(const bool isActive, const bool fromMainThread) + { + const uint32_t latency = fPlugin.getLatency(); + + if (fLastKnownLatency == latency) + return; + + fLastKnownLatency = latency; + + if (isActive) + { + fLatencyChanged = true; + fHost->request_restart(fHost); + } + else + { + // if this is main-thread we can report latency change directly + if (fromMainThread || (fHostExtensions.threadCheck != nullptr && fHostExtensions.threadCheck->is_main_thread(fHost))) + { + fLatencyChanged = false; + fHostExtensions.latency->changed(fHost); + } + // otherwise we need to request a main-thread callback + else + { + fLatencyChanged = true; + fHost->request_callback(fHost); + } + } + } + + // called from main thread + void reportLatencyChangeIfNeeded() + { + if (fLatencyChanged) + { + fLatencyChanged = false; + fHostExtensions.latency->changed(fHost); + } + } + #endif + + // ---------------------------------------------------------------------------------------------------------------- + // state + + bool stateSave(const clap_ostream_t* const stream) + { + const uint32_t paramCount = fPlugin.getParameterCount(); + #if DISTRHO_PLUGIN_WANT_STATE + const uint32_t stateCount = fPlugin.getStateCount(); + #else + const uint32_t stateCount = 0; + #endif + + if (stateCount == 0 && paramCount == 0) + { + char buffer = '\0'; + return stream->write(stream, &buffer, 1) == 1; + } + + #if DISTRHO_PLUGIN_WANT_FULL_STATE + // Update current state + for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) + { + const String& key = cit->first; + fStateMap[key] = fPlugin.getStateValue(key); + } + #endif + + String state; + + #if DISTRHO_PLUGIN_WANT_PROGRAMS + { + String tmpStr("__dpf_program__\xff"); + tmpStr += String(fCurrentProgram); + tmpStr += "\xff"; + + state += tmpStr; + } + #endif + + #if DISTRHO_PLUGIN_WANT_STATE + if (stateCount != 0) + { + state += "__dpf_state_begin__\xff"; + + for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) + { + const String& key = cit->first; + const String& value = cit->second; + + // join key and value + String tmpStr; + tmpStr = key; + tmpStr += "\xff"; + tmpStr += value; + tmpStr += "\xff"; + + state += tmpStr; + } + + state += "__dpf_state_end__\xff"; + } + #endif + + if (paramCount != 0) + { + state += "__dpf_parameters_begin__\xff"; + + for (uint32_t i=0; i(std::round(fPlugin.getParameterValue(i)))); + else + tmpStr += String(fPlugin.getParameterValue(i)); + tmpStr += "\xff"; + + state += tmpStr; + } + + state += "__dpf_parameters_end__\xff"; + } + + // terminator + state += "\xfe"; + + state.replace('\xff', '\0'); + + // now saving state, carefully until host written bytes matches full state size + const char* buffer = state.buffer(); + const int32_t size = static_cast(state.length())+1; + + for (int32_t wrtntotal = 0, wrtn; wrtntotal < size; wrtntotal += wrtn) + { + wrtn = stream->write(stream, buffer, size - wrtntotal); + DISTRHO_SAFE_ASSERT_INT_RETURN(wrtn > 0, wrtn, false); + } + + return true; + } + + bool stateLoad(const clap_istream_t* const stream) + { + #if DISTRHO_PLUGIN_HAS_UI + ClapUI* const ui = fUI.get(); + #endif + String key, value; + bool hasValue = false; + bool fillingKey = true; // if filling key or value + char queryingType = 'i'; // can be 'n', 's' or 'p' (none, states, parameters) + + char buffer[512], orig; + buffer[sizeof(buffer)-1] = '\xff'; + + for (int32_t terminated = 0, read; terminated == 0;) + { + read = stream->read(stream, buffer, sizeof(buffer)-1); + DISTRHO_SAFE_ASSERT_INT_RETURN(read >= 0, read, false); + + if (read == 0) + return true; + + for (int32_t i = 0; i < read; ++i) + { + // found terminator, stop here + if (buffer[i] == '\xfe') + { + terminated = 1; + break; + } + + // store character at read position + orig = buffer[read]; + + // place null character to create valid string + buffer[read] = '\0'; + + // append to temporary vars + if (fillingKey) + { + key += buffer + i; + } + else + { + value += buffer + i; + hasValue = true; + } + + // increase buffer offset by length of string + i += std::strlen(buffer + i); + + // restore read character + buffer[read] = orig; + + // if buffer offset points to null, we found the end of a string, lets check + if (buffer[i] == '\0') + { + // special keys + if (key == "__dpf_state_begin__") + { + DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'i' || queryingType == 'n', + queryingType, false); + queryingType = 's'; + key.clear(); + value.clear(); + hasValue = false; + continue; + } + if (key == "__dpf_state_end__") + { + DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 's', queryingType, false); + queryingType = 'n'; + key.clear(); + value.clear(); + hasValue = false; + continue; + } + if (key == "__dpf_parameters_begin__") + { + DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'i' || queryingType == 'n', + queryingType, false); + queryingType = 'p'; + key.clear(); + value.clear(); + hasValue = false; + continue; + } + if (key == "__dpf_parameters_end__") + { + DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'p', queryingType, false); + queryingType = 'x'; + key.clear(); + value.clear(); + hasValue = false; + continue; + } + + // no special key, swap between reading real key and value + fillingKey = !fillingKey; + + // if there is no value yet keep reading until we have one + if (! hasValue) + continue; + + if (key == "__dpf_program__") + { + DISTRHO_SAFE_ASSERT_INT_RETURN(queryingType == 'i', queryingType, false); + queryingType = 'n'; + + d_debug("found program '%s'", value.buffer()); + + #if DISTRHO_PLUGIN_WANT_PROGRAMS + const int program = std::atoi(value.buffer()); + DISTRHO_SAFE_ASSERT_CONTINUE(program >= 0); + + fCurrentProgram = static_cast(program); + fPlugin.loadProgram(fCurrentProgram); + + #if DISTRHO_PLUGIN_HAS_UI + if (ui != nullptr) + ui->setProgramFromPlugin(fCurrentProgram); + #endif + #endif + } + else if (queryingType == 's') + { + d_debug("found state '%s' '%s'", key.buffer(), value.buffer()); + + #if DISTRHO_PLUGIN_WANT_STATE + if (fPlugin.wantStateKey(key)) + { + fStateMap[key] = value; + fPlugin.setState(key, value); + + #if DISTRHO_PLUGIN_HAS_UI + if (ui != nullptr) + ui->setStateFromPlugin(key, value); + #endif + } + #endif + } + else if (queryingType == 'p') + { + d_debug("found parameter '%s' '%s'", key.buffer(), value.buffer()); + float fvalue; + + // find parameter with this symbol, and set its value + for (uint32_t j=0; jrescan(fHost, CLAP_PARAM_RESCAN_VALUES|CLAP_PARAM_RESCAN_TEXT); + + #if DISTRHO_PLUGIN_WANT_LATENCY + checkForLatencyChanges(fPlugin.isActive(), true); + reportLatencyChangeIfNeeded(); + #endif + + #if DISTRHO_PLUGIN_HAS_UI + if (ui != nullptr) + { + for (uint32_t i=0; isetParameterValueFromPlugin(i, fCachedParameters.values[i]); + } + } + #endif + + return true; + } + + // ---------------------------------------------------------------------------------------------------------------- + // gui + + #if DISTRHO_PLUGIN_HAS_UI + bool createUI(const bool isFloating) + { + const clap_host_gui_t* const hostGui = getHostExtension(CLAP_EXT_GUI); + DISTRHO_SAFE_ASSERT_RETURN(hostGui != nullptr, false); + + #if DPF_CLAP_USING_HOST_TIMER + const clap_host_timer_support_t* const hostTimer = getHostExtension(CLAP_EXT_TIMER_SUPPORT); + DISTRHO_SAFE_ASSERT_RETURN(hostTimer != nullptr, false); + #endif + + fUI = new ClapUI(fPlugin, this, fHost, hostGui, + #if DPF_CLAP_USING_HOST_TIMER + hostTimer, + #endif + isFloating); + return true; + } + + void destroyUI() + { + fUI = nullptr; + } + + ClapUI* getUI() const noexcept + { + return fUI.get(); + } + #endif + + #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_STATE + void setStateFromUI(const char* const key, const char* const value) override + { + fPlugin.setState(key, value); + + // check if we want to save this key + if (! fPlugin.wantStateKey(key)) + return; + + // check if key already exists + for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) + { + const String& dkey(it->first); + + if (dkey == key) + { + it->second = value; + return; + } + } + + d_stderr("Failed to find plugin state with key \"%s\"", key); + } + #endif + + // ---------------------------------------------------------------------------------------------------------------- + +private: + // Plugin and UI + PluginExporter fPlugin; + #if DISTRHO_PLUGIN_HAS_UI + ScopedPointer fUI; + #endif + + // CLAP stuff + const clap_host_t* const fHost; + const clap_output_events_t* fOutputEvents; + + #if DISTRHO_PLUGIN_NUM_INPUTS != 0 + const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; + #endif + #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + float* fAudioOutputs[DISTRHO_PLUGIN_NUM_OUTPUTS]; + #endif + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + bool fUsingCV; + #endif + #if DISTRHO_PLUGIN_WANT_LATENCY + bool fLatencyChanged; + uint32_t fLastKnownLatency; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + uint32_t fMidiEventCount; + MidiEvent fMidiEvents[kMaxMidiEvents]; + #if DISTRHO_PLUGIN_HAS_UI + RingBufferControl fNotesRingBuffer; + #endif + #endif + #if DISTRHO_PLUGIN_WANT_TIMEPOS + TimePosition fTimePosition; + #endif + + struct HostExtensions { + const clap_host_t* const host; + const clap_host_params_t* params; + #if DISTRHO_PLUGIN_WANT_LATENCY + const clap_host_latency_t* latency; + const clap_host_thread_check_t* threadCheck; + #endif + + HostExtensions(const clap_host_t* const host) + : host(host), + params(nullptr) + #if DISTRHO_PLUGIN_WANT_LATENCY + , latency(nullptr) + , threadCheck(nullptr) + #endif + {} + + bool init() + { + params = static_cast(host->get_extension(host, CLAP_EXT_PARAMS)); + #if DISTRHO_PLUGIN_WANT_LATENCY + DISTRHO_SAFE_ASSERT_RETURN(host->request_restart != nullptr, false); + DISTRHO_SAFE_ASSERT_RETURN(host->request_callback != nullptr, false); + latency = static_cast(host->get_extension(host, CLAP_EXT_LATENCY)); + threadCheck = static_cast(host->get_extension(host, CLAP_EXT_THREAD_CHECK)); + #endif + return true; + } + } fHostExtensions; + + // ---------------------------------------------------------------------------------------------------------------- + // helper functions for dealing with buses + + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + struct BusInfo { + char name[CLAP_NAME_SIZE]; + uint32_t numChannels; + bool hasPair; + bool isCV; + bool isMain; + uint32_t groupId; + }; + std::vector fAudioInputBuses, fAudioOutputBuses; + + template + void fillInBusInfoDetails() + { + constexpr const uint32_t numPorts = isInput ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS; + std::vector& busInfos(isInput ? fAudioInputBuses : fAudioOutputBuses); + + enum { + kPortTypeNull, + kPortTypeAudio, + kPortTypeSidechain, + kPortTypeCV, + kPortTypeGroup + } lastSeenPortType = kPortTypeNull; + uint32_t lastSeenGroupId = kPortGroupNone; + uint32_t nonGroupAudioId = 0; + uint32_t nonGroupSidechainId = 0x20000000; + + for (uint32_t i=0; i 3) + return true; + + const clap_event_midi clapEvent = { + { sizeof(clap_event_midi), midiEvent.frame, 0, CLAP_EVENT_MIDI, CLAP_EVENT_IS_LIVE }, + 0, { midiEvent.data[0], + static_cast(midiEvent.size >= 2 ? midiEvent.data[1] : 0), + static_cast(midiEvent.size >= 3 ? midiEvent.data[2] : 0) } + }; + return fOutputEvents->try_push(fOutputEvents, &clapEvent.header); + } + + static bool writeMidiCallback(void* const ptr, const MidiEvent& midiEvent) + { + return static_cast(ptr)->writeMidi(midiEvent); + } + #endif + + #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST bool requestParameterValueChange(uint32_t, float) { return true; @@ -1058,7 +2105,13 @@ static bool clap_gui_set_scale(const clap_plugin_t* const plugin, const double s PluginCLAP* const instance = static_cast(plugin->plugin_data); ClapUI* const gui = instance->getUI(); DISTRHO_SAFE_ASSERT_RETURN(gui != nullptr, false); + #ifndef DISTRHO_OS_MAC return gui->setScaleFactor(scale); + #else + return true; + // unused + (void)scale; + #endif } static bool clap_gui_get_size(const clap_plugin_t* const plugin, uint32_t* const width, uint32_t* const height) @@ -1158,88 +2211,129 @@ static const clap_plugin_gui_t clap_plugin_gui = { clap_gui_show, clap_gui_hide }; + +// -------------------------------------------------------------------------------------------------------------------- +// plugin timer + +#if DPF_CLAP_USING_HOST_TIMER +static void clap_plugin_on_timer(const clap_plugin_t* const plugin, clap_id) +{ + PluginCLAP* const instance = static_cast(plugin->plugin_data); + ClapUI* const gui = instance->getUI(); + DISTRHO_SAFE_ASSERT_RETURN(gui != nullptr,); + return gui->idleCallback(); +} + +static const clap_plugin_timer_support_t clap_timer = { + clap_plugin_on_timer +}; +#endif + #endif // DISTRHO_PLUGIN_HAS_UI // -------------------------------------------------------------------------------------------------------------------- // plugin audio ports -static uint32_t clap_plugin_audio_ports_count(const clap_plugin_t*, const bool is_input) +#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 +static uint32_t clap_plugin_audio_ports_count(const clap_plugin_t* const plugin, const bool is_input) { - return (is_input ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS) != 0 ? 1 : 0; + PluginCLAP* const instance = static_cast(plugin->plugin_data); + return is_input ? instance->getAudioPortCount() + : instance->getAudioPortCount(); } -static bool clap_plugin_audio_ports_get(const clap_plugin_t* /* const plugin */, +static bool clap_plugin_audio_ports_get(const clap_plugin_t* const plugin, const uint32_t index, const bool is_input, clap_audio_port_info_t* const info) { - const uint32_t maxPortCount = is_input ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS; - DISTRHO_SAFE_ASSERT_UINT2_RETURN(index < maxPortCount, index, maxPortCount, false); - - #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 - // PluginCLAP* const instance = static_cast(plugin->plugin_data); - - // TODO use groups - AudioPortWithBusId& audioPort(sPlugin->getAudioPort(is_input, index)); + PluginCLAP* const instance = static_cast(plugin->plugin_data); + return is_input ? instance->getAudioPortInfo(index, info) + : instance->getAudioPortInfo(index, info); +} - info->id = index; - DISTRHO_NAMESPACE::strncpy(info->name, audioPort.name, CLAP_NAME_SIZE); +static const clap_plugin_audio_ports_t clap_plugin_audio_ports = { + clap_plugin_audio_ports_count, + clap_plugin_audio_ports_get +}; +#endif - // TODO bus stuff - info->flags = CLAP_AUDIO_PORT_IS_MAIN; - info->channel_count = maxPortCount; +// -------------------------------------------------------------------------------------------------------------------- +// plugin note ports - // TODO CV - // info->port_type = audioPort.hints & kAudioPortIsCV ? CLAP_PORT_CV : nullptr; - info->port_type = nullptr; +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT+DISTRHO_PLUGIN_WANT_MIDI_OUTPUT != 0 +static uint32_t clap_plugin_note_ports_count(const clap_plugin_t*, const bool is_input) +{ + return (is_input ? DISTRHO_PLUGIN_WANT_MIDI_INPUT : DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) != 0 ? 1 : 0; +} - info->in_place_pair = DISTRHO_PLUGIN_NUM_INPUTS == DISTRHO_PLUGIN_NUM_OUTPUTS ? index : CLAP_INVALID_ID; +static bool clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, + const bool is_input, clap_note_port_info_t* const info) +{ + if (is_input) + { + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + info->id = 0; + info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; + info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; + std::strcpy(info->name, "Event/MIDI Input"); + return true; + #endif + } + else + { + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + info->id = 0; + info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; + info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; + std::strcpy(info->name, "Event/MIDI Output"); + return true; + #endif + } - return true; - #else return false; - #endif } -static const clap_plugin_audio_ports_t clap_plugin_audio_ports = { - clap_plugin_audio_ports_count, - clap_plugin_audio_ports_get +static const clap_plugin_note_ports_t clap_plugin_note_ports = { + clap_plugin_note_ports_count, + clap_plugin_note_ports_get }; +#endif // -------------------------------------------------------------------------------------------------------------------- // plugin parameters -static uint32_t clap_plugin_params_count(const clap_plugin_t* const plugin) +static CLAP_ABI uint32_t clap_plugin_params_count(const clap_plugin_t* const plugin) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->getParameterCount(); } -static bool clap_plugin_params_get_info(const clap_plugin_t* const plugin, const uint32_t index, clap_param_info_t* const info) +static CLAP_ABI bool clap_plugin_params_get_info(const clap_plugin_t* const plugin, const uint32_t index, clap_param_info_t* const info) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->getParameterInfo(index, info); } -static bool clap_plugin_params_get_value(const clap_plugin_t* const plugin, const clap_id param_id, double* const value) +static CLAP_ABI bool clap_plugin_params_get_value(const clap_plugin_t* const plugin, const clap_id param_id, double* const value) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->getParameterValue(param_id, value); } -static bool clap_plugin_params_value_to_text(const clap_plugin_t* plugin, const clap_id param_id, const double value, char* const display, const uint32_t size) +static CLAP_ABI bool clap_plugin_params_value_to_text(const clap_plugin_t* plugin, const clap_id param_id, const double value, char* const display, const uint32_t size) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->getParameterStringForValue(param_id, value, display, size); } -static bool clap_plugin_params_text_to_value(const clap_plugin_t* plugin, const clap_id param_id, const char* const display, double* const value) +static CLAP_ABI bool clap_plugin_params_text_to_value(const clap_plugin_t* plugin, const clap_id param_id, const char* const display, double* const value) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->getParameterValueForString(param_id, display, value); } -static void clap_plugin_params_flush(const clap_plugin_t* plugin, const clap_input_events_t* in, const clap_output_events_t* out) +static CLAP_ABI void clap_plugin_params_flush(const clap_plugin_t* plugin, const clap_input_events_t* in, const clap_output_events_t* out) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->flushParameters(in, out); @@ -1254,25 +2348,62 @@ static const clap_plugin_params_t clap_plugin_params = { clap_plugin_params_flush }; +#if DISTRHO_PLUGIN_WANT_LATENCY +// -------------------------------------------------------------------------------------------------------------------- +// plugin latency + +static CLAP_ABI uint32_t clap_plugin_latency_get(const clap_plugin_t* const plugin) +{ + PluginCLAP* const instance = static_cast(plugin->plugin_data); + return instance->getLatency(); +} + +static const clap_plugin_latency_t clap_plugin_latency = { + clap_plugin_latency_get +}; +#endif + +#if DISTRHO_PLUGIN_WANT_STATE +// -------------------------------------------------------------------------------------------------------------------- +// plugin state + +static CLAP_ABI bool clap_plugin_state_save(const clap_plugin_t* const plugin, const clap_ostream_t* const stream) +{ + PluginCLAP* const instance = static_cast(plugin->plugin_data); + return instance->stateSave(stream); +} + +static CLAP_ABI bool clap_plugin_state_load(const clap_plugin_t* const plugin, const clap_istream_t* const stream) +{ + PluginCLAP* const instance = static_cast(plugin->plugin_data); + return instance->stateLoad(stream); +} + +static const clap_plugin_state_t clap_plugin_state = { + clap_plugin_state_save, + clap_plugin_state_load +}; +#endif + // -------------------------------------------------------------------------------------------------------------------- // plugin -static bool clap_plugin_init(const clap_plugin_t* const plugin) +static CLAP_ABI bool clap_plugin_init(const clap_plugin_t* const plugin) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->init(); } -static void clap_plugin_destroy(const clap_plugin_t* const plugin) +static CLAP_ABI void clap_plugin_destroy(const clap_plugin_t* const plugin) { delete static_cast(plugin->plugin_data); std::free(const_cast(plugin)); } -static bool clap_plugin_activate(const clap_plugin_t* const plugin, - const double sample_rate, - uint32_t, - const uint32_t max_frames_count) +static CLAP_ABI bool clap_plugin_activate(const clap_plugin_t* const plugin, + const double sample_rate, + uint32_t, + const uint32_t max_frames_count) { d_nextBufferSize = max_frames_count; d_nextSampleRate = sample_rate; @@ -1282,50 +2413,69 @@ static bool clap_plugin_activate(const clap_plugin_t* const plugin, return true; } -static void clap_plugin_deactivate(const clap_plugin_t* const plugin) +static CLAP_ABI void clap_plugin_deactivate(const clap_plugin_t* const plugin) { PluginCLAP* const instance = static_cast(plugin->plugin_data); instance->deactivate(); } -static bool clap_plugin_start_processing(const clap_plugin_t*) +static CLAP_ABI bool clap_plugin_start_processing(const clap_plugin_t*) { // nothing to do return true; } -static void clap_plugin_stop_processing(const clap_plugin_t*) +static CLAP_ABI void clap_plugin_stop_processing(const clap_plugin_t*) { // nothing to do } -static void clap_plugin_reset(const clap_plugin_t*) +static CLAP_ABI void clap_plugin_reset(const clap_plugin_t*) { // nothing to do } -static clap_process_status clap_plugin_process(const clap_plugin_t* const plugin, const clap_process_t* const process) +static CLAP_ABI clap_process_status clap_plugin_process(const clap_plugin_t* const plugin, const clap_process_t* const process) { PluginCLAP* const instance = static_cast(plugin->plugin_data); return instance->process(process) ? CLAP_PROCESS_CONTINUE : CLAP_PROCESS_ERROR; } -static const void* clap_plugin_get_extension(const clap_plugin_t*, const char* const id) +static CLAP_ABI const void* clap_plugin_get_extension(const clap_plugin_t*, const char* const id) { - if (std::strcmp(id, CLAP_EXT_AUDIO_PORTS) == 0) - return &clap_plugin_audio_ports; if (std::strcmp(id, CLAP_EXT_PARAMS) == 0) return &clap_plugin_params; - #if DISTRHO_PLUGIN_HAS_UI + #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 + if (std::strcmp(id, CLAP_EXT_AUDIO_PORTS) == 0) + return &clap_plugin_audio_ports; + #endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT+DISTRHO_PLUGIN_WANT_MIDI_OUTPUT != 0 + if (std::strcmp(id, CLAP_EXT_NOTE_PORTS) == 0) + return &clap_plugin_note_ports; + #endif + #if DISTRHO_PLUGIN_WANT_LATENCY + if (std::strcmp(id, CLAP_EXT_LATENCY) == 0) + return &clap_plugin_latency; + #endif + #if DISTRHO_PLUGIN_WANT_STATE + if (std::strcmp(id, CLAP_EXT_STATE) == 0) + return &clap_plugin_state; + #endif + #if DISTRHO_PLUGIN_HAS_UI if (std::strcmp(id, CLAP_EXT_GUI) == 0) return &clap_plugin_gui; + #if DPF_CLAP_USING_HOST_TIMER + if (std::strcmp(id, CLAP_EXT_TIMER_SUPPORT) == 0) + return &clap_timer; #endif + #endif return nullptr; } -static void clap_plugin_on_main_thread(const clap_plugin_t*) +static void clap_plugin_on_main_thread(const clap_plugin_t* const plugin) { - // nothing to do + PluginCLAP* const instance = static_cast(plugin->plugin_data); + instance->onMainThread(); } // -------------------------------------------------------------------------------------------------------------------- @@ -1351,7 +2501,7 @@ static const clap_plugin_descriptor_t* clap_get_plugin_descriptor(const clap_plu static const clap_plugin_descriptor_t descriptor = { CLAP_VERSION, - sPlugin->getLabel(), + DISTRHO_PLUGIN_CLAP_ID, sPlugin->getName(), sPlugin->getMaker(), // TODO url diff --git a/dpf/distrho/src/DistrhoPluginJACK.cpp b/dpf/distrho/src/DistrhoPluginJACK.cpp index 2373fa7..94c9c30 100644 --- a/dpf/distrho/src/DistrhoPluginJACK.cpp +++ b/dpf/distrho/src/DistrhoPluginJACK.cpp @@ -49,6 +49,10 @@ # include #endif +#ifdef __SSE2_MATH__ +# include +#endif + #ifndef JACK_METADATA_ORDER # define JACK_METADATA_ORDER "http://jackaudio.org/metadata/order" #endif @@ -216,6 +220,7 @@ public: #endif } + jackbridge_set_thread_init_callback(fClient, jackThreadInitCallback, this); jackbridge_set_buffer_size_callback(fClient, jackBufferSizeCallback, this); jackbridge_set_sample_rate_callback(fClient, jackSampleRateCallback, this); jackbridge_set_process_callback(fClient, jackProcessCallback, this); @@ -687,6 +692,26 @@ private: #define thisPtr ((PluginJack*)ptr) + static void jackThreadInitCallback(void*) + { + #if defined(__SSE2_MATH__) + _mm_setcsr(_mm_getcsr() | 0x8040); + #elif defined(__aarch64__) + uint64_t c; + __asm__ __volatile__("mrs %0, fpcr \n" + "orr %0, %0, #0x1000000\n" + "msr fpcr, %0 \n" + "isb \n" + : "=r"(c) :: "memory"); + #elif defined(__arm__) + uint32_t c; + __asm__ __volatile__("vmrs %0, fpscr \n" + "orr %0, %0, #0x1000000\n" + "vmsr fpscr, %0 \n" + : "=r"(c) :: "memory"); + #endif + } + static int jackBufferSizeCallback(jack_nframes_t nframes, void* ptr) { thisPtr->jackBufferSize(nframes); @@ -841,7 +866,7 @@ bool runSelfTests() plugin.setSampleRate(48000); plugin.activate(); - float buffer[128]; + float buffer[128] = {}; const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS > 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1]; float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS > 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1]; for (int i=0; i #include #include #include -#if VESTIGE_HEADER -# include "vestige/vestige.h" -#define effFlagsProgramChunks (1 << 5) -#define effSetProgramName 4 -#define effGetParamLabel 6 -#define effGetParamDisplay 7 -#define effGetChunk 23 -#define effSetChunk 24 -#define effCanBeAutomated 26 -#define effGetProgramNameIndexed 29 -#define effGetPlugCategory 35 -#define effVendorSpecific 50 -#define effEditKeyDown 59 -#define effEditKeyUp 60 -#define kVstVersion 2400 -struct ERect { - int16_t top, left, bottom, right; -}; -#else -# include "vst/aeffectx.h" +#ifndef __cdecl +# define __cdecl #endif +#include "xaymar-vst2/vst.h" + START_NAMESPACE_DISTRHO -typedef std::map StringMap; +// -------------------------------------------------------------------------------------------------------------------- + +extern "C" { + +// define the midi stuff ourselves +typedef struct _VstMidiEvent { + int32_t type; + int32_t byteSize; + int32_t deltaFrames; + int32_t _ignore1[3]; + char midiData[4]; + char _ignore2[4]; +} VstMidiEvent; + +typedef union _VstEvent { + int32_t type; + VstMidiEvent midi; // type 1 +} VstEvent; + +typedef struct _HostVstEvents { + int numEvents; + void* reserved; + const VstEvent* events[]; +} HostVstEvents; + +typedef struct _PluginVstEvents { + int numEvents; + void* reserved; + VstEvent* events[1]; +} PluginVstEvents; + +// info from online documentation of VST provided by Steinberg +typedef struct _VstTimeInfo { + double samplePos; + double sampleRate; + double nanoSeconds; + double ppqPos; + double tempo; + double barStartPos; + double cycleStartPos; + double cycleEndPos; + int32_t timeSigNumerator; + int32_t timeSigDenominator; + int32_t smpteOffset; + int32_t smpteFrameRate; + int32_t samplesToNextClock; + int32_t flags; +} VstTimeInfo; -static constexpr const int kVstMidiEventSize = static_cast(sizeof(VstMidiEvent)); +} + +// -------------------------------------------------------------------------------------------------------------------- + +typedef std::map StringMap; #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT static const writeMidiFunc writeMidiCallback = nullptr; @@ -74,7 +100,7 @@ static const writeMidiFunc writeMidiCallback = nullptr; static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; #endif -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- struct ParameterAndNotesHelper { @@ -122,7 +148,7 @@ struct ParameterAndNotesHelper }; #if DISTRHO_PLUGIN_HAS_UI -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT static const sendNoteFunc sendNoteCallback = nullptr; @@ -134,8 +160,8 @@ static const setStateFunc setStateCallback = nullptr; class UIVst { public: - UIVst(const audioMasterCallback audioMaster, - AEffect* const effect, + UIVst(const vst_host_callback audioMaster, + vst_effect* const effect, ParameterAndNotesHelper* const uiHelper, PluginExporter* const plugin, const intptr_t winId, const float scaleFactor) @@ -209,12 +235,12 @@ public: // ------------------------------------------------------------------- // functions called from the plugin side, may block -# if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE void setStateFromPlugin(const char* const key, const char* const value) { fUI.stateChanged(key, value); } -# endif + #endif # if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI int handlePluginKeyEvent(const bool down, const int32_t index, const intptr_t value) @@ -257,7 +283,7 @@ public: // ------------------------------------------------------------------- protected: - inline intptr_t hostCallback(const int32_t opcode, + inline intptr_t hostCallback(const VST_HOST_OPCODE opcode, const int32_t index = 0, const intptr_t value = 0, void* const ptr = nullptr, @@ -268,7 +294,7 @@ protected: void editParameter(const uint32_t index, const bool started) const { - hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index); + hostCallback(started ? VST_HOST_OPCODE_2B : VST_HOST_OPCODE_2C, index); } void setParameterValue(const uint32_t index, const float realValue) @@ -277,7 +303,7 @@ protected: const float perValue(ranges.getNormalizedValue(realValue)); fPlugin->setParameterValue(index, realValue); - hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); + hostCallback(VST_HOST_OPCODE_00, index, 0, nullptr, perValue); } void setSize(uint width, uint height) @@ -287,7 +313,7 @@ protected: width /= scaleFactor; height /= scaleFactor; # endif - hostCallback(audioMasterSizeWindow, width, height); + hostCallback(VST_HOST_OPCODE_0F, width, height); } # if DISTRHO_PLUGIN_WANT_MIDI_INPUT @@ -311,8 +337,8 @@ protected: private: // Vst stuff - const audioMasterCallback fAudioMaster; - AEffect* const fEffect; + const vst_host_callback fAudioMaster; + vst_effect* const fEffect; ParameterAndNotesHelper* const fUiHelper; PluginExporter* const fPlugin; @@ -363,12 +389,12 @@ private: }; #endif // DISTRHO_PLUGIN_HAS_UI -// ----------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- class PluginVst : public ParameterAndNotesHelper { public: - PluginVst(const audioMasterCallback audioMaster, AEffect* const effect) + PluginVst(const vst_host_callback audioMaster, vst_effect* const effect) : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, nullptr), fAudioMaster(audioMaster), fEffect(effect) @@ -452,10 +478,10 @@ public: switch (opcode) { - case effGetProgram: + case VST_EFFECT_OPCODE_03: // get program return 0; - case effSetProgramName: + case VST_EFFECT_OPCODE_04: // set program name if (char* const programName = (char*)ptr) { strncpy(fProgramName, programName, 32); @@ -463,7 +489,7 @@ public: } break; - case effGetProgramName: + case VST_EFFECT_OPCODE_05: // get program name if (char* const programName = (char*)ptr) { strncpy(programName, fProgramName, 24); @@ -471,7 +497,7 @@ public: } break; - case effGetProgramNameIndexed: + case VST_EFFECT_OPCODE_1D: // get program name indexed if (char* const programName = (char*)ptr) { strncpy(programName, fProgramName, 24); @@ -479,7 +505,7 @@ public: } break; - case effGetParamDisplay: + case VST_EFFECT_OPCODE_PARAM_GETVALUE: if (ptr != nullptr && index < static_cast(fPlugin.getParameterCount())) { const uint32_t hints = fPlugin.getParameterHints(index); @@ -517,7 +543,7 @@ public: } break; - case effSetSampleRate: + case VST_EFFECT_OPCODE_SET_SAMPLE_RATE: fPlugin.setSampleRate(opt, true); #if DISTRHO_PLUGIN_HAS_UI @@ -526,26 +552,26 @@ public: #endif break; - case effSetBlockSize: + case VST_EFFECT_OPCODE_SET_BLOCK_SIZE: fPlugin.setBufferSize(value, true); break; - case effMainsChanged: + case VST_EFFECT_OPCODE_SUSPEND: if (value != 0) { #if DISTRHO_PLUGIN_WANT_MIDI_INPUT fMidiEventCount = 0; // tell host we want MIDI events - hostCallback(audioMasterWantMidi); + hostCallback(VST_HOST_OPCODE_06); #endif // deactivate for possible changes fPlugin.deactivateIfNeeded(); // check if something changed - const uint32_t bufferSize = static_cast(hostCallback(audioMasterGetBlockSize)); - const double sampleRate = static_cast(hostCallback(audioMasterGetSampleRate)); + const uint32_t bufferSize = static_cast(hostCallback(VST_HOST_OPCODE_11)); + const double sampleRate = static_cast(hostCallback(VST_HOST_OPCODE_10)); if (bufferSize != 0) fPlugin.setBufferSize(bufferSize, true); @@ -562,7 +588,7 @@ public: break; #if DISTRHO_PLUGIN_HAS_UI - case effEditGetRect: + case VST_EFFECT_OPCODE_WINDOW_GETRECT: if (fVstUI != nullptr) { fVstRect.right = fVstUI->getWidth(); @@ -595,12 +621,13 @@ public: fVstRect.bottom /= scaleFactor; #endif } - *(ERect**)ptr = &fVstRect; + *(vst_rect**)ptr = &fVstRect; return 1; - case effEditOpen: - delete fVstUI; // hosts which don't pair effEditOpen/effEditClose calls (Minihost Modular) + case VST_EFFECT_OPCODE_WINDOW_CREATE: + delete fVstUI; // for hosts which don't pair create/destroy calls (Minihost Modular) fVstUI = nullptr; + { # if DISTRHO_OS_MAC if (! fUsingNsView) @@ -611,25 +638,28 @@ public: # endif fVstUI = new UIVst(fAudioMaster, fEffect, this, &fPlugin, (intptr_t)ptr, fLastScaleFactor); -# if DISTRHO_PLUGIN_WANT_FULL_STATE + #if DISTRHO_PLUGIN_WANT_FULL_STATE // Update current state from plugin side for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; fStateMap[key] = fPlugin.getStateValue(key); } -# endif + #endif -# if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE // Set state for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& key = cit->first; const String& value = cit->second; + // TODO skip DSP only states + fVstUI->setStateFromPlugin(key, value); } -# endif + #endif + for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) setParameterValueFromPlugin(i, fPlugin.getParameterValue(i)); @@ -638,7 +668,7 @@ public: } break; - case effEditClose: + case VST_EFFECT_OPCODE_WINDOW_DESTROY: if (fVstUI != nullptr) { delete fVstUI; @@ -647,18 +677,18 @@ public: } break; - case effEditIdle: + case VST_EFFECT_OPCODE_13: // window idle if (fVstUI != nullptr) fVstUI->idle(); break; # if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI - case effEditKeyDown: + case VST_EFFECT_OPCODE_3B: // key down if (fVstUI != nullptr) return fVstUI->handlePluginKeyEvent(true, index, value); break; - case effEditKeyUp: + case VST_EFFECT_OPCODE_3C: // key up if (fVstUI != nullptr) return fVstUI->handlePluginKeyEvent(false, index, value); break; @@ -666,7 +696,7 @@ public: #endif // DISTRHO_PLUGIN_HAS_UI #if DISTRHO_PLUGIN_WANT_STATE - case effGetChunk: + case VST_EFFECT_OPCODE_17: // get chunk { if (ptr == nullptr) return 0; @@ -753,7 +783,7 @@ public: return ret; } - case effSetChunk: + case VST_EFFECT_OPCODE_18: // set chunk { if (value <= 1 || ptr == nullptr) return 0; @@ -777,7 +807,10 @@ public: # if DISTRHO_PLUGIN_HAS_UI if (fVstUI != nullptr) + { + // TODO skip DSP only states fVstUI->setStateFromPlugin(key, value); + } # endif // get next key @@ -834,39 +867,41 @@ public: #endif // DISTRHO_PLUGIN_WANT_STATE #if DISTRHO_PLUGIN_WANT_MIDI_INPUT - case effProcessEvents: + case VST_EFFECT_OPCODE_19: // process events if (! fPlugin.isActive()) { // host has not activated the plugin yet, nasty! - vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); + vst_dispatcher(VST_EFFECT_OPCODE_SUSPEND, 0, 1, nullptr, 0.0f); } - if (const VstEvents* const events = (const VstEvents*)ptr) + if (const HostVstEvents* const events = (const HostVstEvents*)ptr) { if (events->numEvents == 0) break; for (int i=0, count=events->numEvents; i < count; ++i) { - const VstMidiEvent* const vstMidiEvent((const VstMidiEvent*)events->events[i]); + const VstEvent* const vstEvent = events->events[i]; - if (vstMidiEvent == nullptr) + if (vstEvent == nullptr) break; - if (vstMidiEvent->type != kVstMidiType) + if (vstEvent->type != 1) continue; if (fMidiEventCount >= kMaxMidiEvents) break; + const VstMidiEvent& vstMidiEvent(events->events[i]->midi); + MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]); - midiEvent.frame = vstMidiEvent->deltaFrames; + midiEvent.frame = vstMidiEvent.deltaFrames; midiEvent.size = 3; - std::memcpy(midiEvent.data, vstMidiEvent->midiData, sizeof(uint8_t)*3); + std::memcpy(midiEvent.data, vstMidiEvent.midiData, sizeof(uint8_t)*3); } } break; #endif - case effCanBeAutomated: + case VST_EFFECT_OPCODE_PARAM_ISAUTOMATABLE: if (index < static_cast(fPlugin.getParameterCount())) { const uint32_t hints(fPlugin.getParameterHints(index)); @@ -877,7 +912,7 @@ public: } break; - case effCanDo: + case VST_EFFECT_OPCODE_SUPPORTS: if (const char* const canDo = (const char*)ptr) { #if DISTRHO_OS_MAC && DISTRHO_PLUGIN_HAS_UI @@ -916,9 +951,9 @@ public: } break; - case effVendorSpecific: + case VST_EFFECT_OPCODE_CUSTOM: #if DISTRHO_PLUGIN_HAS_UI && !defined(DISTRHO_OS_MAC) - if (index == CCONST('P', 'r', 'e', 'S') && value == CCONST('A', 'e', 'C', 's')) + if (index == d_cconst('P', 'r', 'e', 'S') && value == d_cconst('A', 'e', 'C', 's')) { if (d_isEqual(fLastScaleFactor, opt)) break; @@ -940,13 +975,13 @@ public: return 0; } - float vst_getParameter(const int32_t index) + float vst_getParameter(const uint32_t index) { const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); return ranges.getNormalizedValue(fPlugin.getParameterValue(index)); } - void vst_setParameter(const int32_t index, const float value) + void vst_setParameter(const uint32_t index, const float value) { const uint32_t hints = fPlugin.getParameterHints(index); const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); @@ -978,7 +1013,7 @@ public: if (! fPlugin.isActive()) { // host has not activated the plugin yet, nasty! - vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); + vst_dispatcher(VST_EFFECT_OPCODE_SUSPEND, 0, 1, nullptr, 0.0f); } if (sampleFrames <= 0) @@ -988,22 +1023,22 @@ public: } #if DISTRHO_PLUGIN_WANT_TIMEPOS - static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstTimeSigValid); + static constexpr const int kWantVstTimeFlags = 0x2602; - if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(audioMasterGetTime, 0, kWantVstTimeFlags)) + if (const VstTimeInfo* const vstTimeInfo = (const VstTimeInfo*)hostCallback(VST_HOST_OPCODE_07, 0, kWantVstTimeFlags)) { fTimePosition.frame = vstTimeInfo->samplePos; - fTimePosition.playing = vstTimeInfo->flags & kVstTransportPlaying; + fTimePosition.playing = vstTimeInfo->flags & 0x2; // ticksPerBeat is not possible with VST2 fTimePosition.bbt.ticksPerBeat = 1920.0; - if (vstTimeInfo->flags & kVstTempoValid) + if (vstTimeInfo->flags & 0x400) fTimePosition.bbt.beatsPerMinute = vstTimeInfo->tempo; else fTimePosition.bbt.beatsPerMinute = 120.0; - if ((vstTimeInfo->flags & (kVstPpqPosValid|kVstTimeSigValid)) == (kVstPpqPosValid|kVstTimeSigValid)) + if ((vstTimeInfo->flags & 0x2200) == 0x2200) { const double ppqPos = std::abs(vstTimeInfo->ppqPos); const int ppqPerBar = vstTimeInfo->timeSigNumerator * 4 / vstTimeInfo->timeSigDenominator; @@ -1083,8 +1118,8 @@ private: PluginExporter fPlugin; // VST stuff - const audioMasterCallback fAudioMaster; - AEffect* const fEffect; + const vst_host_callback fAudioMaster; + vst_effect* const fEffect; // Temporary data char fProgramName[32]; @@ -1100,9 +1135,9 @@ private: // UI stuff #if DISTRHO_PLUGIN_HAS_UI - UIVst* fVstUI; - ERect fVstRect; - float fLastScaleFactor; + UIVst* fVstUI; + vst_rect fVstRect; + float fLastScaleFactor; # if DISTRHO_OS_MAC bool fUsingNsView; # endif @@ -1119,7 +1154,7 @@ private: // ------------------------------------------------------------------- // host callback - intptr_t hostCallback(const int32_t opcode, + intptr_t hostCallback(const VST_HOST_OPCODE opcode, const int32_t index = 0, const intptr_t value = 0, void* const ptr = nullptr, @@ -1177,8 +1212,12 @@ private: } const ParameterRanges& ranges(fPlugin.getParameterRanges(i)); - hostCallback(audioMasterAutomate, i, 0, nullptr, ranges.getNormalizedValue(curValue)); + hostCallback(VST_HOST_OPCODE_00, i, 0, nullptr, ranges.getNormalizedValue(curValue)); } + + #if DISTRHO_PLUGIN_WANT_LATENCY + fEffect->delay = fPlugin.getLatency(); + #endif } #if DISTRHO_PLUGIN_HAS_UI @@ -1192,7 +1231,7 @@ private: #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST bool requestParameterValueChange(const uint32_t index, const float value) { - hostCallback(audioMasterAutomate, index, 0, nullptr, value); + hostCallback(VST_HOST_OPCODE_00, index, 0, nullptr, value); return true; } @@ -1208,23 +1247,20 @@ private: if (midiEvent.size > 4) return true; - VstEvents vstEvents; - std::memset(&vstEvents, 0, sizeof(VstEvents)); - - VstMidiEvent vstMidiEvent; - std::memset(&vstMidiEvent, 0, sizeof(VstMidiEvent)); + PluginVstEvents vstEvents = {}; + VstMidiEvent vstMidiEvent = {}; vstEvents.numEvents = 1; vstEvents.events[0] = (VstEvent*)&vstMidiEvent; - vstMidiEvent.type = kVstMidiType; - vstMidiEvent.byteSize = kVstMidiEventSize; + vstMidiEvent.type = 1; + vstMidiEvent.byteSize = static_cast(sizeof(VstMidiEvent));; vstMidiEvent.deltaFrames = midiEvent.frame; for (uint8_t i=0; iobject != nullptr -#define validPlugin effect != nullptr && effect->object != nullptr && ((VstObject*)effect->object)->plugin != nullptr -#define vstObjectPtr (VstObject*)effect->object -#define pluginPtr (vstObjectPtr)->plugin - static ScopedPointer sPlugin; -static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) -{ - // first internal init - const bool doInternalInit = (opcode == -1729 && index == 0xdead && value == 0xf00d); +static struct Cleanup { + std::vector effects; - if (doInternalInit || opcode == effOpen) + ~Cleanup() { - if (sPlugin == nullptr) + for (std::vector::iterator it = effects.begin(), end = effects.end(); it != end; ++it) { - // set valid but dummy values - d_nextBufferSize = 512; - d_nextSampleRate = 44100.0; - d_nextPluginIsDummy = true; - d_nextCanRequestParameterValueChanges = true; - - // Create dummy plugin to get data from - sPlugin = new PluginExporter(nullptr, nullptr, nullptr, nullptr); - - // unset - d_nextBufferSize = 0; - d_nextSampleRate = 0.0; - d_nextPluginIsDummy = false; - d_nextCanRequestParameterValueChanges = false; + ExtendedAEffect* const exteffect = *it; + delete exteffect->pluginPtr; + delete exteffect; } - if (doInternalInit) - { - *(PluginExporter**)ptr = sPlugin.get(); - return 0; - } + sPlugin = nullptr; } +} sCleanup; + +// -------------------------------------------------------------------------------------------------------------------- + +static inline +ExtendedAEffect* getExtendedEffect(vst_effect* const effect) +{ + if (effect == nullptr) + return nullptr; + + ExtendedAEffect* const exteffect = static_cast(effect); + DISTRHO_SAFE_ASSERT_RETURN(exteffect->valid == 101, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(exteffect->audioMaster != nullptr, nullptr); + + return exteffect; +} +static inline +PluginVst* getEffectPlugin(vst_effect* const effect) +{ + if (effect == nullptr) + return nullptr; + + ExtendedAEffect* const exteffect = static_cast(effect); + DISTRHO_SAFE_ASSERT_RETURN(exteffect->valid == 101, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(exteffect->audioMaster != nullptr, nullptr); + + return exteffect->pluginPtr; +} + +// -------------------------------------------------------------------------------------------------------------------- + +static intptr_t VST_FUNCTION_INTERFACE vst_dispatcherCallback(vst_effect* const effect, + const VST_EFFECT_OPCODE opcode, + const int32_t index, + const intptr_t value, + void* const ptr, + const float opt) +{ // handle base opcodes switch (opcode) { - case effOpen: - if (VstObject* const obj = vstObjectPtr) + case VST_EFFECT_OPCODE_CREATE: + if (ExtendedAEffect* const exteffect = getExtendedEffect(effect)) { - // this must always be valid - DISTRHO_SAFE_ASSERT_RETURN(obj->audioMaster != nullptr, 0); - - // some hosts call effOpen twice - if (obj->plugin != nullptr) + // some hosts call open/create twice + if (exteffect->pluginPtr != nullptr) return 1; - audioMasterCallback audioMaster = (audioMasterCallback)obj->audioMaster; + const vst_host_callback audioMaster = exteffect->audioMaster; - d_nextBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f); - d_nextSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); + d_nextBufferSize = audioMaster(effect, VST_HOST_OPCODE_11, 0, 0, nullptr, 0.0f); + d_nextSampleRate = audioMaster(effect, VST_HOST_OPCODE_10, 0, 0, nullptr, 0.0f); d_nextCanRequestParameterValueChanges = true; // some hosts are not ready at this point or return 0 buffersize/samplerate @@ -1337,35 +1388,37 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t if (d_nextSampleRate <= 0.0) d_nextSampleRate = 44100.0; - obj->plugin = new PluginVst(audioMaster, effect); + exteffect->pluginPtr = new PluginVst(audioMaster, effect); return 1; } return 0; - case effClose: - if (VstObject* const obj = vstObjectPtr) + case VST_EFFECT_OPCODE_DESTROY: + if (ExtendedAEffect* const exteffect = getExtendedEffect(effect)) { - if (obj->plugin != nullptr) + // delete plugin object + if (exteffect->pluginPtr != nullptr) { - delete obj->plugin; - obj->plugin = nullptr; + delete exteffect->pluginPtr; + exteffect->pluginPtr = nullptr; } -#if 0 - /* This code invalidates the object created in VSTPluginMain - * Probably not safe against all hosts */ - obj->audioMaster = nullptr; - effect->object = nullptr; - delete obj; -#endif + // delete effect too, if it comes from us + const std::vector::iterator it = std::find(sCleanup.effects.begin(), sCleanup.effects.end(), exteffect); + if (it != sCleanup.effects.end()) + { + delete exteffect; + sCleanup.effects.erase(it); + } - sPlugin = nullptr; + // delete global plugin instance too if this is the last loaded effect + if (sCleanup.effects.empty()) + sPlugin = nullptr; return 1; } - //delete effect; return 0; - case effGetParamLabel: + case VST_EFFECT_OPCODE_PARAM_GETLABEL: if (ptr != nullptr && index < static_cast(sPlugin->getParameterCount())) { strncpy((char*)ptr, sPlugin->getParameterUnit(index), 8); @@ -1373,7 +1426,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } return 0; - case effGetParamName: + case VST_EFFECT_OPCODE_PARAM_GETNAME: if (ptr != nullptr && index < static_cast(sPlugin->getParameterCount())) { const String& shortName(sPlugin->getParameterShortName(index)); @@ -1385,25 +1438,25 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } return 0; - case effGetParameterProperties: + case VST_EFFECT_OPCODE_38: // FIXME VST_EFFECT_OPCODE_GET_PARAMETER_PROPERTIES is wrong by 1 if (ptr != nullptr && index < static_cast(sPlugin->getParameterCount())) { - if (VstParameterProperties* const properties = (VstParameterProperties*)ptr) + if (vst_parameter_properties* const properties = (vst_parameter_properties*)ptr) { - memset(properties, 0, sizeof(VstParameterProperties)); + memset(properties, 0, sizeof(vst_parameter_properties)); // full name - strncpy(properties->label, + strncpy(properties->name, sPlugin->getParameterName(index), - sizeof(properties->label)); + sizeof(properties->name)); // short name const String& shortName(sPlugin->getParameterShortName(index)); if (shortName.isNotEmpty()) - strncpy(properties->shortLabel, + strncpy(properties->label, sPlugin->getParameterShortName(index), - sizeof(properties->shortLabel)); + sizeof(properties->label)); // parameter hints const uint32_t hints = sPlugin->getParameterHints(index); @@ -1413,20 +1466,20 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t if (hints & kParameterIsBoolean) { - properties->flags |= kVstParameterIsSwitch; + properties->flags |= VST_PARAMETER_FLAGS_SWITCH; } if (hints & kParameterIsInteger) { const ParameterRanges& ranges(sPlugin->getParameterRanges(index)); - properties->flags |= kVstParameterUsesIntegerMinMax; - properties->minInteger = static_cast(ranges.min); - properties->maxInteger = static_cast(ranges.max); + properties->flags |= VST_PARAMETER_FLAGS_INTEGER_LIMITS; + properties->min_value_i32 = static_cast(ranges.min); + properties->max_value_i32 = static_cast(ranges.max); } if (hints & kParameterIsLogarithmic) { - properties->flags |= kVstParameterCanRamp; + properties->flags |= VST_PARAMETER_FLAGS_UNKNOWN6; // can ramp } // parameter group (category in vst) @@ -1441,10 +1494,11 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t if (portGroup.groupId == groupId) { + properties->flags |= VST_PARAMETER_FLAGS_CATEGORY; properties->category = i + 1; - strncpy(properties->categoryLabel, + strncpy(properties->category_label, portGroup.name.buffer(), - sizeof(properties->categoryLabel)); + sizeof(properties->category_label)); break; } } @@ -1453,7 +1507,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t { for (uint32_t i=0, count=sPlugin->getParameterCount(); i < count; ++i) if (sPlugin->getParameterGroupId(i) == groupId) - ++properties->numParametersInCategory; + ++properties->num_parameters_in_category; } } @@ -1462,14 +1516,14 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } return 0; - case effGetPlugCategory: -#if DISTRHO_PLUGIN_IS_SYNTH - return kPlugCategSynth; -#else - return kPlugCategEffect; -#endif + case VST_EFFECT_OPCODE_EFFECT_CATEGORY: + #if DISTRHO_PLUGIN_IS_SYNTH + return VST_CATEGORY_02; + #else + return VST_CATEGORY_01; + #endif - case effGetEffectName: + case VST_EFFECT_OPCODE_EFFECT_NAME: if (char* const cptr = (char*)ptr) { strncpy(cptr, sPlugin->getName(), 32); @@ -1477,7 +1531,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } return 0; - case effGetVendorString: + case VST_EFFECT_OPCODE_VENDOR_NAME: if (char* const cptr = (char*)ptr) { strncpy(cptr, sPlugin->getMaker(), 32); @@ -1485,7 +1539,7 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } return 0; - case effGetProductString: + case VST_EFFECT_OPCODE_PRODUCT_NAME: if (char* const cptr = (char*)ptr) { strncpy(cptr, sPlugin->getLabel(), 32); @@ -1493,82 +1547,75 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t } return 0; - case effGetVendorVersion: + case VST_EFFECT_OPCODE_VENDOR_VERSION: return sPlugin->getVersion(); - case effGetVstVersion: - return kVstVersion; - }; + case VST_EFFECT_OPCODE_VST_VERSION: + return VST_VERSION_2_4_0_0; + + default: + break; + } // handle advanced opcodes - if (validPlugin) + if (PluginVst* const pluginPtr = getEffectPlugin(effect)) return pluginPtr->vst_dispatcher(opcode, index, value, ptr, opt); return 0; } -static float vst_getParameterCallback(AEffect* effect, int32_t index) +static float VST_FUNCTION_INTERFACE vst_getParameterCallback(vst_effect* const effect, + const uint32_t index) { - if (validPlugin) + if (PluginVst* const pluginPtr = getEffectPlugin(effect)) return pluginPtr->vst_getParameter(index); return 0.0f; } -static void vst_setParameterCallback(AEffect* effect, int32_t index, float value) +static void VST_FUNCTION_INTERFACE vst_setParameterCallback(vst_effect* const effect, + const uint32_t index, + const float value) { - if (validPlugin) + if (PluginVst* const pluginPtr = getEffectPlugin(effect)) pluginPtr->vst_setParameter(index, value); } -static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames) +static void VST_FUNCTION_INTERFACE vst_processCallback(vst_effect* const effect, + const float* const* const inputs, + float** const outputs, + const int32_t sampleFrames) { - if (validPlugin) + if (PluginVst* const pluginPtr = getEffectPlugin(effect)) pluginPtr->vst_processReplacing(const_cast(inputs), outputs, sampleFrames); } -static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames) +static void VST_FUNCTION_INTERFACE vst_processReplacingCallback(vst_effect* const effect, + const float* const* const inputs, + float** const outputs, + const int32_t sampleFrames) { - if (validPlugin) + if (PluginVst* const pluginPtr = getEffectPlugin(effect)) pluginPtr->vst_processReplacing(const_cast(inputs), outputs, sampleFrames); } -#undef pluginPtr -#undef validObject -#undef validPlugin -#undef vstObjectPtr - -static struct Cleanup { - std::vector effects; - - ~Cleanup() - { - for (std::vector::iterator it = effects.begin(), end = effects.end(); it != end; ++it) - { - AEffect* const effect = *it; - delete (VstObject*)effect->object; - delete effect; - } - } -} sCleanup; - // ----------------------------------------------------------------------- END_NAMESPACE_DISTRHO DISTRHO_PLUGIN_EXPORT -#if DISTRHO_OS_MAC || DISTRHO_OS_WASM || DISTRHO_OS_WINDOWS -const AEffect* VSTPluginMain(audioMasterCallback audioMaster); +#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) +const vst_effect* VSTPluginMain(vst_host_callback audioMaster); #else -const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main"); +const vst_effect* VSTPluginMain(vst_host_callback audioMaster) asm ("main"); #endif DISTRHO_PLUGIN_EXPORT -const AEffect* VSTPluginMain(audioMasterCallback audioMaster) +const vst_effect* VSTPluginMain(const vst_host_callback audioMaster) { USE_NAMESPACE_DISTRHO // old version - if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0) + if (audioMaster(nullptr, VST_HOST_OPCODE_01 /* version */, 0, 0, nullptr, 0.0f) == 0) return nullptr; // find plugin bundle @@ -1577,7 +1624,7 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) { String tmpPath(getBinaryFilename()); tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); -#ifdef DISTRHO_OS_MAC + #ifdef DISTRHO_OS_MAC if (tmpPath.endsWith("/MacOS")) { tmpPath.truncate(tmpPath.rfind('/')); @@ -1588,38 +1635,56 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) d_nextBundlePath = bundlePath.buffer(); } } -#else + #else if (tmpPath.endsWith(".vst")) { bundlePath = tmpPath; d_nextBundlePath = bundlePath.buffer(); } -#endif + #endif } // first internal init - PluginExporter* plugin = nullptr; - vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f); - DISTRHO_SAFE_ASSERT_RETURN(plugin != nullptr, nullptr); + if (sPlugin == nullptr) + { + // set valid but dummy values + d_nextBufferSize = 512; + d_nextSampleRate = 44100.0; + d_nextPluginIsDummy = true; + d_nextCanRequestParameterValueChanges = true; + + // Create dummy plugin to get data from + sPlugin = new PluginExporter(nullptr, nullptr, nullptr, nullptr); + + // unset + d_nextBufferSize = 0; + d_nextSampleRate = 0.0; + d_nextPluginIsDummy = false; + d_nextCanRequestParameterValueChanges = false; + } - AEffect* const effect(new AEffect); - std::memset(effect, 0, sizeof(AEffect)); + ExtendedAEffect* const effect = new ExtendedAEffect; + std::memset(effect, 0, sizeof(ExtendedAEffect)); // vst fields - effect->magic = kEffectMagic; - effect->uniqueID = plugin->getUniqueId(); - effect->version = plugin->getVersion(); + #ifdef WORDS_BIGENDIAN + effect->magic_number = 0x50747356; + #else + effect->magic_number = 0x56737450; + #endif + effect->unique_id = sPlugin->getUniqueId(); + effect->version = sPlugin->getVersion(); // VST doesn't support parameter outputs. we can fake them, but it is a hack. Disabled by default. #ifdef DPF_VST_SHOW_PARAMETER_OUTPUTS - const int numParams = plugin->getParameterCount(); + const int numParams = sPlugin->getParameterCount(); #else int numParams = 0; bool outputsReached = false; - for (uint32_t i=0, count=plugin->getParameterCount(); i < count; ++i) + for (uint32_t i=0, count=sPlugin->getParameterCount(); i < count; ++i) { - if (plugin->isParameterInput(i)) + if (sPlugin->isParameterInput(i)) { // parameter outputs must be all at the end DISTRHO_SAFE_ASSERT_BREAK(! outputsReached); @@ -1631,37 +1696,36 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) #endif // plugin fields - effect->numParams = numParams; - effect->numPrograms = 1; - effect->numInputs = DISTRHO_PLUGIN_NUM_INPUTS; - effect->numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS; + effect->num_params = numParams; + effect->num_programs = 1; + effect->num_inputs = DISTRHO_PLUGIN_NUM_INPUTS; + effect->num_outputs = DISTRHO_PLUGIN_NUM_OUTPUTS; // plugin flags - effect->flags |= effFlagsCanReplacing; -#if DISTRHO_PLUGIN_IS_SYNTH - effect->flags |= effFlagsIsSynth; -#endif -#if DISTRHO_PLUGIN_HAS_UI - effect->flags |= effFlagsHasEditor; -#endif -#if DISTRHO_PLUGIN_WANT_STATE - effect->flags |= effFlagsProgramChunks; -#endif + effect->flags |= 1 << 4; // uses process_float + #if DISTRHO_PLUGIN_IS_SYNTH + effect->flags |= 1 << 8; + #endif + #if DISTRHO_PLUGIN_HAS_UI + effect->flags |= 1 << 0; + #endif + #if DISTRHO_PLUGIN_WANT_STATE + effect->flags |= 1 << 5; + #endif // static calls - effect->dispatcher = vst_dispatcherCallback; - effect->process = vst_processCallback; - effect->getParameter = vst_getParameterCallback; - effect->setParameter = vst_setParameterCallback; - effect->processReplacing = vst_processReplacingCallback; + effect->control = vst_dispatcherCallback; + effect->process = vst_processCallback; + effect->get_parameter = vst_getParameterCallback; + effect->set_parameter = vst_setParameterCallback; + effect->process_float = vst_processReplacingCallback; - // pointers - VstObject* const obj = new VstObject(); - obj->audioMaster = audioMaster; - obj->plugin = nullptr; + // special values + effect->valid = 101; + effect->audioMaster = audioMaster; + effect->pluginPtr = nullptr; // done - effect->object = obj; sCleanup.effects.push_back(effect); return effect; diff --git a/dpf/distrho/src/DistrhoUI.cpp b/dpf/distrho/src/DistrhoUI.cpp index 1605f63..5ead4e8 100644 --- a/dpf/distrho/src/DistrhoUI.cpp +++ b/dpf/distrho/src/DistrhoUI.cpp @@ -174,28 +174,44 @@ ExternalWindow::PrivateData #else PluginWindow& #endif -UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint height) +UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const bool adjustForScaleFactor) { UI::PrivateData* const pData = s_nextPrivateData; -#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + const double scaleFactor = d_isNotZero(pData->scaleFactor) ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); + + if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) + { + width *= scaleFactor; + height *= scaleFactor; + } + pData->window = new PluginWindow(ui, pData->app); ExternalWindow::PrivateData ewData; ewData.parentWindowHandle = pData->winId; ewData.width = width; ewData.height = height; - ewData.scaleFactor = pData->scaleFactor != 0.0 ? pData->scaleFactor : getDesktopScaleFactor(pData->winId); + ewData.scaleFactor = scaleFactor; ewData.title = DISTRHO_PLUGIN_NAME; ewData.isStandalone = DISTRHO_UI_IS_STANDALONE; return ewData; -#else - pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, pData->scaleFactor); + #else + const double scaleFactor = pData->scaleFactor; + + if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0)) + { + width *= scaleFactor; + height *= scaleFactor; + } + + pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, scaleFactor); // If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks if (pData->callbacksPtr == nullptr) pData->window->setIgnoreIdleCallbacks(); return pData->window.getObject(); -#endif + #endif } /* ------------------------------------------------------------------------------------------------------------ @@ -207,22 +223,32 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA width == 0 ? DISTRHO_UI_DEFAULT_WIDTH : #endif width, + #ifdef DISTRHO_UI_DEFAULT_HEIGHT + height == 0 ? DISTRHO_UI_DEFAULT_HEIGHT : + #endif + height, #ifdef DISTRHO_UI_DEFAULT_WIDTH - height == 0 ? DISTRHO_UI_DEFAULT_WIDTH : + width == 0 + #else + false #endif - height)), + )), uiData(UI::PrivateData::s_nextPrivateData) { #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI if (width != 0 && height != 0) { - #ifndef DISTRHO_UI_DEFAULT_WIDTH Widget::setSize(width, height); - #endif if (automaticallyScaleAndSetAsMinimumSize) setGeometryConstraints(width, height, true, true, true); } + #ifdef DISTRHO_UI_DEFAULT_WIDTH + else + { + Widget::setSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT); + } + #endif #else // unused (void)automaticallyScaleAndSetAsMinimumSize; @@ -405,14 +431,14 @@ void UI::onResize(const ResizeEvent& ev) { UIWidget::onResize(ev); -#ifndef DISTRHO_PLUGIN_TARGET_VST3 + #if !(defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)) if (uiData->initializing) return; const uint width = ev.size.getWidth(); const uint height = ev.size.getHeight(); uiData->setSizeCallback(width, height); -#endif + #endif } // NOTE: only used for VST3 and CLAP diff --git a/dpf/distrho/src/DistrhoUIInternal.hpp b/dpf/distrho/src/DistrhoUIInternal.hpp index ebcb125..e7ecebe 100644 --- a/dpf/distrho/src/DistrhoUIInternal.hpp +++ b/dpf/distrho/src/DistrhoUIInternal.hpp @@ -193,16 +193,16 @@ public: ui->parameterChanged(index, value); } -#if DISTRHO_PLUGIN_WANT_PROGRAMS + #if DISTRHO_PLUGIN_WANT_PROGRAMS void programLoaded(const uint32_t index) { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); ui->programLoaded(index); } -#endif + #endif -#if DISTRHO_PLUGIN_WANT_STATE + #if DISTRHO_PLUGIN_WANT_STATE void stateChanged(const char* const key, const char* const value) { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); @@ -211,11 +211,11 @@ public: ui->stateChanged(key, value); } -#endif + #endif // ------------------------------------------------------------------- -#if DISTRHO_UI_IS_STANDALONE + #if DISTRHO_UI_IS_STANDALONE void exec(DGL_NAMESPACE::IdleCallback* const cb) { DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); @@ -238,7 +238,7 @@ public: uiData->window->show(); uiData->window->focus(); } -#endif + #endif bool plugin_idle() { @@ -263,7 +263,7 @@ public: // ------------------------------------------------------------------- #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS) - void idleForVST3() + void idleFromNativeIdle() { DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); @@ -272,12 +272,12 @@ public: } #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI - void addIdleCallbackForVST3(IdleCallback* const cb, const uint timerFrequencyInMs) + void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs) { uiData->window->addIdleCallback(cb, timerFrequencyInMs); } - void removeIdleCallbackForVST3(IdleCallback* const cb) + void removeIdleCallbackForNativeIdle(IdleCallback* const cb) { uiData->window->removeIdleCallback(cb); } diff --git a/dpf/distrho/src/DistrhoUILV2.cpp b/dpf/distrho/src/DistrhoUILV2.cpp index bfcbc68..617a436 100644 --- a/dpf/distrho/src/DistrhoUILV2.cpp +++ b/dpf/distrho/src/DistrhoUILV2.cpp @@ -556,7 +556,7 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const intptr_t winId = (intptr_t)parentId; float sampleRate = 0.0f; - float scaleFactor = 1.0f; + float scaleFactor = 0.0f; uint32_t bgColor = 0; uint32_t fgColor = 0xffffffff; @@ -567,7 +567,9 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const LV2_URID uridSampleRate = uridMap->map(uridMap->handle, LV2_PARAMETERS__sampleRate); const LV2_URID uridBgColor = uridMap->map(uridMap->handle, LV2_UI__backgroundColor); const LV2_URID uridFgColor = uridMap->map(uridMap->handle, LV2_UI__foregroundColor); + #ifndef DISTRHO_OS_MAC const LV2_URID uridScaleFactor = uridMap->map(uridMap->handle, LV2_UI__scaleFactor); + #endif for (int i=0; options[i].key != 0; ++i) { @@ -578,13 +580,6 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, else d_stderr("Host provides UI sample-rate but has wrong value type"); } - else if (options[i].key == uridScaleFactor) - { - if (options[i].type == uridAtomFloat) - scaleFactor = *(const float*)options[i].value; - else - d_stderr("Host provides UI scale factor but has wrong value type"); - } else if (options[i].key == uridBgColor) { if (options[i].type == uridAtomInt) @@ -599,6 +594,15 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, else d_stderr("Host provides UI foreground color but has wrong value type"); } + #ifndef DISTRHO_OS_MAC + else if (options[i].key == uridScaleFactor) + { + if (options[i].type == uridAtomFloat) + scaleFactor = *(const float*)options[i].value; + else + d_stderr("Host provides UI scale factor but has wrong value type"); + } + #endif } } diff --git a/dpf/distrho/src/DistrhoUIPrivateData.hpp b/dpf/distrho/src/DistrhoUIPrivateData.hpp index f46e146..dfe78ed 100644 --- a/dpf/distrho/src/DistrhoUIPrivateData.hpp +++ b/dpf/distrho/src/DistrhoUIPrivateData.hpp @@ -38,10 +38,10 @@ # define DISTRHO_UI_IS_STANDALONE 0 #endif -#ifdef DISTRHO_PLUGIN_TARGET_VST3 -# define DISTRHO_UI_IS_VST3 1 +#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP) +# define DISTRHO_UI_USES_SIZE_REQUEST true #else -# define DISTRHO_UI_IS_VST3 0 +# define DISTRHO_UI_USES_SIZE_REQUEST false #endif #ifdef DISTRHO_PLUGIN_TARGET_VST2 @@ -183,7 +183,7 @@ public: const uint height, const double scaleFactor) : Window(app, parentWindowHandle, width, height, scaleFactor, - DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_IS_VST3, false), + DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_USES_SIZE_REQUEST, false), ui(uiPtr), initializing(true), receivedReshapeDuringInit(false) @@ -424,9 +424,9 @@ struct UI::PrivateData { static UI::PrivateData* s_nextPrivateData; #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI - static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height); + static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); #else - static PluginWindow& createNextWindow(UI* ui, uint width, uint height); + static PluginWindow& createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor); #endif }; diff --git a/dpf/distrho/src/DistrhoUIVST3.cpp b/dpf/distrho/src/DistrhoUIVST3.cpp index 8916048..9688ad0 100644 --- a/dpf/distrho/src/DistrhoUIVST3.cpp +++ b/dpf/distrho/src/DistrhoUIVST3.cpp @@ -270,7 +270,7 @@ public: #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI fIdleHelper.registerNativeIdleCallback(); #else - fUI.addIdleCallbackForVST3(this, DPF_VST3_TIMER_INTERVAL); + fUI.addIdleCallbackForNativeIdle(this, DPF_VST3_TIMER_INTERVAL); #endif } @@ -282,7 +282,7 @@ public: #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI fIdleHelper.unregisterNativeIdleCallback(); #else - fUI.removeIdleCallbackForVST3(this); + fUI.removeIdleCallbackForNativeIdle(this); #endif } @@ -694,7 +694,7 @@ public: void idleCallback() override { - fUI.idleForVST3(); + fUI.idleFromNativeIdle(); doIdleStuff(); } #endif diff --git a/dpf/distrho/src/clap/entry.h b/dpf/distrho/src/clap/entry.h index 8f3cc1d..996a498 100644 --- a/dpf/distrho/src/clap/entry.h +++ b/dpf/distrho/src/clap/entry.h @@ -48,16 +48,16 @@ typedef struct clap_plugin_entry { // // If init() returns false, then the host must not call deinit() nor any other clap // related symbols from the DSO. - bool (*init)(const char *plugin_path); + bool(CLAP_ABI *init)(const char *plugin_path); // No more calls into the DSO must be made after calling deinit(). - void (*deinit)(void); + void(CLAP_ABI *deinit)(void); // Get the pointer to a factory. See plugin-factory.h for an example. // // Returns null if the factory is not provided. // The returned pointer must *not* be freed by the caller. - const void *(*get_factory)(const char *factory_id); + const void *(CLAP_ABI *get_factory)(const char *factory_id); } clap_plugin_entry_t; /* Entry point */ diff --git a/dpf/distrho/src/clap/events.h b/dpf/distrho/src/clap/events.h index db2314f..895efc9 100644 --- a/dpf/distrho/src/clap/events.h +++ b/dpf/distrho/src/clap/events.h @@ -263,10 +263,11 @@ typedef struct clap_event_midi2 { typedef struct clap_input_events { void *ctx; // reserved pointer for the list - uint32_t (*size)(const struct clap_input_events *list); + // returns the number of events in the list + uint32_t(CLAP_ABI *size)(const struct clap_input_events *list); // Don't free the returned event, it belongs to the list - const clap_event_header_t *(*get)(const struct clap_input_events *list, uint32_t index); + const clap_event_header_t *(CLAP_ABI *get)(const struct clap_input_events *list, uint32_t index); } clap_input_events_t; // Output event list, events must be sorted by time. @@ -275,7 +276,8 @@ typedef struct clap_output_events { // Pushes a copy of the event // returns false if the event could not be pushed to the queue (out of memory?) - bool (*try_push)(const struct clap_output_events *list, const clap_event_header_t *event); + bool(CLAP_ABI *try_push)(const struct clap_output_events *list, + const clap_event_header_t *event); } clap_output_events_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/ext/audio-ports.h b/dpf/distrho/src/clap/ext/audio-ports.h index 5d0af46..badf78e 100644 --- a/dpf/distrho/src/clap/ext/audio-ports.h +++ b/dpf/distrho/src/clap/ext/audio-ports.h @@ -69,14 +69,14 @@ typedef struct clap_audio_port_info { typedef struct clap_plugin_audio_ports { // number of ports, for either input or output // [main-thread] - uint32_t (*count)(const clap_plugin_t *plugin, bool is_input); + uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin, bool is_input); // get info about about an audio port. // [main-thread] - bool (*get)(const clap_plugin_t *plugin, - uint32_t index, - bool is_input, - clap_audio_port_info_t *info); + bool(CLAP_ABI *get)(const clap_plugin_t *plugin, + uint32_t index, + bool is_input, + clap_audio_port_info_t *info); } clap_plugin_audio_ports_t; enum { @@ -102,13 +102,13 @@ enum { typedef struct clap_host_audio_ports { // Checks if the host allows a plugin to change a given aspect of the audio ports definition. // [main-thread] - bool (*is_rescan_flag_supported)(const clap_host_t *host, uint32_t flag); + bool(CLAP_ABI *is_rescan_flag_supported)(const clap_host_t *host, uint32_t flag); // Rescan the full list of audio ports according to the flags. // It is illegal to ask the host to rescan with a flag that is not supported. // Certain flags require the plugin to be de-activated. // [main-thread] - void (*rescan)(const clap_host_t *host, uint32_t flags); + void(CLAP_ABI *rescan)(const clap_host_t *host, uint32_t flags); } clap_host_audio_ports_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/ext/gui.h b/dpf/distrho/src/clap/ext/gui.h index da43612..cb03fa2 100644 --- a/dpf/distrho/src/clap/ext/gui.h +++ b/dpf/distrho/src/clap/ext/gui.h @@ -97,12 +97,16 @@ typedef struct clap_gui_resize_hints { typedef struct clap_plugin_gui { // Returns true if the requested gui api is supported // [main-thread] - bool (*is_api_supported)(const clap_plugin_t *plugin, const char *api, bool is_floating); + bool(CLAP_ABI *is_api_supported)(const clap_plugin_t *plugin, const char *api, bool is_floating); // Returns true if the plugin has a preferred api. // The host has no obligation to honor the plugin preferrence, this is just a hint. + // The const char **api variable should be explicitly assigned as a pointer to + // one of the CLAP_WINDOW_API_ constants defined above, not strcopied. // [main-thread] - bool (*get_preferred_api)(const clap_plugin_t *plugin, const char **api, bool *is_floating); + bool(CLAP_ABI *get_preferred_api)(const clap_plugin_t *plugin, + const char **api, + bool *is_floating); // Create and allocate all resources necessary for the gui. // @@ -115,11 +119,11 @@ typedef struct clap_plugin_gui { // // After this call, the GUI may not be visible yet; don't forget to call show(). // [main-thread] - bool (*create)(const clap_plugin_t *plugin, const char *api, bool is_floating); + bool(CLAP_ABI *create)(const clap_plugin_t *plugin, const char *api, bool is_floating); // Free all resources associated with the gui. // [main-thread] - void (*destroy)(const clap_plugin_t *plugin); + void(CLAP_ABI *destroy)(const clap_plugin_t *plugin); // Set the absolute GUI scaling factor, and override any OS info. // Should not be used if the windowing api relies upon logical pixels. @@ -130,21 +134,21 @@ typedef struct clap_plugin_gui { // Returns true if the scaling could be applied // Returns false if the call was ignored, or the scaling could not be applied. // [main-thread] - bool (*set_scale)(const clap_plugin_t *plugin, double scale); + bool(CLAP_ABI *set_scale)(const clap_plugin_t *plugin, double scale); // Get the current size of the plugin UI. // clap_plugin_gui->create() must have been called prior to asking the size. // [main-thread] - bool (*get_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height); + bool(CLAP_ABI *get_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height); // Returns true if the window is resizeable (mouse drag). // Only for embedded windows. // [main-thread] - bool (*can_resize)(const clap_plugin_t *plugin); + bool(CLAP_ABI *can_resize)(const clap_plugin_t *plugin); // Returns true if the plugin can provide hints on how to resize the window. // [main-thread] - bool (*get_resize_hints)(const clap_plugin_t *plugin, clap_gui_resize_hints_t *hints); + bool(CLAP_ABI *get_resize_hints)(const clap_plugin_t *plugin, clap_gui_resize_hints_t *hints); // If the plugin gui is resizable, then the plugin will calculate the closest // usable size which fits in the given size. @@ -152,38 +156,38 @@ typedef struct clap_plugin_gui { // // Only for embedded windows. // [main-thread] - bool (*adjust_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height); + bool(CLAP_ABI *adjust_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height); // Sets the window size. Only for embedded windows. // [main-thread] - bool (*set_size)(const clap_plugin_t *plugin, uint32_t width, uint32_t height); + bool(CLAP_ABI *set_size)(const clap_plugin_t *plugin, uint32_t width, uint32_t height); // Embbeds the plugin window into the given window. // [main-thread & !floating] - bool (*set_parent)(const clap_plugin_t *plugin, const clap_window_t *window); + bool(CLAP_ABI *set_parent)(const clap_plugin_t *plugin, const clap_window_t *window); // Set the plugin floating window to stay above the given window. // [main-thread & floating] - bool (*set_transient)(const clap_plugin_t *plugin, const clap_window_t *window); + bool(CLAP_ABI *set_transient)(const clap_plugin_t *plugin, const clap_window_t *window); // Suggests a window title. Only for floating windows. // [main-thread & floating] - void (*suggest_title)(const clap_plugin_t *plugin, const char *title); + void(CLAP_ABI *suggest_title)(const clap_plugin_t *plugin, const char *title); // Show the window. // [main-thread] - bool (*show)(const clap_plugin_t *plugin); + bool(CLAP_ABI *show)(const clap_plugin_t *plugin); // Hide the window, this method does not free the resources, it just hides // the window content. Yet it may be a good idea to stop painting timers. // [main-thread] - bool (*hide)(const clap_plugin_t *plugin); + bool(CLAP_ABI *hide)(const clap_plugin_t *plugin); } clap_plugin_gui_t; typedef struct clap_host_gui { // The host should call get_resize_hints() again. // [thread-safe] - void (*resize_hints_changed)(const clap_host_t *host); + void(CLAP_ABI *resize_hints_changed)(const clap_host_t *host); /* Request the host to resize the client area to width, height. * Return true if the new size is accepted, false otherwise. @@ -194,24 +198,24 @@ typedef struct clap_host_gui { * satisfied then the host will call set_size() to revert the operation. * * [thread-safe] */ - bool (*request_resize)(const clap_host_t *host, uint32_t width, uint32_t height); + bool(CLAP_ABI *request_resize)(const clap_host_t *host, uint32_t width, uint32_t height); /* Request the host to show the plugin gui. * Return true on success, false otherwise. * [thread-safe] */ - bool (*request_show)(const clap_host_t *host); + bool(CLAP_ABI *request_show)(const clap_host_t *host); /* Request the host to hide the plugin gui. * Return true on success, false otherwise. * [thread-safe] */ - bool (*request_hide)(const clap_host_t *host); + bool(CLAP_ABI *request_hide)(const clap_host_t *host); // The floating window has been closed, or the connection to the gui has been lost. // // If was_destroyed is true, then the host must call clap_plugin_gui->destroy() to acknowledge // the gui destruction. // [thread-safe] - void (*closed)(const clap_host_t *host, bool was_destroyed); + void(CLAP_ABI *closed)(const clap_host_t *host, bool was_destroyed); } clap_host_gui_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/ext/latency.h b/dpf/distrho/src/clap/ext/latency.h new file mode 100644 index 0000000..ca068ca --- /dev/null +++ b/dpf/distrho/src/clap/ext/latency.h @@ -0,0 +1,28 @@ +#pragma once + +#include "../plugin.h" + +static CLAP_CONSTEXPR const char CLAP_EXT_LATENCY[] = "clap.latency"; + +#ifdef __cplusplus +extern "C" { +#endif + +// The audio ports scan has to be done while the plugin is deactivated. +typedef struct clap_plugin_latency { + // Returns the plugin latency. + // [main-thread] + uint32_t(CLAP_ABI *get)(const clap_plugin_t *plugin); +} clap_plugin_latency_t; + +typedef struct clap_host_latency { + // Tell the host that the latency changed. + // The latency is only allowed to change if the plugin is deactivated. + // If the plugin is activated, call host->request_restart() + // [main-thread] + void(CLAP_ABI *changed)(const clap_host_t *host); +} clap_host_latency_t; + +#ifdef __cplusplus +} +#endif diff --git a/dpf/distrho/src/clap/ext/note-ports.h b/dpf/distrho/src/clap/ext/note-ports.h new file mode 100644 index 0000000..806dace --- /dev/null +++ b/dpf/distrho/src/clap/ext/note-ports.h @@ -0,0 +1,78 @@ +#pragma once + +#include "../plugin.h" +#include "../string-sizes.h" + +/// @page Note Ports +/// +/// This extension provides a way for the plugin to describe its current note ports. +/// If the plugin does not implement this extension, it won't have note input or output. +/// The plugin is only allowed to change its note ports configuration while it is deactivated. + +static CLAP_CONSTEXPR const char CLAP_EXT_NOTE_PORTS[] = "clap.note-ports"; + +#ifdef __cplusplus +extern "C" { +#endif + +enum clap_note_dialect { + // Uses clap_event_note and clap_event_note_expression. + CLAP_NOTE_DIALECT_CLAP = 1 << 0, + + // Uses clap_event_midi, no polyphonic expression + CLAP_NOTE_DIALECT_MIDI = 1 << 1, + + // Uses clap_event_midi, with polyphonic expression (MPE) + CLAP_NOTE_DIALECT_MIDI_MPE = 1 << 2, + + // Uses clap_event_midi2 + CLAP_NOTE_DIALECT_MIDI2 = 1 << 3, +}; + +typedef struct clap_note_port_info { + // id identifies a port and must be stable. + // id may overlap between input and output ports. + clap_id id; + uint32_t supported_dialects; // bitfield, see clap_note_dialect + uint32_t preferred_dialect; // one value of clap_note_dialect + char name[CLAP_NAME_SIZE]; // displayable name, i18n? +} clap_note_port_info_t; + +// The note ports scan has to be done while the plugin is deactivated. +typedef struct clap_plugin_note_ports { + // number of ports, for either input or output + // [main-thread] + uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin, bool is_input); + + // get info about about a note port. + // [main-thread] + bool(CLAP_ABI *get)(const clap_plugin_t *plugin, + uint32_t index, + bool is_input, + clap_note_port_info_t *info); +} clap_plugin_note_ports_t; + +enum { + // The ports have changed, the host shall perform a full scan of the ports. + // This flag can only be used if the plugin is not active. + // If the plugin active, call host->request_restart() and then call rescan() + // when the host calls deactivate() + CLAP_NOTE_PORTS_RESCAN_ALL = 1 << 0, + + // The ports name did change, the host can scan them right away. + CLAP_NOTE_PORTS_RESCAN_NAMES = 1 << 1, +}; + +typedef struct clap_host_note_ports { + // Query which dialects the host supports + // [main-thread] + uint32_t(CLAP_ABI *supported_dialects)(const clap_host_t *host); + + // Rescan the full list of note ports according to the flags. + // [main-thread] + void(CLAP_ABI *rescan)(const clap_host_t *host, uint32_t flags); +} clap_host_note_ports_t; + +#ifdef __cplusplus +} +#endif diff --git a/dpf/distrho/src/clap/ext/params.h b/dpf/distrho/src/clap/ext/params.h index 93ab841..4c58d36 100644 --- a/dpf/distrho/src/clap/ext/params.h +++ b/dpf/distrho/src/clap/ext/params.h @@ -155,16 +155,43 @@ typedef struct clap_param_info { clap_param_info_flags flags; - // This value is optional and set by the plugin. - // Its purpose is to provide a fast access to the plugin parameter: + // This value is optional and set by the plugin. The host will + // set it on all subsequent events regarding this param_id + // or set the cookie to nullptr if the host chooses to + // not implement cookies. // + // The plugin must gracefully handle the case of a cookie + // which is nullptr, but can safely assume any cookie + // which is not nullptr is the value it issued. + // + // It is very strongly recommended that the host implement + // cookies. Some plugins may have noticably reduced + // performance when addressing params in hosts without cookies. + // + // The cookie's purpose is to provide a fast access to the + // plugin parameter objects. For instance: + // + // in clap_plugin_params.get_info // Parameter *p = findParameter(param_id); // param_info->cookie = p; // - // /* and later on */ - // Parameter *p = (Parameter *)cookie; + // later, in clap_plugin.process: + // + // Parameter *p{nullptr}; + // if (evt->cookie) [[likely]] + // p = (Parameter *)evt->cookie; + // else + // p = -- alternate mechanism -- // - // It is invalidated on clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) and when the plugin is + // where "alternate mechanism" is a mechanism the plugin implements + // to map parameter ids to internal objects. + // + // The host should make no assumption about the + // value of the cookie other than passing it back to the plugin or + // replacing it with nullptr. + // + // Once set, the cookie is valid until invalidated by a call to + // clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) or when the plugin is // destroyed. void *cookie; @@ -183,39 +210,44 @@ typedef struct clap_param_info { typedef struct clap_plugin_params { // Returns the number of parameters. // [main-thread] - uint32_t (*count)(const clap_plugin_t *plugin); + uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin); // Copies the parameter's info to param_info and returns true on success. // [main-thread] - bool (*get_info)(const clap_plugin_t *plugin, - uint32_t param_index, - clap_param_info_t *param_info); + bool(CLAP_ABI *get_info)(const clap_plugin_t *plugin, + uint32_t param_index, + clap_param_info_t *param_info); // Gets the parameter plain value. // [main-thread] - bool (*get_value)(const clap_plugin_t *plugin, clap_id param_id, double *value); + bool(CLAP_ABI *get_value)(const clap_plugin_t *plugin, clap_id param_id, double *value); // Formats the display text for the given parameter value. // The host should always format the parameter value to text using this function // before displaying it to the user. // [main-thread] - bool (*value_to_text)( + bool(CLAP_ABI *value_to_text)( const clap_plugin_t *plugin, clap_id param_id, double value, char *display, uint32_t size); // Converts the display text to a parameter value. // [main-thread] - bool (*text_to_value)(const clap_plugin_t *plugin, - clap_id param_id, - const char *display, - double *value); + bool(CLAP_ABI *text_to_value)(const clap_plugin_t *plugin, + clap_id param_id, + const char *display, + double *value); // Flushes a set of parameter changes. // This method must not be called concurrently to clap_plugin->process(). // + // Note: if the plugin is processing, then the process() call will already achieve the + // parameter update (bi-directionnal), so a call to flush isn't required, also be aware + // that the plugin may use the sample offset in process(), while this information would be + // lost within flush(). + // // [active ? audio-thread : main-thread] - void (*flush)(const clap_plugin_t *plugin, - const clap_input_events_t *in, - const clap_output_events_t *out); + void(CLAP_ABI *flush)(const clap_plugin_t *plugin, + const clap_input_events_t *in, + const clap_output_events_t *out); } clap_plugin_params_t; enum { @@ -272,23 +304,23 @@ typedef uint32_t clap_param_clear_flags; typedef struct clap_host_params { // Rescan the full list of parameters according to the flags. // [main-thread] - void (*rescan)(const clap_host_t *host, clap_param_rescan_flags flags); + void(CLAP_ABI *rescan)(const clap_host_t *host, clap_param_rescan_flags flags); // Clears references to a parameter. // [main-thread] - void (*clear)(const clap_host_t *host, clap_id param_id, clap_param_clear_flags flags); + void(CLAP_ABI *clear)(const clap_host_t *host, clap_id param_id, clap_param_clear_flags flags); // Request a parameter flush. // // The host will then schedule a call to either: // - clap_plugin.process() - // - clap_plugin_params->flush() + // - clap_plugin_params.flush() // // This function is always safe to use and should not be called from an [audio-thread] as the // plugin would already be within process() or flush(). // // [thread-safe,!audio-thread] - void (*request_flush)(const clap_host_t *host); + void(CLAP_ABI *request_flush)(const clap_host_t *host); } clap_host_params_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/ext/state.h b/dpf/distrho/src/clap/ext/state.h new file mode 100644 index 0000000..c1c2cdc --- /dev/null +++ b/dpf/distrho/src/clap/ext/state.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../plugin.h" +#include "../stream.h" + +static CLAP_CONSTEXPR const char CLAP_EXT_STATE[] = "clap.state"; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct clap_plugin_state { + // Saves the plugin state into stream. + // Returns true if the state was correctly saved. + // [main-thread] + bool(CLAP_ABI *save)(const clap_plugin_t *plugin, const clap_ostream_t *stream); + + // Loads the plugin state from stream. + // Returns true if the state was correctly restored. + // [main-thread] + bool(CLAP_ABI *load)(const clap_plugin_t *plugin, const clap_istream_t *stream); +} clap_plugin_state_t; + +typedef struct clap_host_state { + // Tell the host that the plugin state has changed and should be saved again. + // If a parameter value changes, then it is implicit that the state is dirty. + // [main-thread] + void(CLAP_ABI *mark_dirty)(const clap_host_t *host); +} clap_host_state_t; + +#ifdef __cplusplus +} +#endif diff --git a/dpf/distrho/src/clap/ext/thread-check.h b/dpf/distrho/src/clap/ext/thread-check.h new file mode 100644 index 0000000..359ac88 --- /dev/null +++ b/dpf/distrho/src/clap/ext/thread-check.h @@ -0,0 +1,51 @@ +#pragma once + +#include "../plugin.h" + +static CLAP_CONSTEXPR const char CLAP_EXT_THREAD_CHECK[] = "clap.thread-check"; + +#ifdef __cplusplus +extern "C" { +#endif + +/// @page thread-check +/// +/// CLAP defines two symbolic threads: +/// +/// main-thread: +/// This is the thread in which most of the interaction between the plugin and host happens. +/// It is usually the thread on which the GUI receives its events. +/// It isn't a realtime thread, yet this thread needs to respond fast enough to user interaction, +/// so it is recommended to run long and expensive tasks such as preset indexing or asset loading +/// in dedicated background threads. +/// +/// audio-thread: +/// This thread is used for realtime audio processing. Its execution should be as deterministic +/// as possible to meet the audio interface's deadline (can be <1ms). In other words, there is a +/// known set of operations that should be avoided: malloc() and free(), mutexes (spin mutexes +/// are worse), I/O, waiting, ... +/// The audio-thread is something symbolic, there isn't one OS thread that remains the +/// audio-thread for the plugin lifetime. As you may guess, the host is likely to have a +/// thread pool and the plugin.process() call may be scheduled on different OS threads over time. +/// The most important thing is that there can't be two audio-threads at the same time. All the +/// functions marked with [audio-thread] **ARE NOT CONCURRENT**. The host may mark any OS thread, +/// including the main-thread as the audio-thread, as long as it can guarentee that only one OS +/// thread is the audio-thread at a time. The audio-thread can be seen as a concurrency guard for +/// all functions marked with [audio-thread]. + +// This interface is useful to do runtime checks and make +// sure that the functions are called on the correct threads. +// It is highly recommended that hosts implement this extension. +typedef struct clap_host_thread_check { + // Returns true if "this" thread is the main thread. + // [thread-safe] + bool(CLAP_ABI *is_main_thread)(const clap_host_t *host); + + // Returns true if "this" thread is one of the audio threads. + // [thread-safe] + bool(CLAP_ABI *is_audio_thread)(const clap_host_t *host); +} clap_host_thread_check_t; + +#ifdef __cplusplus +} +#endif diff --git a/dpf/distrho/src/clap/ext/timer-support.h b/dpf/distrho/src/clap/ext/timer-support.h new file mode 100644 index 0000000..b8d13a6 --- /dev/null +++ b/dpf/distrho/src/clap/ext/timer-support.h @@ -0,0 +1,29 @@ +#pragma once + +#include "../plugin.h" + +static CLAP_CONSTEXPR const char CLAP_EXT_TIMER_SUPPORT[] = "clap.timer-support"; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct clap_plugin_timer_support { + // [main-thread] + void(CLAP_ABI *on_timer)(const clap_plugin_t *plugin, clap_id timer_id); +} clap_plugin_timer_support_t; + +typedef struct clap_host_timer_support { + // Registers a periodic timer. + // The host may adjust the period if it is under a certain threshold. + // 30 Hz should be allowed. + // [main-thread] + bool(CLAP_ABI *register_timer)(const clap_host_t *host, uint32_t period_ms, clap_id *timer_id); + + // [main-thread] + bool(CLAP_ABI *unregister_timer)(const clap_host_t *host, clap_id timer_id); +} clap_host_timer_support_t; + +#ifdef __cplusplus +} +#endif diff --git a/dpf/distrho/src/clap/host.h b/dpf/distrho/src/clap/host.h index 0b67aad..07fcabe 100644 --- a/dpf/distrho/src/clap/host.h +++ b/dpf/distrho/src/clap/host.h @@ -19,21 +19,21 @@ typedef struct clap_host { // Query an extension. // [thread-safe] - const void *(*get_extension)(const struct clap_host *host, const char *extension_id); + const void *(CLAP_ABI *get_extension)(const struct clap_host *host, const char *extension_id); // Request the host to deactivate and then reactivate the plugin. // The operation may be delayed by the host. // [thread-safe] - void (*request_restart)(const struct clap_host *host); + void(CLAP_ABI *request_restart)(const struct clap_host *host); // Request the host to activate and start processing the plugin. // This is useful if you have external IO and need to wake up the plugin from "sleep". // [thread-safe] - void (*request_process)(const struct clap_host *host); + void(CLAP_ABI *request_process)(const struct clap_host *host); // Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread. // [thread-safe] - void (*request_callback)(const struct clap_host *host); + void(CLAP_ABI *request_callback)(const struct clap_host *host); } clap_host_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/plugin-factory.h b/dpf/distrho/src/clap/plugin-factory.h index 07e8560..3262975 100644 --- a/dpf/distrho/src/clap/plugin-factory.h +++ b/dpf/distrho/src/clap/plugin-factory.h @@ -11,17 +11,18 @@ extern "C" { // Every method must be thread-safe. // It is very important to be able to scan the plugin as quickly as possible. // -// If the content of the factory may change due to external events, like the user installed +// The host may use clap_plugin_invalidation_factory to detect filesystem changes +// which may change the factory's content. typedef struct clap_plugin_factory { // Get the number of plugins available. // [thread-safe] - uint32_t (*get_plugin_count)(const struct clap_plugin_factory *factory); + uint32_t(CLAP_ABI *get_plugin_count)(const struct clap_plugin_factory *factory); // Retrieves a plugin descriptor by its index. // Returns null in case of error. // The descriptor must not be freed. // [thread-safe] - const clap_plugin_descriptor_t *(*get_plugin_descriptor)( + const clap_plugin_descriptor_t *(CLAP_ABI *get_plugin_descriptor)( const struct clap_plugin_factory *factory, uint32_t index); // Create a clap_plugin by its plugin_id. @@ -29,9 +30,9 @@ typedef struct clap_plugin_factory { // The plugin is not allowed to use the host callbacks in the create method. // Returns null in case of error. // [thread-safe] - const clap_plugin_t *(*create_plugin)(const struct clap_plugin_factory *factory, - const clap_host_t *host, - const char *plugin_id); + const clap_plugin_t *(CLAP_ABI *create_plugin)(const struct clap_plugin_factory *factory, + const clap_host_t *host, + const char *plugin_id); } clap_plugin_factory_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/plugin.h b/dpf/distrho/src/clap/plugin.h index 04cbc8e..af0193c 100644 --- a/dpf/distrho/src/clap/plugin.h +++ b/dpf/distrho/src/clap/plugin.h @@ -38,12 +38,12 @@ typedef struct clap_plugin { // Must be called after creating the plugin. // If init returns false, the host must destroy the plugin instance. // [main-thread] - bool (*init)(const struct clap_plugin *plugin); + bool(CLAP_ABI *init)(const struct clap_plugin *plugin); // Free the plugin and its resources. // It is required to deactivate the plugin prior to this call. // [main-thread & !active] - void (*destroy)(const struct clap_plugin *plugin); + void(CLAP_ABI *destroy)(const struct clap_plugin *plugin); // Activate and deactivate the plugin. // In this call the plugin may allocate memory and prepare everything needed for the process @@ -52,21 +52,20 @@ typedef struct clap_plugin { // Once activated the latency and port configuration must remain constant, until deactivation. // // [main-thread & !active_state] - bool (*activate)(const struct clap_plugin *plugin, - double sample_rate, - uint32_t min_frames_count, - uint32_t max_frames_count); - + bool(CLAP_ABI *activate)(const struct clap_plugin *plugin, + double sample_rate, + uint32_t min_frames_count, + uint32_t max_frames_count); // [main-thread & active_state] - void (*deactivate)(const struct clap_plugin *plugin); + void(CLAP_ABI *deactivate)(const struct clap_plugin *plugin); // Call start processing before processing. // [audio-thread & active_state & !processing_state] - bool (*start_processing)(const struct clap_plugin *plugin); + bool(CLAP_ABI *start_processing)(const struct clap_plugin *plugin); // Call stop processing before sending the plugin to sleep. // [audio-thread & active_state & processing_state] - void (*stop_processing)(const struct clap_plugin *plugin); + void(CLAP_ABI *stop_processing)(const struct clap_plugin *plugin); // - Clears all buffers, performs a full reset of the processing state (filters, oscillators, // enveloppes, lfo, ...) and kills all voices. @@ -74,21 +73,22 @@ typedef struct clap_plugin { // - clap_process.steady_time may jump backward. // // [audio-thread & active_state] - void (*reset)(const struct clap_plugin *plugin); + void(CLAP_ABI *reset)(const struct clap_plugin *plugin); // process audio, events, ... // [audio-thread & active_state & processing_state] - clap_process_status (*process)(const struct clap_plugin *plugin, const clap_process_t *process); + clap_process_status(CLAP_ABI *process)(const struct clap_plugin *plugin, + const clap_process_t *process); // Query an extension. // The returned pointer is owned by the plugin. // [thread-safe] - const void *(*get_extension)(const struct clap_plugin *plugin, const char *id); + const void *(CLAP_ABI *get_extension)(const struct clap_plugin *plugin, const char *id); // Called by the host on the main thread in response to a previous call to: // host->request_callback(host); // [main-thread] - void (*on_main_thread)(const struct clap_plugin *plugin); + void(CLAP_ABI *on_main_thread)(const struct clap_plugin *plugin); } clap_plugin_t; #ifdef __cplusplus diff --git a/dpf/distrho/src/clap/private/macros.h b/dpf/distrho/src/clap/private/macros.h index 1d62251..15b6b1b 100644 --- a/dpf/distrho/src/clap/private/macros.h +++ b/dpf/distrho/src/clap/private/macros.h @@ -17,6 +17,14 @@ # endif #endif +#if !defined(CLAP_ABI) +# if defined _WIN32 || defined __CYGWIN__ +# define CLAP_ABI __cdecl +# else +# define CLAP_ABI +# endif +#endif + #if defined(__cplusplus) && __cplusplus >= 201103L # define CLAP_HAS_CXX11 # define CLAP_CONSTEXPR constexpr diff --git a/dpf/distrho/src/clap/process.h b/dpf/distrho/src/clap/process.h index d5bf572..746cb1f 100644 --- a/dpf/distrho/src/clap/process.h +++ b/dpf/distrho/src/clap/process.h @@ -45,8 +45,9 @@ typedef struct clap_process { const clap_event_transport_t *transport; // Audio buffers, they must have the same count as specified - // by clap_plugin_audio_ports->get_count(). - // The index maps to clap_plugin_audio_ports->get_info(). + // by clap_plugin_audio_ports->count(). + // The index maps to clap_plugin_audio_ports->get(). + // Input buffer and its contents are read-only. const clap_audio_buffer_t *audio_inputs; clap_audio_buffer_t *audio_outputs; uint32_t audio_inputs_count; diff --git a/dpf/distrho/src/clap/stream.h b/dpf/distrho/src/clap/stream.h new file mode 100644 index 0000000..3e8d9a9 --- /dev/null +++ b/dpf/distrho/src/clap/stream.h @@ -0,0 +1,26 @@ +#pragma once + +#include "private/std.h" +#include "private/macros.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct clap_istream { + void *ctx; // reserved pointer for the stream + + // returns the number of bytes read; 0 indicates end of file and -1 a read error + int64_t(CLAP_ABI *read)(const struct clap_istream *stream, void *buffer, uint64_t size); +} clap_istream_t; + +typedef struct clap_ostream { + void *ctx; // reserved pointer for the stream + + // returns the number of bytes written; -1 on write error + int64_t(CLAP_ABI *write)(const struct clap_ostream *stream, const void *buffer, uint64_t size); +} clap_ostream_t; + +#ifdef __cplusplus +} +#endif diff --git a/dpf/distrho/src/jackbridge/RtAudioBridge.hpp b/dpf/distrho/src/jackbridge/RtAudioBridge.hpp index 2d37133..d156ff2 100644 --- a/dpf/distrho/src/jackbridge/RtAudioBridge.hpp +++ b/dpf/distrho/src/jackbridge/RtAudioBridge.hpp @@ -29,6 +29,7 @@ # define RTMIDI_API_TYPE MACOSX_CORE #elif defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) # define __WINDOWS_DS__ +# define __WINDOWS_MM__ # define RTAUDIO_API_TYPE WINDOWS_DS # define RTMIDI_API_TYPE WINDOWS_MM #else @@ -36,10 +37,10 @@ # define __LINUX_PULSE__ # define RTAUDIO_API_TYPE LINUX_PULSE # elif defined(HAVE_ALSA) -# define __LINUX_ALSA__ - # define RTAUDIO_API_TYPE LINUX_ALSA +# define RTAUDIO_API_TYPE LINUX_ALSA # endif # ifdef HAVE_ALSA +# define __LINUX_ALSA__ # define RTMIDI_API_TYPE LINUX_ALSA # endif #endif diff --git a/dpf/distrho/src/vestige/vestige.h b/dpf/distrho/src/vestige/vestige.h deleted file mode 100644 index 56135fd..0000000 --- a/dpf/distrho/src/vestige/vestige.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * IMPORTANT: The author of DPF has no connection with the - * author of the VeSTige VST-compatibility header, has had no - * involvement in its creation. - * - * The VeSTige header is included in this package in the good-faith - * belief that it has been cleanly and legally reverse engineered - * without reference to the official VST SDK and without its - * developer(s) having agreed to the VST SDK license agreement. - */ - -/* - * simple header to allow VeSTige compilation and eventually work - * - * Copyright (c) 2006 Javier Serrano Polo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program (see COPYING); if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - */ -#include -#ifndef _VESTIGE_H -#define _VESTIGE_H - -#define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ - ( ( (int) b ) << 16 ) | \ - ( ( (int) c ) << 8 ) | \ - ( ( (int) d ) << 0 ) ) - -#define audioMasterAutomate 0 -#define audioMasterVersion 1 -#define audioMasterCurrentId 2 -#define audioMasterIdle 3 -#define audioMasterPinConnected 4 -// unsupported? 5 -#define audioMasterWantMidi 6 -#define audioMasterGetTime 7 -#define audioMasterProcessEvents 8 -#define audioMasterSetTime 9 -#define audioMasterTempoAt 10 -#define audioMasterGetNumAutomatableParameters 11 -#define audioMasterGetParameterQuantization 12 -#define audioMasterIOChanged 13 -#define audioMasterNeedIdle 14 -#define audioMasterSizeWindow 15 -#define audioMasterGetSampleRate 16 -#define audioMasterGetBlockSize 17 -#define audioMasterGetInputLatency 18 -#define audioMasterGetOutputLatency 19 -#define audioMasterGetPreviousPlug 20 -#define audioMasterGetNextPlug 21 -#define audioMasterWillReplaceOrAccumulate 22 -#define audioMasterGetCurrentProcessLevel 23 -#define audioMasterGetAutomationState 24 -#define audioMasterOfflineStart 25 -#define audioMasterOfflineRead 26 -#define audioMasterOfflineWrite 27 -#define audioMasterOfflineGetCurrentPass 28 -#define audioMasterOfflineGetCurrentMetaPass 29 -#define audioMasterSetOutputSampleRate 30 -// unsupported? 31 -#define audioMasterGetSpeakerArrangement 31 // deprecated in 2.4? -#define audioMasterGetVendorString 32 -#define audioMasterGetProductString 33 -#define audioMasterGetVendorVersion 34 -#define audioMasterVendorSpecific 35 -#define audioMasterSetIcon 36 -#define audioMasterCanDo 37 -#define audioMasterGetLanguage 38 -#define audioMasterOpenWindow 39 -#define audioMasterCloseWindow 40 -#define audioMasterGetDirectory 41 -#define audioMasterUpdateDisplay 42 -#define audioMasterBeginEdit 43 -#define audioMasterEndEdit 44 -#define audioMasterOpenFileSelector 45 -#define audioMasterCloseFileSelector 46 // currently unused -#define audioMasterEditFile 47 // currently unused -#define audioMasterGetChunkFile 48 // currently unused -#define audioMasterGetInputSpeakerArrangement 49 // currently unused - -#define effFlagsHasEditor 1 -#define effFlagsCanReplacing (1 << 4) // very likely -#define effFlagsIsSynth (1 << 8) // currently unused - -#define effOpen 0 -#define effClose 1 -#define effSetProgram 2 -#define effGetProgram 3 -#define effGetProgramName 5 -#define effGetParamName 8 -#define effSetSampleRate 10 -#define effSetBlockSize 11 -#define effMainsChanged 12 -#define effEditGetRect 13 -#define effEditOpen 14 -#define effEditClose 15 -#define effEditIdle 19 -#define effEditTop 20 -#define effProcessEvents 25 -#define effGetPlugCategory 35 -#define effGetEffectName 45 -#define effGetVendorString 47 -#define effGetProductString 48 -#define effGetVendorVersion 49 -#define effCanDo 51 -#define effIdle 53 -#define effGetParameterProperties 56 -#define effGetVstVersion 58 -#define effShellGetNextPlugin 70 -#define effStartProcess 71 -#define effStopProcess 72 - -#define effBeginSetProgram 67 -#define effEndSetProgram 68 - -#ifdef WORDS_BIGENDIAN -// "VstP" -#define kEffectMagic 0x50747356 -#else -// "PtsV" -#define kEffectMagic 0x56737450 -#endif - -#define kVstLangEnglish 1 -#define kVstMidiType 1 - -struct RemoteVstPlugin; - -#define kVstTransportChanged 1 -#define kVstTransportPlaying (1 << 1) -#define kVstTransportCycleActive (1 << 2) -#define kVstTransportRecording (1 << 3) - -#define kVstAutomationWriting (1 << 6) -#define kVstAutomationReading (1 << 7) - -#define kVstNanosValid (1 << 8) -#define kVstPpqPosValid (1 << 9) -#define kVstTempoValid (1 << 10) -#define kVstBarsValid (1 << 11) -#define kVstCyclePosValid (1 << 12) -#define kVstTimeSigValid (1 << 13) -#define kVstSmpteValid (1 << 14) -#define kVstClockValid (1 << 15) - -struct _VstMidiEvent -{ - // 00 - int type; - // 04 - int byteSize; - // 08 - int deltaFrames; - // 0c? - int flags; - // 10? - int noteLength; - // 14? - int noteOffset; - // 18 - char midiData[4]; - // 1c? - char detune; - // 1d? - char noteOffVelocity; - // 1e? - char reserved1; - // 1f? - char reserved2; -}; - -typedef struct _VstMidiEvent VstMidiEvent; - - -struct _VstEvent -{ - char dump[sizeof (VstMidiEvent)]; - -}; - -typedef struct _VstEvent VstEvent; - -struct _VstEvents -{ - // 00 - int numEvents; - // 04 - void *reserved; - // 08 - VstEvent * events[2]; -}; - -enum Vestige2StringConstants -{ - VestigeMaxNameLen = 64, - VestigeMaxLabelLen = 64, - VestigeMaxShortLabelLen = 8, - VestigeMaxCategLabelLen = 24, - VestigeMaxFileNameLen = 100 -}; - - -enum VstPlugCategory -{ - kPlugCategUnknown = 0, - kPlugCategEffect, - kPlugCategSynth, - kPlugCategAnalysis, - kPlugCategMastering, - kPlugCategSpacializer, - kPlugCategRoomFx, - kPlugSurroundFx, - kPlugCategRestoration, - kPlugCategOfflineProcess, - kPlugCategShell, - kPlugCategGenerator, - kPlugCategMaxCount -}; - -typedef struct _VstEvents VstEvents; - -struct _VstParameterProperties -{ - float stepFloat; /* float step */ - float smallStepFloat; /* small float step */ - float largeStepFloat; /* large float step */ - char label[VestigeMaxLabelLen]; /* parameter label */ - int32_t flags; /* @see VstParameterFlags */ - int32_t minInteger; /* integer minimum */ - int32_t maxInteger; /* integer maximum */ - int32_t stepInteger; /* integer step */ - int32_t largeStepInteger; /* large integer step */ - char shortLabel[VestigeMaxShortLabelLen]; /* short label, recommended: 6 + delimiter */ - int16_t displayIndex; /* index where this parameter should be displayed (starting with 0) */ - int16_t category; /* 0: no category, else group index + 1 */ - int16_t numParametersInCategory; /* number of parameters in category */ - int16_t reserved; /* zero */ - char categoryLabel[VestigeMaxCategLabelLen]; /* category label, e.g. "Osc 1" */ - char future[16]; /* reserved for future use */ -}; - -typedef struct _VstParameterProperties VstParameterProperties; - -enum VstParameterFlags -{ - kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */ - kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */ - kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */ - kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */ - kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */ - kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */ - kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */ -}; - -struct _AEffect -{ - // Never use virtual functions!!! - // 00-03 - int magic; - // dispatcher 04-07 - intptr_t (* dispatcher) (struct _AEffect *, int, int, intptr_t, void *, float); - // process, quite sure 08-0b - void (* process) (struct _AEffect *, float **, float **, int); - // setParameter 0c-0f - void (* setParameter) (struct _AEffect *, int, float); - // getParameter 10-13 - float (* getParameter) (struct _AEffect *, int); - // programs 14-17 - int numPrograms; - // Params 18-1b - int numParams; - // Input 1c-1f - int numInputs; - // Output 20-23 - int numOutputs; - // flags 24-27 - int flags; - // Fill somewhere 28-2b - void *ptr1; - void *ptr2; - int initialDelay; - // Zeroes 30-33 34-37 38-3b - char empty2[4 + 4]; - // 1.0f 3c-3f - float unkown_float; - // An object? pointer 40-43 - void *object; - // Zeroes 44-47 - void *user; - // Id 48-4b - int32_t uniqueID; - // plugin version 4c-4f - int32_t version; - // processReplacing 50-53 - void (* processReplacing) (struct _AEffect *, float **, float **, int); -}; - -typedef struct _AEffect AEffect; - -typedef struct _VstTimeInfo -{ - /* info from online documentation of VST provided by Steinberg */ - - double samplePos; - double sampleRate; - double nanoSeconds; - double ppqPos; - double tempo; - double barStartPos; - double cycleStartPos; - double cycleEndPos; - int32_t timeSigNumerator; - int32_t timeSigDenominator; - int32_t smpteOffset; - int32_t smpteFrameRate; - int32_t samplesToNextClock; - int32_t flags; - -} VstTimeInfo; - -typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); - -#endif diff --git a/dpf/distrho/src/xaymar-vst2/LICENSE b/dpf/distrho/src/xaymar-vst2/LICENSE new file mode 100644 index 0000000..5c85a6d --- /dev/null +++ b/dpf/distrho/src/xaymar-vst2/LICENSE @@ -0,0 +1,11 @@ +Copyright 2020 Michael Fabian 'Xaymar' Dirks + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dpf/distrho/src/xaymar-vst2/README.md b/dpf/distrho/src/xaymar-vst2/README.md new file mode 100644 index 0000000..025ea27 --- /dev/null +++ b/dpf/distrho/src/xaymar-vst2/README.md @@ -0,0 +1,21 @@ +# About the Project +This is a completely "clean room" untainted reverse engineered "SDK" for the VST 2.x interface. It was reverse engineered from binaries where no license restricting the reverse engineering was attached, or where the legal system explicitly allowed reverse engineering for the purpose of interoperability. + +# Frequently Asked Questions +## Is this legal? Can I use this in my own product? +**Disclaimer:** I am not a lawyer. The information presented below is purely from available copyright laws that I could find about this topic. You should always consult with a lawyer first before including this in your product. + +As this only enables interoperability with existing VST 2.x programs and addons, it is considered to be reverse engineering in the name of interoperability. In most of the developed world, this is considered completely legal and is fine to be used by anyone, as long as it is not the only function of the product. + +Note that this does not grant any patent licenses, nor does it grant you any right to use trademarks in the names. That could mean that you can't advertise your product as having support for VST, and can't use VST in the name or presentation of the product at all unless you have permission to do so. + +## Why recreate an SDK for something officially abandoned by the creators? +There is a ton of software that is only capable of loading VST2.x audio effects, and Steinberg has made no effort to create a VST3-to-VST2-adapter for that software. Notable software includes Audacity and OBS Studio, which both likely felt restricted by the license additions Steinberg added to the GPL license. + +## How did you reverse engineer this? +The reverse engineering was done with various tools (mostly disassemblers to x86 assembly code), hooking into system APIs, attempting to mimic functionality through observation and testing, and other methods. Primarily Visual Studio Code was used to write the header files, and Visual Studio 2019 Express was used to create fake VST plugins/hosts to figure out actual behavior. + +### Which binaries were disassembled? +* A fake VST2 host (using this header) was created to verify against existing plugins. +* A fake VST2 plugin (using this header) was created to verify against existing hosts. +* OBS Studio and Audacity were used to verify compatability between closed source and open source VST hosts. diff --git a/dpf/distrho/src/xaymar-vst2/vst.h b/dpf/distrho/src/xaymar-vst2/vst.h new file mode 100644 index 0000000..b6df35e --- /dev/null +++ b/dpf/distrho/src/xaymar-vst2/vst.h @@ -0,0 +1,1012 @@ +// This was created from released VST2.x plugins, and is technically under the 2-clause BSD license. +// Depending on which country you are in, Steinberg can do fuck all about this. Notable countries for +// this are most members of the United States of America, the entirety of Europe, Japan, and Russia. +// Consult a lawyer if you don't know if clean room reverse engineering is allowed in your country. + +// See README.md for all information. + +// Known additional information: +// - Function call standard seems to be stdcall. +// - Everything is aligned to 8 bytes. + +// VST Versioning: +// - Base-10, thus can't store many version numbers. +// - Always four components, with the major one being able to store the most numbers. +// - Format is A...ABCD, so 1.2.3.4 would turn into 1234. + +#pragma once +#ifndef VST2SDK_VST_H +#define VST2SDK_VST_H + +#define VST_FUNCTION_INTERFACE __cdecl +#define VST_ALIGNMENT 8 +#define VST_MAGICNUMBER 'VstP' + +// Common VST buffer lengths: +// 8: OpCodes(GetLabel, GetName, GetValue) +#define VST_BUFFER_8 8 +// 16: +#define VST_BUFFER_16 16 +// 24: OpCodes? +#define VST_BUFFER_24 24 +// 32: OpCodes(EffectName) +#define VST_BUFFER_32 32 +#define VST_EFFECT_BUFFER_SIZE 32 +// 64: OpCodes(ProductName, VendorName) +#define VST_BUFFER_64 64 +#define VST_VENDOR_BUFFER_SIZE VST_BUFFER_64 +#define VST_PRODUCT_BUFFER_SIZE VST_BUFFER_64 +#define VST_NAME_BUFFER_SIZE VST_BUFFER_64 +// 100: +#define VST_BUFFER_100 100 + +#define VST_MAX_CHANNELS 32 // Couldn't find any audio editing software which would attempt to add more channels. + +#pragma pack(push, VST_ALIGNMENT) + +#ifdef __cplusplus +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +#include +#else +#include +#endif +extern "C" { +#else +#include +#endif + +/******************************************************************************* +|* Enumeration +|*/ +enum VST_VERSION { + VST_VERSION_1 = 0, // Anything before 2.0, used by official plug-ins. + VST_VERSION_1_0_0_0 = 1000, // 1.0, used by some third-party plug-ins. + VST_VERSION_1_1_0_0 = 1100, // 1.1, used by some third-party plug-ins. + VST_VERSION_2 = 2, // 2.0, used by official plug-ins. + VST_VERSION_2_0_0_0 = 2000, // 2.0, used by some third-party plug-ins. + VST_VERSION_2_1_0_0 = 2100, // 2.1 + VST_VERSION_2_2_0_0 = 2200, // 2.2 + VST_VERSION_2_3_0_0 = 2300, // 2.3 + VST_VERSION_2_4_0_0 = 2400, // 2.4 + + // Pad to force 32-bit number. + _VST_VERSION_PAD = 0xFFFFFFFFul, +}; + +enum VST_CATEGORY { + VST_CATEGORY_UNCATEGORIZED = 0x00, + VST_CATEGORY_01 = 0x01, + VST_CATEGORY_02 = 0x02, + VST_CATEGORY_03 = 0x03, + VST_CATEGORY_04 = 0x04, + VST_CATEGORY_05 = 0x05, + VST_CATEGORY_06 = 0x06, + VST_CATEGORY_07 = 0x07, + VST_CATEGORY_RESTORATION = 0x08, // Denoising and similar effects. + VST_CATEGORY_09 = 0x09, + VST_CATEGORY_CONTAINER = 0x0A, // Plugin contains more than one Plugin. + VST_CATEGORY_0B = 0x0B, + VST_CATEGORY_MAX, // Not part of specification, marks maximum category. + + // Pad to force 32-bit number. + _VST_CATEGORY_PAD = 0xFFFFFFFFul, +}; + +enum VST_EFFECT_OPCODE { + /* Create/Initialize the effect (if it has not been created already). + * + * @return Always 0. + */ + VST_EFFECT_OPCODE_00 = 0x00, + VST_EFFECT_OPCODE_CREATE = 0x00, + VST_EFFECT_OPCODE_INITIALIZE = 0x00, + + /* Destroy the effect (if there is any) and free its memory. + * + * This should destroy the actual object created by VST_ENTRYPOINT. + * + * @return Always 0. + */ + VST_EFFECT_OPCODE_01 = 0x01, + VST_EFFECT_OPCODE_DESTROY = 0x01, + + /* Set Program + * + * + */ + VST_EFFECT_OPCODE_02 = 0x02, + + /* Get Program + * + * + */ + VST_EFFECT_OPCODE_03 = 0x03, + + /* Set Program Name + * + * + */ + VST_EFFECT_OPCODE_04 = 0x04, + + /* Get Program Name + * + * "Returns 0. If ptr is valid, sets the first byte of ptr to 0 then returns 0." + */ + VST_EFFECT_OPCODE_05 = 0x05, + + /* Get the value? label for the parameter. + * + * @param p_int1 Parameter index. + * @param p_ptr 'char[8]' + * @return 0 on success, 1 on failure. + */ + VST_EFFECT_OPCODE_06 = 0x06, + VST_EFFECT_OPCODE_PARAM_GETLABEL = 0x06, + + /* Get the string value for the parameter. + * + * @param p_int1 Parameter index. + * @param p_ptr 'char[8]' + * @return 0 on success, 1 on failure. + */ + VST_EFFECT_OPCODE_07 = 0x07, + VST_EFFECT_OPCODE_PARAM_GETVALUE = 0x07, + + /* Get the name for the parameter. + * + * @param p_int1 Parameter index. + * @param p_ptr 'char[8]' + * @return 0 on success, 1 on failure. + */ + VST_EFFECT_OPCODE_08 = 0x08, + VST_EFFECT_OPCODE_PARAM_GETNAME = 0x08, + + /* + * + * + */ + VST_EFFECT_OPCODE_09 = 0x09, + + /* Set the new sample rate for the plugin to use. + * + * @param p_float New sample rate as a float (double on 64-bit because register upgrades). + */ + VST_EFFECT_OPCODE_0A = 0x0A, + VST_EFFECT_OPCODE_SETSAMPLERATE = 0x0A, + VST_EFFECT_OPCODE_SET_SAMPLE_RATE = 0x0A, + + /* Sets the block size, which is the maximum number of samples passed into the effect via process calls. + * + * @param p_int2 The maximum number of samples to be passed in. + */ + VST_EFFECT_OPCODE_0B = 0x0B, + VST_EFFECT_OPCODE_SETBLOCKSIZE = 0x0B, + VST_EFFECT_OPCODE_SET_BLOCK_SIZE = 0x0B, + + /* Effect processing should be suspended/paused. + * + * Unclear if this is should result in a flush of buffers. + * + * @param p_int2 0 if the effect should suspend processing, 1 if it should resume. + */ + VST_EFFECT_OPCODE_0C = 0x0C, + VST_EFFECT_OPCODE_SUSPEND = 0x0C, + + /* Retrieve the client rect size of the plugins window. + * If no window has been created, returns the default rect. + * + * @param p_ptr Pointer of type 'struct vst_rect*'. + * @return On success, returns 1 and updates p_ptr to the rect. On failure, returns 0. + */ + VST_EFFECT_OPCODE_0D = 0x0D, + VST_EFFECT_OPCODE_WINDOW_GETRECT = 0x0D, + + /* Create the window for the plugin. + * + * @param p_ptr HWND of the parent window. + * @return 0 on failure, or HWND on success. + */ + VST_EFFECT_OPCODE_0E = 0x0E, + VST_EFFECT_OPCODE_WINDOW_CREATE = 0x0E, + + /* Destroy the plugins window. + * + * @return Always 0. + */ + VST_EFFECT_OPCODE_0F = 0x0F, + VST_EFFECT_OPCODE_WINDOW_DESTROY = 0x0F, + + /* + * + * + */ + VST_EFFECT_OPCODE_10 = 0x10, + + /* + * + * + */ + VST_EFFECT_OPCODE_11 = 0x11, + + /* + * + * + */ + VST_EFFECT_OPCODE_12 = 0x12, + + /* + * + * + */ + VST_EFFECT_OPCODE_13 = 0x13, + + /* + * + * + */ + VST_EFFECT_OPCODE_14 = 0x14, + + /* + * + * + */ + VST_EFFECT_OPCODE_15 = 0x15, + + /* Always returns the FourCC 'NvEF' (0x4E764566). + */ + VST_EFFECT_OPCODE_16 = 0x16, + + /* Get Chunk + * + * + */ + VST_EFFECT_OPCODE_17 = 0x17, + + /* Set Chunk + * + * + */ + VST_EFFECT_OPCODE_18 = 0x18, + + // VST2.x starts here. + + /* + * + * + */ + VST_EFFECT_OPCODE_19 = 0x19, + + /* Can the parameter be automated? + * + * @param p_int1 Index of the parameter. + * @return 1 if the parameter can be automated, otherwise 0. + */ + VST_EFFECT_OPCODE_1A = 0x1A, + VST_EFFECT_OPCODE_PARAM_ISAUTOMATABLE = 0x1A, + + /* + * + * + */ + VST_EFFECT_OPCODE_1B = 0x1B, + + /* + * + * + */ + VST_EFFECT_OPCODE_1C = 0x1C, + + /* + * + * + */ + VST_EFFECT_OPCODE_1D = 0x1D, // See VST_EFFECT_OPCODE_05 + + /* + * + * + */ + VST_EFFECT_OPCODE_1E = 0x1E, + + /* Input connected. + * + * + */ + VST_EFFECT_OPCODE_1F = 0x1F, + + /* Input disconnected. + * + * + */ + VST_EFFECT_OPCODE_20 = 0x20, + + /* Retrieve the name of the input channel at the given index. + * + * @param p_int1 Index of the input to get the name for. + * @param p_ptr Pointer to a char* buffer able to hold at minimum 20 characters. Might need to be 32 even. + * @return 0 on failure, 1 on success. + */ + VST_EFFECT_OPCODE_21 = 0x21, + VST_EFFECT_OPCODE_INPUT_GETCHANNELNAME = 0x21, + VST_EFFECT_OPCODE_INPUT_CHANNEL_NAME = 0x21, + + /* Retrieve the name of the output channel at the given index. + * + * @param p_int1 Index of the output to get the name for. + * @param p_ptr Pointer to a char* buffer able to hold at minimum 20 characters. Might need to be 32 even. + * @return 0 on failure, 1 on success. + */ + VST_EFFECT_OPCODE_22 = 0x22, + VST_EFFECT_OPCODE_OUTPUT_GETCHANNELNAME = 0x22, + VST_EFFECT_OPCODE_OUTPUT_CHANNEL_NAME = 0x22, + + /* Retrieve category of this effect. + * + * @return The category that this effect is in, see VST_CATEGORY. + */ + VST_EFFECT_OPCODE_23 = 0x23, + VST_EFFECT_OPCODE_EFFECT_CATEGORY = 0x23, + + /* + * + * + */ + VST_EFFECT_OPCODE_24 = 0x24, + + /* + * + * + */ + VST_EFFECT_OPCODE_25 = 0x25, + + /* + * + * + */ + VST_EFFECT_OPCODE_26 = 0x26, + + /* + * + * + */ + VST_EFFECT_OPCODE_27 = 0x27, + + /* + * + * + */ + VST_EFFECT_OPCODE_28 = 0x28, + + /* + * + * + */ + VST_EFFECT_OPCODE_29 = 0x29, + + /* Set the speaker arrangement + * + * @param p_int2 (vst_speaker_arrangement*) Pointer to a pointer to the speaker arrangement for the input. + * @param p_ptr (vst_speaker_arrangement*) Pointer to a pointer to the speaker arrangement for the output. + */ + VST_EFFECT_OPCODE_2A = 0x2A, + VST_EFFECT_OPCODE_SET_SPEAKER_ARRANGEMENT = 0x2A, + + /* + * + * + */ + VST_EFFECT_OPCODE_2B = 0x2B, + + /* Enable/Disable bypassing the effect. + * + * @param p_int2 Zero if bypassing the effect is disabled, otherwise 1. + */ + VST_EFFECT_OPCODE_2C = 0x2C, + VST_EFFECT_OPCODE_BYPASS = 0x2C, + + /* Retrieve the effect name into the ptr buffer. + * + * @param p_ptr char[64] Buffer containing a zero-terminated effect information string. May be shorter than 64 bytes on older hosts. + * @return Always 0, even on failure. + */ + VST_EFFECT_OPCODE_2D = 0x2D, + VST_EFFECT_OPCODE_GETNAME = 0x2D, + VST_EFFECT_OPCODE_EFFECT_NAME = 0x2D, + + /* Translate an error code to a string. + * + * @param p_ptr char[256] Buffer that should contain a zero-terminated error string. + */ + VST_EFFECT_OPCODE_2E = 0x2E, + VST_EFFECT_OPCODE_TRANSLATE_ERROR = 0x2E, + + /* Retrieve the vendor name into the ptr buffer. + * + * @param p_ptr char[64] Buffer containing a zero-terminated vendor information string. May be shorter than 64 bytes on older hosts. + * @return Always 0, even on failure. + */ + VST_EFFECT_OPCODE_2F = 0x2F, + VST_EFFECT_OPCODE_GETVENDOR = 0x2F, + VST_EFFECT_OPCODE_VENDOR_NAME = 0x2F, + + /* See VST_EFFECT_OPCODE_GETNAME + * + * Rarely used, if at all even supported. Not sure what the purpose of this is even. + */ + VST_EFFECT_OPCODE_30 = 0x30, + VST_EFFECT_OPCODE_GETNAME2 = 0x30, + VST_EFFECT_OPCODE_PRODUCT_NAME = 0x30, + + /* Retrieve the vendor version in return value. + * + * @return Version. + */ + VST_EFFECT_OPCODE_31 = 0x31, + VST_EFFECT_OPCODE_GETVENDORVERSION = 0x31, + VST_EFFECT_OPCODE_VENDOR_VERSION = 0x31, + + /* User defined OP Code, for custom interaction. + * + */ + VST_EFFECT_OPCODE_32 = 0x32, + VST_EFFECT_OPCODE_CUSTOM = 0x32, + + /* Test for support of a specific named feature. + * + * @param p_ptr Pointer to a zero-terminated buffer containing the feature name. + * @return Non-zero if the feature is supported, otherwise 0. + */ + VST_EFFECT_OPCODE_33 = 0x33, + VST_EFFECT_OPCODE_SUPPORTS = 0x33, + + /* Number of samples that are at the tail at the end of playback. + * + * @return 0 or 1 for no tail, > 1 for number of samples to tail. + */ + VST_EFFECT_OPCODE_34 = 0x34, + VST_EFFECT_OPCODE_GETTAILSAMPLES = 0x34, + VST_EFFECT_OPCODE_TAIL_SAMPLES = 0x34, + + /* + * + * + */ + VST_EFFECT_OPCODE_35 = 0x35, + + /* + * + * + */ + VST_EFFECT_OPCODE_36 = 0x36, + + /* + * + * + */ + VST_EFFECT_OPCODE_37 = 0x37, + + /* + * + * + */ + VST_EFFECT_OPCODE_38 = 0x38, + + /* Parameter Properties + * + * @param p_ptr vst_parameter_properties* + * @return 1 if supported, otherwise 0. + */ + VST_EFFECT_OPCODE_39 = 0x39, + VST_EFFECT_OPCODE_GET_PARAMETER_PROPERTIES = VST_EFFECT_OPCODE_39, + + /* Retrieve the VST Version supported. + * + * @return Return 0 for <2.0, 2 for 2.0, 2100 for 2.1, 2200 for 2.2, 2300 for 2.3, etc. + */ + VST_EFFECT_OPCODE_3A = 0x3A, + VST_EFFECT_OPCODE_VST_VERSION = 0x3A, + + // VST 2.1 or later + + /* + * + * + */ + VST_EFFECT_OPCODE_3B = 0x3B, + + /* + * + * + */ + VST_EFFECT_OPCODE_3C = 0x3C, + + /* + * + * + */ + VST_EFFECT_OPCODE_3D = 0x3D, + + /* + * + * + */ + VST_EFFECT_OPCODE_3E = 0x3E, + + /* + * + * + */ + VST_EFFECT_OPCODE_3F = 0x3F, + + /* + * + * + */ + VST_EFFECT_OPCODE_40 = 0x40, + + /* + * + * + */ + VST_EFFECT_OPCODE_41 = 0x41, + + /* + * + * + */ + VST_EFFECT_OPCODE_42 = 0x42, + + /* + * + * + */ + VST_EFFECT_OPCODE_43 = 0x43, + + /* + * + * + */ + VST_EFFECT_OPCODE_44 = 0x44, + + // VST 2.3 or later + + /* Retrieve the speaker arrangement. + * + * @param p_int2 (vst_speaker_arrangement**) Pointer to a pointer to the speaker arrangement for the input. + * @param p_ptr (vst_speaker_arrangement**) Pointer to a pointer to the speaker arrangement for the output. + */ + VST_EFFECT_OPCODE_45 = 0x45, + VST_EFFECT_OPCODE_GET_SPEAKER_ARRANGEMENT = 0x45, + + /* + * + * + */ + VST_EFFECT_OPCODE_46 = 0x46, + + /* Begin processing of audio. + * + * + * + */ + VST_EFFECT_OPCODE_PROCESS_BEGIN = 0x47, + + /* End processing of audio. + * + * + * + */ + VST_EFFECT_OPCODE_PROCESS_END = 0x48, + + /* + * + * + */ + VST_EFFECT_OPCODE_49 = 0x49, + + /* + * + * + */ + VST_EFFECT_OPCODE_4A = 0x4A, + + /* + * + * + */ + VST_EFFECT_OPCODE_4B = 0x4B, + + /* + * + * + */ + VST_EFFECT_OPCODE_4C = 0x4C, + + // VST 2.4 or later + + /* + * + * + */ + VST_EFFECT_OPCODE_4D = 0x4D, + + /* + * + * + */ + VST_EFFECT_OPCODE_4E = 0x4E, + + /* + * + * + */ + VST_EFFECT_OPCODE_4F = 0x4F, + + // Highest number of known OPCODE. + VST_EFFECT_OPCODE_MAX, + + // Pad to force 32-bit number. + _VST_EFFECT_OPCODE_PAD = 0xFFFFFFFFul, +}; + +enum VST_HOST_OPCODE { + /* + * @param int1 -1 or Parameter Index + * @return Expected to return... something. + */ + VST_HOST_OPCODE_00 = 0x00, // cb(vst, 0x00, ?, 0, 0); + VST_HOST_OPCODE_01 = 0x01, + VST_HOST_OPCODE_02 = 0x02, // bool cb(0, 0x02, 0, 0, 0); + VST_HOST_OPCODE_03 = 0x03, + VST_HOST_OPCODE_04 = 0x04, + VST_HOST_OPCODE_05 = 0x05, + VST_HOST_OPCODE_06 = 0x06, + VST_HOST_OPCODE_07 = 0x07, + VST_HOST_OPCODE_08 = 0x08, + VST_HOST_OPCODE_09 = 0x09, + VST_HOST_OPCODE_0A = 0x0A, + VST_HOST_OPCODE_0B = 0x0B, + VST_HOST_OPCODE_0C = 0x0C, + VST_HOST_OPCODE_0D = 0x0D, + VST_HOST_OPCODE_0E = 0x0E, + VST_HOST_OPCODE_0F = 0x0F, + VST_HOST_OPCODE_10 = 0x10, + VST_HOST_OPCODE_11 = 0x11, + VST_HOST_OPCODE_12 = 0x12, + VST_HOST_OPCODE_13 = 0x13, + VST_HOST_OPCODE_14 = 0x14, + VST_HOST_OPCODE_15 = 0x15, + VST_HOST_OPCODE_16 = 0x16, + VST_HOST_OPCODE_17 = 0x17, + VST_HOST_OPCODE_18 = 0x18, + VST_HOST_OPCODE_19 = 0x19, + VST_HOST_OPCODE_1A = 0x1A, + VST_HOST_OPCODE_1B = 0x1B, + VST_HOST_OPCODE_1C = 0x1C, + VST_HOST_OPCODE_1D = 0x1D, + VST_HOST_OPCODE_1E = 0x1E, + VST_HOST_OPCODE_1F = 0x1F, + VST_HOST_OPCODE_20 = 0x20, + VST_HOST_OPCODE_21 = 0x21, + VST_HOST_OPCODE_22 = 0x22, + VST_HOST_OPCODE_23 = 0x23, + VST_HOST_OPCODE_24 = 0x24, + VST_HOST_OPCODE_25 = 0x25, + VST_HOST_OPCODE_26 = 0x26, + VST_HOST_OPCODE_27 = 0x27, + VST_HOST_OPCODE_28 = 0x28, + VST_HOST_OPCODE_29 = 0x29, + VST_HOST_OPCODE_2A = 0x2A, + + /* Parameter gained focus. + * + * @param int1 Parameter index. + */ + VST_HOST_OPCODE_2B = 0x2B, + + /* Parameter lost focus. + * + * @param int1 Parameter index. + */ + VST_HOST_OPCODE_2C = 0x2C, + + VST_HOST_OPCODE_2D = 0x2D, + VST_HOST_OPCODE_2E = 0x2E, + VST_HOST_OPCODE_2F = 0x2F, + + // Highest number of known OPCODE. + VST_HOST_OPCODE_MAX, + + // Pad to force 32-bit number. + _VST_HOST_OPCODE_PAD = 0xFFFFFFFFul, +}; + +enum VST_ARRANGEMENT_TYPE { + /* Custom speaker arrangement. + * + * Accidentally discovered through random testing. + */ + VST_ARRANGEMENT_TYPE_CUSTOM = -2, + + /* Unknown/Empty speaker layout. + * + */ + VST_ARRANGEMENT_TYPE_UNKNOWN = -1, + + /* Mono + */ + VST_ARRANGEMENT_TYPE_MONO = 0, + + /* Stereo + */ + VST_ARRANGEMENT_TYPE_STEREO = 1, + + /* 5.1 + */ + VST_ARRANGEMENT_TYPE_5_1 = 0x0F, + + // Pad to force 32-bit number. + _VST_ARRANGEMENT_TYPE_PAD = 0xFFFFFFFFul, +}; + +enum VST_SPEAKER_TYPE { + VST_SPEAKER_TYPE_MONO = 0, + VST_SPEAKER_TYPE_LEFT = 1, + VST_SPEAKER_TYPE_RIGHT = 2, + VST_SPEAKER_TYPE_CENTER = 3, + VST_SPEAKER_TYPE_LFE = 4, + VST_SPEAKER_TYPE_LEFT_SIDE = 5, + VST_SPEAKER_TYPE_RIGHT_SIDE = 6, + + // Pad to force 32-bit number. + _VST_SPEAKER_TYPE_PAD = 0xFFFFFFFFul, +}; + +enum VST_PARAMETER_FLAGS { + /** + * Parameter is an on/off switch. + */ + VST_PARAMETER_FLAGS_SWITCH = 1, + /** + * Limits defined by integers. + */ + VST_PARAMETER_FLAGS_INTEGER_LIMITS = 1 << 1, + /** + * Uses float steps. + */ + VST_PARAMETER_FLAGS_STEP_FLOAT = 1 << 2, + /** + * Uses integer steps. + */ + VST_PARAMETER_FLAGS_STEP_INT = 1 << 3, + /** + * Respect index variable for display ordering. + */ + VST_PARAMETER_FLAGS_INDEX = 1 << 4, + /** + * Respect category value and names. + */ + VST_PARAMETER_FLAGS_CATEGORY = 1 << 5, + VST_PARAMETER_FLAGS_UNKNOWN6 = 1 << 6, + _VST_PARAMETER_FLAGS_PAD = 0xFFFFFFFFul, +}; + +/******************************************************************************* +|* Structures +|*/ + +struct vst_rect { + int16_t top; + int16_t left; + int16_t bottom; + int16_t right; +}; + +struct vst_effect { + int32_t magic_number; // Should always be VST_MAGICNUMBER + + // 64-bit adds 4-byte padding here to align pointers. + + /* Control the VST through an opcode and up to four parameters. + * + * @param this Pointer to the effect itself. + * @param opcode The opcode to run, see VST_EFFECT_OPCODES. + * @param p_int1 Parameter, see VST_EFFECT_OPCODES. + * @param p_int2 Parameter, see VST_EFFECT_OPCODES. + * @param p_ptr Parameter, see VST_EFFECT_OPCODES. + * @param p_float Parameter, see VST_EFFECT_OPCODES. + */ + intptr_t(VST_FUNCTION_INTERFACE* control)(vst_effect* pthis, VST_EFFECT_OPCODE opcode, int32_t p_int1, + intptr_t p_int2, void* p_ptr, float p_float); + + /* Process the given number of samples in inputs and outputs. + * + * Different to process_float how? Never seen any difference. + * + * @param pthis Pointer to the effect itself. + * @param inputs Pointer to an array of 'const float[samples]' with size numInputs. + * @param outputs Pointer to an array of 'float[samples]' with size numOutputs. + * @param samples Number of samples per channel in inputs. + */ + void(VST_FUNCTION_INTERFACE* process)(vst_effect* pthis, const float* const* inputs, float** outputs, + int32_t samples); + + /* Updates the value for the parameter at the given index, or does nothing if out of bounds. + * + * @param pthis Pointer to the effect itself. + * @param index Parameter index. + * @param value New value for the parameter. + */ + void(VST_FUNCTION_INTERFACE* set_parameter)(vst_effect* pthis, uint32_t index, float value); + + /* Returns the value stored for the parameter at index, or 0 if out of bounds. + * + * @param pthis Pointer to the effect itself. + * @param index Parameter index. + * @return float Value of the parameter. + */ + float(VST_FUNCTION_INTERFACE* get_parameter)(vst_effect* pthis, uint32_t index); + + int32_t num_programs; // Number of possible programs. + int32_t num_params; // Number of possible parameters. + int32_t num_inputs; // Number of inputs. + int32_t num_outputs; // Number of outputs. + + /* Bitflags + * + * Bit Description + * 1 Effect has "Editor" + * 2 Unknown (Found in: ReaDelay) + * 3 Unknown (Found in: ReaDelay) + * 4 Unknown (Found in: ReaDelay) + * 5 Has process_float (Found in: ReaDelay, ReaComp, ReaControlMIDI, ReaStream, ReaFir) + * 6 Unknown (Found in: ReaControlMIDI, ReaStream, ReaFir) + * 10 Unknown (Found in: ReaFir) + * 13 Has process_double (Found in: ReaControlMIDI) + */ + int32_t flags; + + // 64-bit adds 4-byte padding here to align pointers. + + void* _unknown_ptr_00[2]; + + /* Initial delay before processing of samples can actually begin in Samples. + * + * Should be updated before or during handling the 0x47 control call. + */ + int32_t delay; + + int32_t _unknown_int32_00[2]; // Unknown int32_t values. + float _unknown_float_00; // Seems to always be 1.0 + + void* effect_internal; // Pointer to Plugin internal data + void* host_internal; // Pointer to Host internal data. + + /* Id of the plugin. + * + * Due to this not being enough for uniqueness, it should not be used alone + * for indexing. Ideally you want to index like this: + * [unique_id][module_name][version][flags] + * If any of the checks after unique_id fail, you default to the first + * possible choice. + */ + int32_t unique_id; + + /* Plugin version + * + * Unrelated to the minimum VST Version, but often the same. + */ + int32_t version; + + // There is no padding here if everything went right. + + /* Process the given number of single samples in inputs and outputs. + * + * @param pthis Pointer to the effect itself. + * @param inputs Pointer to an array of 'const float[samples]' with size numInputs. + * @param outputs Pointer to an array of 'float[samples]' with size numOutputs. + * @param samples Number of samples per channel in inputs. + */ + void(VST_FUNCTION_INTERFACE* process_float)(vst_effect* pthis, const float* const* inputs, float** outputs, + int32_t samples); + + /* Process the given number of double samples in inputs and outputs. + * + * Used only by 2.4 hosts and plugins, possibly restricted to said version. + * + * @param pthis Pointer to the effect itself. + * @param inputs Pointer to an array of 'const double[samples]' with size numInputs. + * @param outputs Pointer to an array of 'double[samples]' with size numOutputs. + * @param samples Number of samples per channel in inputs. + */ + void(VST_FUNCTION_INTERFACE* process_double)(vst_effect* pthis, const double* const* inputs, double** outputs, + int32_t samples); + + // Everything after this is unknown and was present in reacomp-standalone.dll. + uint8_t _unknown[56]; // 56-bytes of something. Could also just be 52-bytes. +}; + +struct vst_parameter_properties { + float step_f32; + float step_small_f32; + float step_large_f32; + + char name[VST_BUFFER_64]; + + uint32_t flags; + int32_t min_value_i32; + int32_t max_value_i32; + int32_t step_i32; + + char label[VST_BUFFER_8]; + + uint16_t index; + + uint16_t category; + uint16_t num_parameters_in_category; + uint16_t _unknown_00; + + char category_label[VST_BUFFER_24]; + + char _unknown_01[VST_BUFFER_16]; +}; + +struct vst_speaker_properties { + float _unknown_00; // 10.0 if LFE, otherwise random? Never exceeds -PI to PI range. + float _unknown_04; // 10.0 if LFE, otherwise random? Never exceeds -PI to PI range. + float _unknown_08; // 0.0 if LFE, otherwise 1.0. + float _unknown_0C; + char name[VST_BUFFER_64]; + VST_SPEAKER_TYPE type; + + uint8_t _unknown[28]; // Padding detected from testing. +}; + +struct vst_speaker_arrangement { + VST_ARRANGEMENT_TYPE type; // See VST_SPEAKER_ARRANGEMENT_TYPE + int32_t channels; // Number of channels in speakers. + vst_speaker_properties speakers[VST_MAX_CHANNELS]; // Array of speaker properties, actual size defined by channels. +}; + +/* Callback used by the plugin to interface with the host. + * + * @param opcode See VST_HOST_OPCODE + * @param p_str Zero terminated string or null on call. + * @return ? + */ +typedef intptr_t (*vst_host_callback)(vst_effect* plugin, VST_HOST_OPCODE opcode, int32_t p_int1, int64_t p_int2, + void* p_str, int32_t p_int3); + +/* Entry point for VST2.x plugins. + * + * @return A new instance of the VST2.x effect. + */ +#define VST_ENTRYPOINT vst_effect* VSTPluginMain(vst_host_callback callback) +#define VST_ENTRYPOINT_WINDOWS \ + vst_effect* MAIN(vst_host_callback callback) \ + { \ + return VSTPluginMain(callback); \ + } +#define VST_ENTRYPOINT_MACOS \ + vst_effect* main_macho(vst_host_callback callback) \ + { \ + return VSTPluginMain(callback); \ + } + +#ifdef __cplusplus +} +#endif + +// Variable size variant of vst_speaker_arrangement. +#ifdef __cplusplus +template +struct vst_speaker_arrangement_t { + VST_ARRANGEMENT_TYPE type; // See VST_SPEAKER_ARRANGEMENT_TYPE + int32_t channels; // Number of channels in speakers. + vst_speaker_properties speakers[T]; // Array of speaker properties, actual size defined by channels. +}; +#endif + +#pragma pack(pop) + +#endif diff --git a/dpf/dpf.doxygen b/dpf/dpf.doxygen index eb2be59..01ae0f1 100644 --- a/dpf/dpf.doxygen +++ b/dpf/dpf.doxygen @@ -141,7 +141,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -HTML_TIMESTAMP = YES +HTML_TIMESTAMP = NO HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO diff --git a/dpf/utils/package-osx-bundles.sh b/dpf/utils/package-osx-bundles.sh index cb10b56..20d1e1a 100755 --- a/dpf/utils/package-osx-bundles.sh +++ b/dpf/utils/package-osx-bundles.sh @@ -15,12 +15,14 @@ SNAME="$(echo ${NAME} | tr -d ' ' | tr '/' '-')" rm -rf lv2 rm -rf vst2 rm -rf vst3 +rm -rf clap -mkdir lv2 vst2 vst3 +mkdir lv2 vst2 vst3 clap cp -RL *.lv2 lv2/ cp -RL *.vst vst2/ cp -RL *.vst3 vst3/ -rm -rf *.lv2 *.vst *.vst3 +cp -RL *.clap clap/ +rm -rf *.lv2 *.vst *.vst3 *.clap pkgbuild \ --identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ @@ -40,6 +42,12 @@ pkgbuild \ --root "${PWD}/vst3/" \ ../dpf-${SNAME}-vst3bundles.pkg +pkgbuild \ + --identifier "studio.kx.distrho.plugins.${SNAME}.clapbundles" \ + --install-location "/Library/Audio/Plug-Ins/CLAP/" \ + --root "${PWD}/clap/" \ + ../dpf-${SNAME}-clapbundles.pkg + cd .. DPF_UTILS_DIR=$(dirname ${0}) @@ -52,6 +60,7 @@ sed -e "s|@builddir@|${PWD}/build|" \ -e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \ -e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \ -e "s|@vst3bundleref@|dpf-${SNAME}-vst3bundles.pkg|" \ + -e "s|@clapbundleref@|dpf-${SNAME}-clapbundles.pkg|" \ -e "s|@name@|${NAME}|g" \ -e "s|@sname@|${SNAME}|g" \ ${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml diff --git a/dpf/utils/plugin.pkg/package.xml.in b/dpf/utils/plugin.pkg/package.xml.in index 3b4a8a6..ca46e33 100644 --- a/dpf/utils/plugin.pkg/package.xml.in +++ b/dpf/utils/plugin.pkg/package.xml.in @@ -14,9 +14,13 @@ @vst3bundleref@ + + @clapbundleref@ + + diff --git a/plugins/3BandEQ/DistrhoPluginInfo.h b/plugins/3BandEQ/DistrhoPluginInfo.h index 4a50ae9..3c19b58 100644 --- a/plugins/3BandEQ/DistrhoPluginInfo.h +++ b/plugins/3BandEQ/DistrhoPluginInfo.h @@ -17,9 +17,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "3 Band EQ" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandEQ" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "3 Band EQ" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandEQ" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MVerb" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -27,7 +28,8 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:EQPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "equalizer", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:EQPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|EQ" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/3BandEQ/Makefile b/plugins/3BandEQ/Makefile index 872fb2d..998b748 100644 --- a/plugins/3BandEQ/Makefile +++ b/plugins/3BandEQ/Makefile @@ -29,10 +29,7 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += vst2 -TARGETS += vst3 +TARGETS = jack ladspa lv2_sep vst2 vst3 clap ifeq ($(HAVE_CAIRO_OR_OPENGL),true) ifeq ($(HAVE_LIBLO),true) @@ -40,12 +37,6 @@ TARGETS += dssi endif endif -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - all: $(TARGETS) # -------------------------------------------------------------- diff --git a/plugins/3BandSplitter/DistrhoPluginInfo.h b/plugins/3BandSplitter/DistrhoPluginInfo.h index 73990bd..fc66f80 100644 --- a/plugins/3BandSplitter/DistrhoPluginInfo.h +++ b/plugins/3BandSplitter/DistrhoPluginInfo.h @@ -17,9 +17,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "3 Band Splitter" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandSplitter" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "3 Band Splitter" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/3BandSplitter" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MVerb" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -27,7 +28,8 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 6 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:EQPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "equalizer", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:EQPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|EQ" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/3BandSplitter/Makefile b/plugins/3BandSplitter/Makefile index 89985d9..91b90c6 100644 --- a/plugins/3BandSplitter/Makefile +++ b/plugins/3BandSplitter/Makefile @@ -29,10 +29,7 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += vst2 -TARGETS += vst3 +TARGETS = jack ladspa lv2_sep vst2 vst3 clap ifeq ($(HAVE_CAIRO_OR_OPENGL),true) ifeq ($(HAVE_LIBLO),true) @@ -40,12 +37,6 @@ TARGETS += dssi endif endif -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - all: $(TARGETS) # -------------------------------------------------------------- diff --git a/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.cpp b/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.cpp index ee3ecfa..52f5541 100644 --- a/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.cpp +++ b/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.cpp @@ -57,27 +57,27 @@ void DistrhoPluginAmplitudeImposer::initAudioPort(bool input, uint32_t index, Au switch (index) { case 0: + port.name = "Input Left (Audio)"; + port.symbol = "in_left_audio"; + port.groupId = kPortGroupStereo; + break; + case 1: + port.name = "Input Right (Audio)"; + port.symbol = "in_right_audio"; + port.groupId = kPortGroupStereo; + break; + case 2: port.name = "Input Left (Amp Env)"; port.symbol = "in_left_amp"; port.groupId = kPortGroupAmpEnv; port.hints = kAudioPortIsSidechain; break; - case 1: + case 3: port.name = "Input Right (Amp Env)"; port.symbol = "in_right_amp"; port.groupId = kPortGroupAmpEnv; port.hints = kAudioPortIsSidechain; break; - case 2: - port.name = "Input Left (Audio)"; - port.symbol = "in_left_audio"; - port.groupId = kPortGroupAudio; - break; - case 3: - port.name = "Input Right (Audio)"; - port.symbol = "in_right_audio"; - port.groupId = kPortGroupAudio; - break; } } else @@ -127,10 +127,6 @@ void DistrhoPluginAmplitudeImposer::initPortGroup(uint32_t groupId, PortGroup& p portGroup.name = "Amp Env"; portGroup.symbol = "amp_env"; break; - case kPortGroupAudio: - portGroup.name = "Audio"; - portGroup.symbol = "audio"; - break; } } @@ -194,10 +190,10 @@ void DistrhoPluginAmplitudeImposer::activate() void DistrhoPluginAmplitudeImposer::run(const float** inputs, float** outputs, uint32_t frames) { - const float* const in1 = inputs[0]; - const float* const in2 = inputs[1]; - const float* const in3 = inputs[2]; - const float* const in4 = inputs[3]; + const float* const in1 = inputs[0]; + const float* const in2 = inputs[1]; + const float* const env1 = inputs[2]; + const float* const env2 = inputs[3]; /* */ float* const out1 = outputs[0]; /* */ float* const out2 = outputs[1]; @@ -208,26 +204,26 @@ void DistrhoPluginAmplitudeImposer::run(const float** inputs, float** outputs, u for (uint32_t i=0; i ampEnvelope_l) ampEnvelope_l = tmp; else if (tmp < ampEnvelope_l) ampEnvelope_l -= envDecay; - tmp = std::abs(in2[i]); + tmp = std::abs(env2[i]); /**/ if (tmp > ampEnvelope_r) ampEnvelope_r = tmp; else if (tmp < ampEnvelope_r) ampEnvelope_r -= envDecay; // calculate envelope from 2nd two inputs - tmp = std::abs(in3[i]); + tmp = std::abs(in1[i]); /**/ if (tmp > audioEnvelope_l) audioEnvelope_l = tmp; else if (tmp < audioEnvelope_l) audioEnvelope_l -= envDecay; - tmp = std::abs(in4[i]); + tmp = std::abs(in2[i]); /**/ if (tmp > audioEnvelope_r) audioEnvelope_r = tmp; else if (tmp < audioEnvelope_r) @@ -246,26 +242,26 @@ void DistrhoPluginAmplitudeImposer::run(const float** inputs, float** outputs, u // work out whether we need to multiply audio input if (audioEnvelope_l > fThreshold) { - tempin.left = in3[i]; + tempin.left = in1[i]; } else { if (audioEnvelope_l > 0.001f) - tempin.left = in3[i] * (fThreshold/audioEnvelope_l); + tempin.left = in1[i] * (fThreshold/audioEnvelope_l); else - tempin.left = in3[i] * (fThreshold/0.001f); //so it'll decay away smoothly + tempin.left = in1[i] * (fThreshold/0.001f); //so it'll decay away smoothly } if (audioEnvelope_r > fThreshold) { - tempin.right = in4[i]; + tempin.right = in2[i]; } else { if (audioEnvelope_r > 0.001f) - tempin.right = in4[i] * (fThreshold/audioEnvelope_r); + tempin.right = in2[i] * (fThreshold/audioEnvelope_r); else - tempin.right = in4[i] * (fThreshold/0.001f); + tempin.right = in2[i] * (fThreshold/0.001f); } // calculate output diff --git a/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.hpp b/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.hpp index da9c313..b0e0d19 100644 --- a/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.hpp +++ b/plugins/AmplitudeImposer/DistrhoPluginAmplitudeImposer.hpp @@ -42,7 +42,6 @@ public: enum PortGroups { kPortGroupAmpEnv, - kPortGroupAudio, kPortGroupCount }; diff --git a/plugins/AmplitudeImposer/DistrhoPluginInfo.h b/plugins/AmplitudeImposer/DistrhoPluginInfo.h index eadc15a..27e0dbb 100644 --- a/plugins/AmplitudeImposer/DistrhoPluginInfo.h +++ b/plugins/AmplitudeImposer/DistrhoPluginInfo.h @@ -25,9 +25,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Amplitude Imposr" -#define DISTRHO_PLUGIN_URI "http://www.niallmoody.com/ndcplugs/ampimposer.htm" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Amplitude Imposr" +#define DISTRHO_PLUGIN_URI "http://www.niallmoody.com/ndcplugs/ampimposer.htm" +#define DISTRHO_PLUGIN_CLAP_ID "niallmoody.ndcplugs.ampimposer" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -35,7 +36,8 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "utility", "stereo" #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AmplifierPlugin" -#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Dynamics" +#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Dynamics|Stereo" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/AmplitudeImposer/Makefile b/plugins/AmplitudeImposer/Makefile index 974172a..eee2cce 100644 --- a/plugins/AmplitudeImposer/Makefile +++ b/plugins/AmplitudeImposer/Makefile @@ -29,8 +29,10 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types +TARGETS += clap TARGETS += jack TARGETS += ladspa +TARGETS += lv2_sep TARGETS += vst2 TARGETS += vst3 @@ -40,12 +42,6 @@ TARGETS += dssi endif endif -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - all: $(TARGETS) # -------------------------------------------------------------- diff --git a/plugins/CycleShifter/DistrhoPluginInfo.h b/plugins/CycleShifter/DistrhoPluginInfo.h index 1a253cb..edc3583 100644 --- a/plugins/CycleShifter/DistrhoPluginInfo.h +++ b/plugins/CycleShifter/DistrhoPluginInfo.h @@ -25,9 +25,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Cycle Shifter" -#define DISTRHO_PLUGIN_URI "http://www.niallmoody.com/ndcplugs/cycleshifter.htm" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Cycle Shifter" +#define DISTRHO_PLUGIN_URI "http://www.niallmoody.com/ndcplugs/cycleshifter.htm" +#define DISTRHO_PLUGIN_CLAP_ID "niallmoody.ndcplugs.cycleshifter" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -35,4 +36,7 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 1 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "stereo" +#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Stereo" + #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/CycleShifter/Makefile b/plugins/CycleShifter/Makefile index 15be344..8aba6d1 100644 --- a/plugins/CycleShifter/Makefile +++ b/plugins/CycleShifter/Makefile @@ -29,8 +29,10 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types +TARGETS += clap TARGETS += jack TARGETS += ladspa +TARGETS += lv2_sep TARGETS += vst2 TARGETS += vst3 @@ -40,12 +42,6 @@ TARGETS += dssi endif endif -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - all: $(TARGETS) # -------------------------------------------------------------- diff --git a/plugins/Kars/DistrhoPluginInfo.h b/plugins/Kars/DistrhoPluginInfo.h index 7ea4eae..36f3f7d 100644 --- a/plugins/Kars/DistrhoPluginInfo.h +++ b/plugins/Kars/DistrhoPluginInfo.h @@ -17,9 +17,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Kars" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Kars" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Kars" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Kars" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.Kars" #define DISTRHO_PLUGIN_HAS_UI 0 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 diff --git a/plugins/Kars/Makefile b/plugins/Kars/Makefile index 9fab00f..f84b6d4 100644 --- a/plugins/Kars/Makefile +++ b/plugins/Kars/Makefile @@ -23,6 +23,6 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types -all: jack dssi_dsp lv2_dsp vst2 vst3 +all: jack dssi_dsp lv2_dsp vst2 vst3 clap # -------------------------------------------------------------- diff --git a/plugins/MVerb/DistrhoPluginInfo.h b/plugins/MVerb/DistrhoPluginInfo.h index d3b92ad..5f6dd4c 100644 --- a/plugins/MVerb/DistrhoPluginInfo.h +++ b/plugins/MVerb/DistrhoPluginInfo.h @@ -1,7 +1,7 @@ /* * DISTRHO MVerb, a DPF'ied MVerb. * Copyright (c) 2010 Martin Eastwood - * Copyright (C) 2015 Filipe Coelho + * Copyright (C) 2015-2022 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,9 +19,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "MVerb" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MVerb" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "MVerb" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MVerb" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MVerb" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -29,6 +30,7 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "reverb", "stereo" #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Reverb" diff --git a/plugins/MVerb/Makefile b/plugins/MVerb/Makefile index 337780b..aeb93f1 100644 --- a/plugins/MVerb/Makefile +++ b/plugins/MVerb/Makefile @@ -28,11 +28,7 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += lv2_sep -TARGETS += vst2 -TARGETS += vst3 +TARGETS = jack ladspa lv2_sep vst2 vst3 clap ifeq ($(HAVE_DGL),true) ifeq ($(HAVE_LIBLO),true) diff --git a/plugins/Nekobi/DistrhoPluginInfo.h b/plugins/Nekobi/DistrhoPluginInfo.h index a1c2af3..41ed912 100644 --- a/plugins/Nekobi/DistrhoPluginInfo.h +++ b/plugins/Nekobi/DistrhoPluginInfo.h @@ -18,9 +18,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Nekobi" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Nekobi" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Nekobi" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Nekobi" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.Nekobi" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 diff --git a/plugins/Nekobi/Makefile b/plugins/Nekobi/Makefile index 98b5f94..c89dfb1 100644 --- a/plugins/Nekobi/Makefile +++ b/plugins/Nekobi/Makefile @@ -35,24 +35,6 @@ LINK_FLAGS += -pthread # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += dssi_dsp - -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -ifeq ($(HAVE_LIBLO),true) -TARGETS += dssi_ui -endif -endif - -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - -TARGETS += vst2 -TARGETS += vst3 - -all: $(TARGETS) +all: jack dssi lv2_sep vst2 vst3 clap # -------------------------------------------------------------- diff --git a/plugins/PingPongPan/DistrhoPluginInfo.h b/plugins/PingPongPan/DistrhoPluginInfo.h index 47a98c0..4ae5c83 100644 --- a/plugins/PingPongPan/DistrhoPluginInfo.h +++ b/plugins/PingPongPan/DistrhoPluginInfo.h @@ -17,9 +17,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Ping Pong Pan" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/PingPongPan" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Ping Pong Pan" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/PingPongPan" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MVerb" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -27,7 +28,8 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:SpatialPlugin" -#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|EQ" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:SpatialPlugin" +#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Spatial" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/PingPongPan/Makefile b/plugins/PingPongPan/Makefile index 3f7993a..08355eb 100644 --- a/plugins/PingPongPan/Makefile +++ b/plugins/PingPongPan/Makefile @@ -29,10 +29,7 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += vst2 -TARGETS += vst3 +TARGETS = jack ladspa lv2_sep vst2 vst3 clap ifeq ($(HAVE_CAIRO_OR_OPENGL),true) ifeq ($(HAVE_LIBLO),true) @@ -40,12 +37,6 @@ TARGETS += dssi endif endif -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - all: $(TARGETS) # -------------------------------------------------------------- diff --git a/plugins/ProM/DistrhoPluginInfo.h b/plugins/ProM/DistrhoPluginInfo.h index 3024761..eeb474f 100644 --- a/plugins/ProM/DistrhoPluginInfo.h +++ b/plugins/ProM/DistrhoPluginInfo.h @@ -17,9 +17,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "ProM" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/ProM" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "ProM" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/ProM" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.ProM" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_NUM_INPUTS 2 @@ -29,7 +30,8 @@ // required by projectM #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "analyzer", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Analyzer" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/ProM/Makefile b/plugins/ProM/Makefile index 5582d07..74c6a53 100644 --- a/plugins/ProM/Makefile +++ b/plugins/ProM/Makefile @@ -107,6 +107,7 @@ endif # !HAVE_PROJECTM # Do some magic UI_TYPE = opengl3 +USE_CLAP_BUNDLE = true USE_VST2_BUNDLE = true include ../../dpf/Makefile.plugins.mk @@ -205,7 +206,7 @@ LINK_FLAGS += -lpthread # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS = lv2 vst2 vst3 +TARGETS = lv2 vst2 vst3 clap all: $(TARGETS) diff --git a/plugins/SoulForce/DistrhoPluginInfo.h b/plugins/SoulForce/DistrhoPluginInfo.h index 3f0419f..aaf42cb 100644 --- a/plugins/SoulForce/DistrhoPluginInfo.h +++ b/plugins/SoulForce/DistrhoPluginInfo.h @@ -25,9 +25,10 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "Soul Force" -#define DISTRHO_PLUGIN_URI "http://www.niallmoody.com/ndcplugs/soulforce.htm" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "Soul Force" +#define DISTRHO_PLUGIN_URI "http://www.niallmoody.com/ndcplugs/soulforce.htm" +#define DISTRHO_PLUGIN_CLAP_ID "niallmoody.ndcplugs.soulforce" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_IS_RT_SAFE 1 @@ -35,7 +36,8 @@ #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 #define DISTRHO_PLUGIN_WANT_PROGRAMS 1 +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "distortion", "stereo" #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:WaveshaperPlugin" -#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Distortion" +#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Distortion|Stereo" #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/plugins/SoulForce/Makefile b/plugins/SoulForce/Makefile index d965691..23b36f6 100644 --- a/plugins/SoulForce/Makefile +++ b/plugins/SoulForce/Makefile @@ -29,8 +29,10 @@ include ../../dpf/Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types +TARGETS += clap TARGETS += jack TARGETS += ladspa +TARGETS += lv2_sep TARGETS += vst2 TARGETS += vst3 @@ -40,12 +42,6 @@ TARGETS += dssi endif endif -ifeq ($(HAVE_CAIRO_OR_OPENGL),true) -TARGETS += lv2_sep -else -TARGETS += lv2_dsp -endif - all: $(TARGETS) # -------------------------------------------------------------- diff --git a/plugins/bitcrush/DistrhoPluginInfo.h b/plugins/bitcrush/DistrhoPluginInfo.h index 7270445..7023254 100644 --- a/plugins/bitcrush/DistrhoPluginInfo.h +++ b/plugins/bitcrush/DistrhoPluginInfo.h @@ -17,16 +17,18 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "MaBitcrush" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaBitcrush" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "MaBitcrush" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaBitcrush" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MaBitcrush" #define DISTRHO_PLUGIN_HAS_UI 0 #define DISTRHO_PLUGIN_IS_RT_SAFE 0 #define DISTRHO_PLUGIN_NUM_INPUTS 1 #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:DistortionPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "distortion", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:DistortionPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Distortion" #define DISTRHO_PLUGIN_DESCRIPTION "Max Gen Bitcrush example." diff --git a/plugins/bitcrush/Makefile b/plugins/bitcrush/Makefile index 4978acb..e90f392 100644 --- a/plugins/bitcrush/Makefile +++ b/plugins/bitcrush/Makefile @@ -29,12 +29,6 @@ BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += lv2_dsp -TARGETS += vst2 -TARGETS += vst3 - -all: $(TARGETS) +all: jack ladspa lv2_dsp vst2 vst3 clap # -------------------------------------------------------------- diff --git a/plugins/freeverb/DistrhoPluginInfo.h b/plugins/freeverb/DistrhoPluginInfo.h index 96cba61..46f8b40 100644 --- a/plugins/freeverb/DistrhoPluginInfo.h +++ b/plugins/freeverb/DistrhoPluginInfo.h @@ -17,16 +17,18 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "MaFreeverb" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaFreeverb" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "MaFreeverb" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaFreeverb" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MaFreeverb" #define DISTRHO_PLUGIN_HAS_UI 0 #define DISTRHO_PLUGIN_IS_RT_SAFE 0 #define DISTRHO_PLUGIN_NUM_INPUTS 1 #define DISTRHO_PLUGIN_NUM_OUTPUTS 1 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "reverb", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Reverb" #define DISTRHO_PLUGIN_DESCRIPTION "Max Gen Freeverb example." diff --git a/plugins/freeverb/Makefile b/plugins/freeverb/Makefile index f68d454..c9c6f26 100644 --- a/plugins/freeverb/Makefile +++ b/plugins/freeverb/Makefile @@ -29,12 +29,6 @@ BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += lv2_dsp -TARGETS += vst2 -TARGETS += vst3 - -all: $(TARGETS) +all: jack ladspa lv2_dsp vst2 vst3 clap # -------------------------------------------------------------- diff --git a/plugins/gigaverb/DistrhoPluginInfo.h b/plugins/gigaverb/DistrhoPluginInfo.h index c0a8ca3..496155f 100644 --- a/plugins/gigaverb/DistrhoPluginInfo.h +++ b/plugins/gigaverb/DistrhoPluginInfo.h @@ -17,16 +17,18 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "MaGigaverb" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaGigaverb" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "MaGigaverb" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaGigaverb" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MaGigaverb" #define DISTRHO_PLUGIN_HAS_UI 0 #define DISTRHO_PLUGIN_IS_RT_SAFE 0 #define DISTRHO_PLUGIN_NUM_INPUTS 2 #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "reverb", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:ReverbPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Reverb" #define DISTRHO_PLUGIN_DESCRIPTION "Max Gen Gigaverb example." diff --git a/plugins/gigaverb/Makefile b/plugins/gigaverb/Makefile index af04197..bc2ed21 100644 --- a/plugins/gigaverb/Makefile +++ b/plugins/gigaverb/Makefile @@ -29,12 +29,6 @@ BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += lv2_dsp -TARGETS += vst2 -TARGETS += vst3 - -all: $(TARGETS) +all: jack ladspa lv2_dsp vst2 vst3 clap # -------------------------------------------------------------- diff --git a/plugins/glBars/DistrhoPluginInfo.h b/plugins/glBars/DistrhoPluginInfo.h index 3e85b65..2bd321e 100644 --- a/plugins/glBars/DistrhoPluginInfo.h +++ b/plugins/glBars/DistrhoPluginInfo.h @@ -21,14 +21,16 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "glBars" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/glBars" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "glBars" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/glBars" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.glBars" #define DISTRHO_PLUGIN_HAS_UI 1 #define DISTRHO_PLUGIN_NUM_INPUTS 1 #define DISTRHO_PLUGIN_NUM_OUTPUTS 1 #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1 +#define DISTRHO_PLUGIN_CLAP_FEATURES "analyzer", "stereo" #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:AnalyserPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Analyzer" #define DISTRHO_UI_USER_RESIZABLE 1 diff --git a/plugins/glBars/Makefile b/plugins/glBars/Makefile index 65b7106..8be2bb2 100644 --- a/plugins/glBars/Makefile +++ b/plugins/glBars/Makefile @@ -32,7 +32,7 @@ LINK_FLAGS += -lpthread # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS = jack lv2 vst2 vst3 +TARGETS = jack lv2 vst2 vst3 clap all: $(TARGETS) diff --git a/plugins/pitchshift/DistrhoPluginInfo.h b/plugins/pitchshift/DistrhoPluginInfo.h index 99607f7..2f663fc 100644 --- a/plugins/pitchshift/DistrhoPluginInfo.h +++ b/plugins/pitchshift/DistrhoPluginInfo.h @@ -17,16 +17,18 @@ #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED #define DISTRHO_PLUGIN_INFO_H_INCLUDED -#define DISTRHO_PLUGIN_BRAND "DISTRHO" -#define DISTRHO_PLUGIN_NAME "MaPitchshift" -#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaPitchshift" +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "MaPitchshift" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/MaPitchshift" +#define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.MaPitchshift" #define DISTRHO_PLUGIN_HAS_UI 0 #define DISTRHO_PLUGIN_IS_RT_SAFE 0 #define DISTRHO_PLUGIN_NUM_INPUTS 1 #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 -#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:PitchPlugin" +#define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "pitch-shifter", "stereo" +#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:PitchPlugin" #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Pitch Shift" #define DISTRHO_PLUGIN_DESCRIPTION "Max Gen Pitchshifter example." diff --git a/plugins/pitchshift/Makefile b/plugins/pitchshift/Makefile index fd7edf8..d38d164 100644 --- a/plugins/pitchshift/Makefile +++ b/plugins/pitchshift/Makefile @@ -29,12 +29,6 @@ BUILD_CXX_FLAGS += -Wno-unused-parameter # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += ladspa -TARGETS += lv2_dsp -TARGETS += vst2 -TARGETS += vst3 - -all: $(TARGETS) +all: jack ladspa lv2_dsp vst2 vst3 clap # --------------------------------------------------------------