commit d7ba57dee15380086fb2c2ea0d40fbc147307fc0
parent 4bba885338e39608ad689a2b93fa368b8b077f65
Author: falkTX <falktx@falktx.com>
Date: Thu, 13 May 2021 03:39:51 +0100
Initial work for VST3 compatible plugins, lots to do..
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
7 files changed, 375 insertions(+), 13 deletions(-)
diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk
@@ -53,6 +53,19 @@ endif
BASE_FLAGS += -DHAVE_JACK
# ---------------------------------------------------------------------------------------------------------------------
+# Set VST3 filename, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html
+
+ifeq ($(LINUX),true)
+VST3_FILENAME = $(TARGET_PROCESSOR)-linux/$(NAME).so
+endif
+ifeq ($(MACOS),true)
+VST3_FILENAME = MacOS/$(NAME)
+endif
+ifeq ($(WINDOWS),true)
+VST3_FILENAME = $(TARGET_PROCESSOR)-win/$(NAME).vst3
+endif
+
+# ---------------------------------------------------------------------------------------------------------------------
# Set files to build
OBJS_DSP = $(FILES_DSP:%=$(BUILD_DIR)/%.o)
@@ -72,7 +85,10 @@ dssi_ui = $(TARGET_DIR)/$(NAME)-dssi/$(NAME)_ui$(APP_EXT)
lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME)$(LIB_EXT)
lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT)
lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT)
-vst = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT)
+vst2 = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT)
+ifneq ($(VST3_FILENAME),)
+vst3 = $(TARGET_DIR)/$(NAME).vst3/Contents/$(VST3_FILENAME)
+endif
# ---------------------------------------------------------------------------------------------------------------------
# Set plugin symbols to export
@@ -83,6 +99,7 @@ SYMBOLS_DSSI = -Wl,-exported_symbol,_ladspa_descriptor -Wl,-exported_symbol,_d
SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2_generate_ttl
SYMBOLS_LV2UI = -Wl,-exported_symbol,_lv2ui_descriptor
SYMBOLS_VST2 = -Wl,-exported_symbol,_VSTPluginMain
+SYMBOLS_VST3 = -Wl,-exported_symbol,_GetPluginFactory -Wl,-exported_symbol,_bundleEntry -Wl,-exported_symbol,_bundleExit
endif
# ---------------------------------------------------------------------------------------------------------------------
@@ -288,20 +305,30 @@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB)
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@
# ---------------------------------------------------------------------------------------------------------------------
-# VST
+# VST2
-vst: $(vst)
+vst2 vst: $(vst2)
ifeq ($(HAVE_DGL),true)
-$(vst): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST.cpp.o $(DGL_LIB)
+$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST.cpp.o $(DGL_LIB)
else
-$(vst): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o
+$(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o
endif
-@mkdir -p $(shell dirname $@)
- @echo "Creating VST plugin for $(NAME)"
+ @echo "Creating VST2 plugin for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST2) -o $@
# ---------------------------------------------------------------------------------------------------------------------
+# VST3
+
+vst3: $(vst3)
+
+$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o
+ -@mkdir -p $(shell dirname $@)
+ @echo "Creating VST3 plugin for $(NAME)"
+ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@
+
+# ---------------------------------------------------------------------------------------------------------------------
-include $(OBJS_DSP:%.o=%.d)
ifneq ($(UI_TYPE),)
@@ -313,10 +340,12 @@ endif
-include $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.d
+-include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST.cpp.d
+-include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d
# ---------------------------------------------------------------------------------------------------------------------
diff --git a/distrho/DistrhoPluginMain.cpp b/distrho/DistrhoPluginMain.cpp
@@ -27,6 +27,8 @@
# include "src/DistrhoPluginLV2export.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_VST)
# include "src/DistrhoPluginVST.cpp"
+#elif defined(DISTRHO_PLUGIN_TARGET_VST3)
+# include "src/DistrhoPluginVST3.cpp"
#else
# error unsupported format
#endif
diff --git a/distrho/DistrhoUIMain.cpp b/distrho/DistrhoUIMain.cpp
@@ -26,6 +26,8 @@
# include "src/DistrhoUILV2.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_VST)
// nothing
+#elif defined(DISTRHO_PLUGIN_TARGET_VST3)
+// nothing
#else
# error unsupported format
#endif
diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp
@@ -814,7 +814,9 @@ private:
static const PortGroupWithId sFallbackPortGroup;
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter)
+#ifndef DISTRHO_PLUGIN_TARGET_VST3 /* there is no way around this for VST3 */
DISTRHO_PREVENT_HEAP_ALLOCATION
+#endif
};
// -----------------------------------------------------------------------
diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp
@@ -0,0 +1,333 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "DistrhoPluginInternal.hpp"
+#include "../extra/ScopedPointer.hpp"
+
+#include "travesty/audio_processor.h"
+#include "travesty/component.h"
+#include "travesty/edit_controller.h"
+#include "travesty/factory.h"
+
+START_NAMESPACE_DISTRHO
+
+#if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+static const writeMidiFunc writeMidiCallback = nullptr;
+#endif
+
+// custom v3_tuid compatible type
+typedef uint32_t dpf_tuid[4];
+static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch");
+
+// custom uids, fully created during module init
+static constexpr const uint32_t dpf_id_entry = d_cconst('D', 'P', 'F', ' ');
+static constexpr const uint32_t dpf_id_clas = d_cconst('c', 'l', 'a', 's');
+static constexpr const uint32_t dpf_id_comp = d_cconst('c', 'o', 'm', 'p');
+static constexpr const uint32_t dpf_id_ctrl = d_cconst('c', 't', 'r', 'l');
+static constexpr const uint32_t dpf_id_proc = d_cconst('p', 'r', 'o', 'c');
+static constexpr const uint32_t dpf_id_view = d_cconst('v', 'i', 'e', 'w');
+
+static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, 0 };
+static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, 0 };
+static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, 0 };
+static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, 0 };
+static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 };
+
+// -----------------------------------------------------------------------
+
+void strncpy(char* const dst, const char* const src, const size_t size)
+{
+ DISTRHO_SAFE_ASSERT_RETURN(size > 0,);
+
+ if (const size_t len = std::min(std::strlen(src), size-1U))
+ {
+ std::memcpy(dst, src, len);
+ dst[len] = '\0';
+ }
+ else
+ {
+ dst[0] = '\0';
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// v3_funknown, v3_plugin_base, v3_component
+
+// audio_processor
+
+class PluginVst3
+{
+public:
+ PluginVst3()
+ : fPlugin(this, writeMidiCallback)
+ {
+ }
+
+private:
+ // Plugin
+ PluginExporter fPlugin;
+
+ // VST3 stuff
+ // TODO
+
+#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
+ bool writeMidi(const MidiEvent& midiEvent)
+ {
+ // TODO
+ return true;
+ }
+
+ static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent)
+ {
+ return ((PluginVst*)ptr)->writeMidi(midiEvent);
+ }
+#endif
+
+};
+
+// -----------------------------------------------------------------------
+// WIP this whole section still TODO
+
+struct ControllerComponent;
+struct ProcessorComponent;
+
+struct ComponentAdapter : v3_funknown, v3_plugin_base
+{
+ // needs atomic refcount, starts at 1
+
+ ComponentAdapter()
+ {
+ static const uint8_t* kSupportedFactories[] = {
+ v3_funknown_iid,
+ v3_plugin_base_iid,
+ /*
+ v3_component_iid,
+ v3_edit_controller_iid,
+ v3_audio_processor_iid
+ */
+ };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_funknown
+
+ query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
+ {
+ d_stdout("ComponentAdapter::query_interface %p %p %p", self, iid, iface);
+
+ *iface = NULL;
+ DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
+
+ for (const uint8_t* factory_iid : kSupportedFactories)
+ {
+ if (v3_tuid_match(factory_iid, iid))
+ {
+ *iface = self;
+ return V3_OK;
+ }
+ }
+
+ return V3_NO_INTERFACE;
+ };
+
+ // TODO use atomic counter
+ ref = []V3_API(void*) -> uint32_t { return 1; };
+ unref = []V3_API(void*) -> uint32_t { return 0; };
+ }
+};
+
+struct ControllerComponent : ComponentAdapter
+{
+};
+
+struct ProcessorComponent : ComponentAdapter
+{
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// Dummy plugin to get data from
+
+static ScopedPointer<PluginExporter> gPluginInfo;
+
+static void gPluginInit()
+{
+ if (gPluginInfo != nullptr)
+ return;
+
+ d_lastBufferSize = 512;
+ d_lastSampleRate = 44100.0;
+ gPluginInfo = new PluginExporter(nullptr, nullptr);
+ d_lastBufferSize = 0;
+ d_lastSampleRate = 0.0;
+
+ dpf_tuid_class[3] = dpf_tuid_component[3] = dpf_tuid_controller[3]
+ = dpf_tuid_processor[3] = dpf_tuid_view[3] = gPluginInfo->getUniqueId();
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// dpf_factory
+
+struct v3_plugin_factory_cpp : v3_funknown, v3_plugin_factory {
+ v3_plugin_factory_2 v2;
+ v3_plugin_factory_3 v3;
+};
+
+struct dpf_factory : v3_plugin_factory_cpp {
+ dpf_factory()
+ {
+ static const uint8_t* kSupportedFactories[] = {
+ v3_funknown_iid,
+ v3_plugin_factory_iid,
+ v3_plugin_factory_2_iid
+ };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_funknown
+
+ query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
+ {
+ *iface = NULL;
+ DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
+
+ for (const uint8_t* factory_iid : kSupportedFactories)
+ {
+ if (v3_tuid_match(factory_iid, iid))
+ {
+ *iface = self;
+ return V3_OK;
+ }
+ }
+
+ return V3_NO_INTERFACE;
+ };
+
+ // we only support 1 plugin per binary, so don't have to care here
+ ref = []V3_API(void*) -> uint32_t { return 1; };
+ unref = []V3_API(void*) -> uint32_t { return 0; };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_plugin_factory
+
+ get_factory_info = []V3_API(void*, struct v3_factory_info* const info) -> v3_result
+ {
+ DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo->getMaker(), sizeof(info->vendor));
+ DISTRHO_NAMESPACE::strncpy(info->url, gPluginInfo->getHomePage(), sizeof(info->url));
+ DISTRHO_NAMESPACE::strncpy(info->email, "", sizeof(info->email)); // TODO
+ return V3_OK;
+ };
+
+ num_classes = []V3_API(void*) -> int32_t
+ {
+ return 1;
+ };
+
+ get_class_info = []V3_API(void*, int32_t /*idx*/, struct v3_class_info* const info) -> v3_result
+ {
+ memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
+ info->cardinality = 0x7FFFFFFF;
+ DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
+ DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo->getName(), sizeof(info->name));
+ return V3_OK;
+ };
+
+ create_instance = []V3_API(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance) -> v3_result
+ {
+ d_stdout("%s %i %p %p %p %p", __PRETTY_FUNCTION__, __LINE__, self, class_id, iid, instance);
+ DISTRHO_SAFE_ASSERT_RETURN(v3_tuid_match(class_id, *(v3_tuid*)&dpf_tuid_class) &&
+ v3_tuid_match(iid, v3_component_iid), V3_NO_INTERFACE);
+
+ *instance = nullptr; // new ComponentAdapter();
+ return V3_INTERNAL_ERR;
+ };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_plugin_factory_2
+
+ v2.get_class_info_2 = []V3_API(void*, int32_t /*idx*/, struct v3_class_info_2 *info) -> v3_result
+ {
+ // get_class_info
+ memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid));
+ info->cardinality = 0x7FFFFFFF;
+ DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category));
+ DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo->getName(), sizeof(info->name));
+ // get_class_info_2
+ info->class_flags = 0;
+ DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO
+ DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo->getMaker(), sizeof(info->vendor));
+ DISTRHO_NAMESPACE::strncpy(info->version, "", sizeof(info->version)); // TODO
+ DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", sizeof(info->sdk_version)); // TESTING use "VST 3.7" ?
+ return V3_OK;
+ };
+ }
+};
+
+static const dpf_factory dpf_factory;
+
+END_NAMESPACE_DISTRHO
+
+// --------------------------------------------------------------------------------------------------------------------
+// VST3 entry point
+
+DISTRHO_PLUGIN_EXPORT
+const void* GetPluginFactory(void);
+
+const void* GetPluginFactory(void)
+{
+ static const struct v3_plugin_factory_2* const factory = (v3_plugin_factory_2*)&dpf_factory;
+ return &factory;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// OS specific module load
+
+#ifdef DISTRHO_OS_MAC
+DISTRHO_PLUGIN_EXPORT bool bundleEntry(CFBundleRef);
+DISTRHO_PLUGIN_EXPORT bool bundleExit(void);
+bool bundleEntry(CFBundleRef)
+{
+ gPluginInit();
+ return true;
+}
+bool bundleExit(void)
+{
+ gPluginInfo = nullptr;
+ return true;
+}
+#else
+# ifdef DISTRHO_OS_WINDOWS
+# define ENTRYFNNAME InitDll
+# define EXITFNNAME ExitDll
+# else
+# define ENTRYFNNAME ModuleEntry
+# define EXITFNNAME ModuleExit
+# endif
+DISTRHO_PLUGIN_EXPORT bool ENTRYFNNAME(void*);
+DISTRHO_PLUGIN_EXPORT bool EXITFNNAME(void);
+bool ENTRYFNNAME(void*)
+{
+ gPluginInit();
+ return true;
+}
+bool EXITFNNAME(void)
+{
+ gPluginInfo = nullptr;
+ return true;
+}
+# undef ENTRYFNNAME
+# undef EXITFNNAME
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
diff --git a/distrho/src/travesty/factory.h b/distrho/src/travesty/factory.h
@@ -113,10 +113,3 @@ struct v3_plugin_factory_3 {
static const v3_tuid v3_plugin_factory_3_iid =
V3_ID(0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931);
-
-#ifdef __cplusplus
-struct v3_plugin_factory_cpp : v3_funknown, v3_plugin_factory {
- v3_plugin_factory_2 v2;
- v3_plugin_factory_3 v3;
-};
-#endif
diff --git a/examples/Parameters/Makefile b/examples/Parameters/Makefile
@@ -46,6 +46,7 @@ TARGETS += lv2_dsp
endif
TARGETS += vst
+TARGETS += vst3
all: $(TARGETS)