commit e41e03f7247349b36754a425e0d41d5029079773
parent 57a430e9d5cf79beb28d4e47c5bc2913ddb519c7
Author: falkTX <falktx@falktx.com>
Date: Sat, 25 Sep 2021 23:54:37 +0100
VST3: Start handling UI->DSP messages, WIP
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
4 files changed, 457 insertions(+), 75 deletions(-)
diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp
@@ -21,6 +21,7 @@
#include "travesty/component.h"
#include "travesty/edit_controller.h"
#include "travesty/factory.h"
+#include "travesty/message.h"
#include <atomic>
#include <vector>
@@ -89,8 +90,49 @@ static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 };
const char* tuid2str(const v3_tuid iid)
{
+ static constexpr const struct {
+ v3_tuid iid;
+ const char* name;
+ } extra_known_iids[] = {
+ { V3_ID(0x00000000,0x00000000,0x00000000,0x00000000), "(nil)" },
+ // edit-controller
+ { V3_ID(0xF040B4B3,0xA36045EC,0xABCDC045,0xB4D5A2CC), "{v3_component_handler2|NOT}" },
+ { V3_ID(0x7F4EFE59,0xF3204967,0xAC27A3AE,0xAFB63038), "{v3_edit_controller2|NOT}" },
+ { V3_ID(0x067D02C1,0x5B4E274D,0xA92D90FD,0x6EAF7240), "{v3_component_handler_bus_activation|NOT}" },
+ { V3_ID(0xDF0FF9F7,0x49B74669,0xB63AB732,0x7ADBF5E5), "{v3_midi_mapping|NOT}" },
+ { V3_ID(0xC1271208,0x70594098,0xB9DD34B3,0x6BB0195E), "{v3_edit_controller_host_editing|NOT}" },
+ // units
+ { V3_ID(0x8683B01F,0x7B354F70,0xA2651DEC,0x353AF4FF), "{v3_program_list_data|NOT}" },
+ { V3_ID(0x6C389611,0xD391455D,0xB870B833,0x94A0EFDD), "{v3_unit_data|NOT}" },
+ { V3_ID(0x4B5147F8,0x4654486B,0x8DAB30BA,0x163A3C56), "{v3_unit_handler|NOT}" },
+ { V3_ID(0xF89F8CDF,0x699E4BA5,0x96AAC9A4,0x81452B01), "{v3_unit_handler2|NOT}" },
+ { V3_ID(0x3D4BD6B5,0x913A4FD2,0xA886E768,0xA5EB92C1), "{v3_unit_info|NOT}" },
+ // misc
+ { V3_ID(0x0F194781,0x8D984ADA,0xBBA0C1EF,0xC011D8D0), "{v3_info_listener|NOT}" },
+ };
+
+ if (v3_tuid_match(iid, v3_audio_processor_iid))
+ return "{v3_audio_processor}";
+ if (v3_tuid_match(iid, v3_bstream_iid))
+ return "{v3_bstream}";
+ if (v3_tuid_match(iid, v3_component_iid))
+ return "{v3_component}";
+ if (v3_tuid_match(iid, v3_component_handler_iid))
+ return "{v3_component_handler}";
+ if (v3_tuid_match(iid, v3_connection_point_iid))
+ return "{v3_connection_point_iid}";
+ if (v3_tuid_match(iid, v3_edit_controller_iid))
+ return "{v3_edit_controller}";
+ if (v3_tuid_match(iid, v3_event_list_iid))
+ return "{v3_event_list}";
if (v3_tuid_match(iid, v3_funknown_iid))
return "{v3_funknown}";
+ if (v3_tuid_match(iid, v3_message_iid))
+ return "{v3_message_iid}";
+ if (v3_tuid_match(iid, v3_param_value_queue_iid))
+ return "{v3_param_value_queue}";
+ if (v3_tuid_match(iid, v3_param_changes_iid))
+ return "{v3_param_changes}";
if (v3_tuid_match(iid, v3_plugin_base_iid))
return "{v3_plugin_base}";
if (v3_tuid_match(iid, v3_plugin_factory_iid))
@@ -99,32 +141,17 @@ const char* tuid2str(const v3_tuid iid)
return "{v3_plugin_factory_2}";
if (v3_tuid_match(iid, v3_plugin_factory_3_iid))
return "{v3_plugin_factory_3}";
- if (v3_tuid_match(iid, v3_component_iid))
- return "{v3_component}";
- if (v3_tuid_match(iid, v3_bstream_iid))
- return "{v3_bstream}";
- if (v3_tuid_match(iid, v3_event_list_iid))
- return "{v3_event_list}";
- if (v3_tuid_match(iid, v3_param_value_queue_iid))
- return "{v3_param_value_queue}";
- if (v3_tuid_match(iid, v3_param_changes_iid))
- return "{v3_param_changes}";
- if (v3_tuid_match(iid, v3_process_context_requirements_iid))
- return "{v3_process_context_requirements}";
- if (v3_tuid_match(iid, v3_audio_processor_iid))
- return "{v3_audio_processor}";
- if (v3_tuid_match(iid, v3_component_handler_iid))
- return "{v3_component_handler}";
- if (v3_tuid_match(iid, v3_edit_controller_iid))
- return "{v3_edit_controller}";
- if (v3_tuid_match(iid, v3_plugin_view_iid))
- return "{v3_plugin_view}";
if (v3_tuid_match(iid, v3_plugin_frame_iid))
return "{v3_plugin_frame}";
+ if (v3_tuid_match(iid, v3_plugin_view_iid))
+ return "{v3_plugin_view}";
if (v3_tuid_match(iid, v3_plugin_view_content_scale_iid))
return "{v3_plugin_view_content_scale_iid}";
if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid))
return "{v3_plugin_view_parameter_finder}";
+ if (v3_tuid_match(iid, v3_process_context_requirements_iid))
+ return "{v3_process_context_requirements}";
+
if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0)
return "{dpf_tuid_class}";
if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0)
@@ -136,6 +163,12 @@ const char* tuid2str(const v3_tuid iid)
if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0)
return "{dpf_tuid_view}";
+ for (size_t i=0; i<ARRAY_SIZE(extra_known_iids); ++i)
+ {
+ if (v3_tuid_match(iid, extra_known_iids[i].iid))
+ return extra_known_iids[i].name;
+ }
+
static char buf[46];
std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}",
(uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
@@ -1238,6 +1271,17 @@ public:
}
// ----------------------------------------------------------------------------------------------------------------
+ // dpf_connection_point
+
+ v3_result notify(v3_message** const message)
+ {
+ d_stdout("notify received %p -> %s", message, v3_cpp_obj(message)->get_message_id(message));
+ // TESTING, ensure host gets the message
+ requestParameterValueChange(2, 1.0f);
+ return V3_OK;
+ }
+
+ // ----------------------------------------------------------------------------------------------------------------
private:
// Plugin
@@ -1309,13 +1353,15 @@ private:
{
DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false);
- if (v3_cpp_obj(fComponentHandler)->begin_edit(fComponentHandler, index) != V3_OK)
+ const uint32_t rindex = index + fParameterOffset;
+
+ if (v3_cpp_obj(fComponentHandler)->begin_edit(fComponentHandler, rindex) != V3_OK)
return false;
const double normalized = fPlugin.getParameterRanges(index).getNormalizedValue(value);
- const bool ret = v3_cpp_obj(fComponentHandler)->perform_edit(fComponentHandler, index, normalized) == V3_OK;
+ const bool ret = v3_cpp_obj(fComponentHandler)->perform_edit(fComponentHandler, rindex, normalized) == V3_OK;
- v3_cpp_obj(fComponentHandler)->end_edit(fComponentHandler, index);
+ v3_cpp_obj(fComponentHandler)->end_edit(fComponentHandler, rindex);
return ret;
}
@@ -1395,11 +1441,100 @@ private:
// --------------------------------------------------------------------------------------------------------------------
// dpf_plugin_view_create (called from DSP side)
-v3_funknown** dpf_plugin_view_create(v3_edit_controller** controller, v3_component_handler** handler,
- void* instancePointer, double sampleRate);
+v3_funknown** dpf_plugin_view_create(v3_connection_point** connection, void* instancePointer, double sampleRate);
#endif
// --------------------------------------------------------------------------------------------------------------------
+// dpf_connection_point
+
+struct v3_connection_point_cpp : v3_funknown {
+ v3_connection_point point;
+};
+
+struct dpf_connection_point : v3_connection_point_cpp {
+ ScopedPointer<PluginVst3>& vst3;
+ const bool controller; // component otherwise
+ bool connected;
+
+ dpf_connection_point(const bool isEditCtrl, ScopedPointer<PluginVst3>& v)
+ : vst3(v),
+ controller(isEditCtrl),
+ connected(false)
+ {
+ static const uint8_t* kSupportedInterfaces[] = {
+ v3_funknown_iid,
+ v3_connection_point_iid
+ };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_funknown
+
+ query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result
+ {
+ d_stdout("dpf_connection_point::query_interface => %p %s %p", self, tuid2str(iid), iface);
+ *iface = NULL;
+ DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
+
+ for (const uint8_t* interface_iid : kSupportedInterfaces)
+ {
+ if (v3_tuid_match(interface_iid, iid))
+ {
+ *iface = self;
+ return V3_OK;
+ }
+ }
+
+ return V3_NO_INTERFACE;
+ };
+
+ // there is only a single instance of this, so we don't have to care here
+ ref = []V3_API(void*) -> uint32_t { return 1; };
+ unref = []V3_API(void*) -> uint32_t { return 0; };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_connection_point
+
+ point.connect = []V3_API(void* self, struct v3_connection_point** other) -> v3_result
+ {
+ d_stdout("dpf_connection_point::connect => %p %p", self, other);
+ dpf_connection_point* const point = *(dpf_connection_point**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED);
+
+ const bool connected = point->connected;
+ DISTRHO_SAFE_ASSERT_RETURN(! connected, V3_INVALID_ARG);
+
+ point->connected = true;
+ return V3_OK;
+ };
+
+ point.disconnect = []V3_API(void* self, struct v3_connection_point** other) -> v3_result
+ {
+ d_stdout("dpf_connection_point::disconnect => %p %p", self, other);
+ dpf_connection_point* const point = *(dpf_connection_point**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED);
+
+ const bool connected = point->connected;
+ DISTRHO_SAFE_ASSERT_RETURN(connected, V3_INVALID_ARG);
+
+ point->connected = false;
+ return V3_OK;
+ };
+
+ point.notify = []V3_API(void* self, struct v3_message** message) -> v3_result
+ {
+ d_stdout("dpf_connection_point::notify => %p %p", self, message);
+ dpf_connection_point* const point = *(dpf_connection_point**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED);
+
+ PluginVst3* const vst3 = point->vst3;
+ DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED);
+
+ return vst3->notify(message);
+ };
+ }
+};
+
+// --------------------------------------------------------------------------------------------------------------------
// dpf_edit_controller
struct v3_edit_controller_cpp : v3_funknown {
@@ -1408,6 +1543,7 @@ struct v3_edit_controller_cpp : v3_funknown {
};
struct dpf_edit_controller : v3_edit_controller_cpp {
+ ScopedPointer<dpf_connection_point> connection;
ScopedPointer<PluginVst3>& vst3;
bool initialized;
// cached values
@@ -1418,7 +1554,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
initialized(false),
handler(nullptr)
{
- static const uint8_t* kSupportedInterfaces[] = {
+ static const uint8_t* kSupportedInterfacesBase[] = {
v3_funknown_iid,
v3_edit_controller_iid
};
@@ -1432,7 +1568,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
*iface = NULL;
DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
- for (const uint8_t* interface_iid : kSupportedInterfaces)
+ for (const uint8_t* interface_iid : kSupportedInterfacesBase)
{
if (v3_tuid_match(interface_iid, iid))
{
@@ -1441,6 +1577,17 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
}
}
+ dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NO_INTERFACE);
+
+ if (v3_tuid_match(v3_connection_point_iid, iid))
+ {
+ if (controller->connection == nullptr)
+ controller->connection = new dpf_connection_point(true, controller->vst3);
+ *iface = &controller->connection;
+ return V3_OK;
+ }
+
return V3_NO_INTERFACE;
};
@@ -1527,7 +1674,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
controller.get_parameter_count = []V3_API(void* self) -> int32_t
{
- d_stdout("dpf_edit_controller::get_parameter_count => %p", self);
+ // d_stdout("dpf_edit_controller::get_parameter_count => %p", self);
dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
@@ -1539,7 +1686,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
controller.get_parameter_info = []V3_API(void* self, int32_t param_idx, v3_param_info* param_info) -> v3_result
{
- d_stdout("dpf_edit_controller::get_parameter_info => %p %i", self, param_idx);
+ // d_stdout("dpf_edit_controller::get_parameter_info => %p %i", self, param_idx);
dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED);
@@ -1651,14 +1798,39 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr);
- PluginVst3* const vst3 = controller->vst3;
- DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr);
+ // if there is no connection yet we can still manage ourselves, but only if component is initialized
+ DISTRHO_SAFE_ASSERT_RETURN((controller->connection != nullptr && controller->connection->connected) ||
+ controller->vst3 != nullptr, nullptr);
+
+ if (controller->connection != nullptr)
+ {
+ // if there is a connection point alreay it needs to be connected
+ DISTRHO_SAFE_ASSERT_RETURN(controller->connection->connected, nullptr);
+ }
+ else
+ {
+ // no connection point, let's do it ourselves (assume local usage)
+ controller->connection = new dpf_connection_point(true, controller->vst3);
+ controller->connection->connected = true;
+ }
+
+ void* instancePointer;
+ double sampleRate;
+
+ if (PluginVst3* const vst3 = controller->vst3)
+ {
+ instancePointer = vst3->getInstancePointer();
+ sampleRate = vst3->getSampleRate();
+ }
+ else
+ {
+ instancePointer = nullptr;
+ sampleRate = 44100.0;
+ }
#if DISTRHO_PLUGIN_HAS_UI
- return (v3_plugin_view**)dpf_plugin_view_create((v3_edit_controller**)self,
- controller->handler,
- vst3->getInstancePointer(),
- vst3->getSampleRate());
+ return (v3_plugin_view**)dpf_plugin_view_create((v3_connection_point**)&controller->connection,
+ instancePointer, sampleRate);
#else
return nullptr;
#endif
@@ -1990,6 +2162,7 @@ struct dpf_component : v3_component_cpp {
std::atomic<int> refcounter;
ScopedPointer<dpf_component>* self;
ScopedPointer<dpf_audio_processor> processor;
+ ScopedPointer<dpf_connection_point> connection;
ScopedPointer<dpf_edit_controller> controller;
// ScopedPointer<dpf_state_stream> stream;
ScopedPointer<PluginVst3> vst3;
@@ -2032,6 +2205,14 @@ struct dpf_component : v3_component_cpp {
return V3_OK;
}
+ if (v3_tuid_match(v3_connection_point_iid, iid))
+ {
+ if (component->connection == nullptr)
+ component->connection = new dpf_connection_point(false, component->vst3);
+ *iface = &component->connection;
+ return V3_OK;
+ }
+
if (v3_tuid_match(v3_edit_controller_iid, iid))
{
if (component->controller == nullptr)
diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp
@@ -39,6 +39,7 @@
// #endif
#include "travesty/edit_controller.h"
+#include "travesty/message.h"
#include "travesty/view.h"
/* TODO items:
@@ -70,6 +71,21 @@ static constexpr const setStateFunc setStateCallback = nullptr;
const char* tuid2str(const v3_tuid iid);
// --------------------------------------------------------------------------------------------------------------------
+// dpf_message (needed by the UI class, implementation comes later)
+
+struct v3_message_cpp : v3_funknown {
+ v3_message msg;
+};
+
+// NOTE value type must be POD
+template<typename T>
+struct dpf_message : v3_message_cpp {
+ dpf_message(ScopedPointer<dpf_message>* self, const char* id, T value);
+ struct PrivateData;
+ PrivateData* const pData;
+};
+
+// --------------------------------------------------------------------------------------------------------------------
/**
* VST3 UI class.
@@ -77,14 +93,17 @@ const char* tuid2str(const v3_tuid iid);
* All the dynamic things from VST3 get implemented here, free of complex low-level VST3 pointer things.
* The UI is created during the "attach" view event, and destroyed during "removed".
*
+ * Note that DPF VST3 implementation works over the connection point interface,
+ * rather than using edit controller directly.
+ * This allows the UI to be running remotely from the DSP.
+ *
* The low-level VST3 stuff comes after.
*/
class UIVst3 : public Thread
{
public:
UIVst3(v3_plugin_view** const view,
- v3_edit_controller** const controller,
- v3_component_handler** const handler,
+ v3_connection_point** const connection,
const intptr_t winId,
const float scaleFactor,
const double sampleRate,
@@ -100,8 +119,7 @@ public:
instancePointer,
scaleFactor),
fView(view),
- fController(controller),
- fHandler(handler),
+ fConnection(connection),
fFrame(nullptr),
fScaleFactor(scaleFactor)
{
@@ -211,21 +229,23 @@ private:
// VST3 stuff
v3_plugin_view** const fView;
- v3_edit_controller** const fController;
- v3_component_handler** const fHandler;
+ v3_connection_point** const fConnection;
v3_plugin_frame** fFrame;
// Temporary data
float fScaleFactor;
- void editParameter(const uint32_t rindex, const bool started) const
+ // ----------------------------------------------------------------------------------------------------------------
+ // DPF callbacks
+
+ void editParameter(const uint32_t /*rindex*/, const bool /*started*/) const
{
- DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,);
+// DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,);
- if (started)
- v3_cpp_obj(fHandler)->begin_edit(fHandler, rindex);
- else
- v3_cpp_obj(fHandler)->end_edit(fHandler, rindex);
+// if (started)
+// v3_cpp_obj(fHandler)->begin_edit(fHandler, rindex);
+// else
+// v3_cpp_obj(fHandler)->end_edit(fHandler, rindex);
}
static void editParameterCallback(void* ptr, uint32_t rindex, bool started)
@@ -235,11 +255,17 @@ private:
void setParameterValue(const uint32_t rindex, const float realValue)
{
- DISTRHO_SAFE_ASSERT_RETURN(fController != nullptr,);
- DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,);
+ DISTRHO_SAFE_ASSERT_RETURN(fConnection != nullptr,);
+ d_stdout("setParameterValue %p %u %f", this, rindex, realValue);
+
+ struct IndexAndValue {
+ uint32_t index;
+ float value;
+ };
+ ScopedPointer<dpf_message<IndexAndValue>>* const messageptr = new ScopedPointer<dpf_message<IndexAndValue>>;
+ *messageptr = new dpf_message<IndexAndValue>(messageptr, "parameter-value-set", { rindex, realValue });
- const double value = v3_cpp_obj(fController)->plain_parameter_to_normalised(fController, rindex, realValue);
- v3_cpp_obj(fHandler)->perform_edit(fHandler, rindex, value);
+ v3_cpp_obj(fConnection)->notify(fConnection, (v3_message**)messageptr);
}
static void setParameterCallback(void* ptr, uint32_t rindex, float value)
@@ -253,17 +279,17 @@ private:
DISTRHO_SAFE_ASSERT_RETURN(fFrame != nullptr,);
d_stdout("from UI setSize %u %u | %p %p", width, height, fView, fFrame);
-#ifdef DISTRHO_OS_MAC
- const double scaleFactor = fUI.getScaleFactor();
- width /= scaleFactor;
- height /= scaleFactor;
-#endif
-
- v3_view_rect rect;
- std::memset(&rect, 0, sizeof(rect));
- rect.right = width;
- rect.bottom = height;
- v3_cpp_obj(fFrame)->resize_view(fFrame, fView, &rect);
+// #ifdef DISTRHO_OS_MAC
+// const double scaleFactor = fUI.getScaleFactor();
+// width /= scaleFactor;
+// height /= scaleFactor;
+// #endif
+//
+// v3_view_rect rect;
+// std::memset(&rect, 0, sizeof(rect));
+// rect.right = width;
+// rect.bottom = height;
+// v3_cpp_obj(fFrame)->resize_view(fFrame, fView, &rect);
}
static void setSizeCallback(void* ptr, uint width, uint height)
@@ -308,6 +334,118 @@ private:
*/
// --------------------------------------------------------------------------------------------------------------------
+// dpf_message (implementation only, declaration already done as needed by UI class)
+
+template<typename T>
+struct dpf_message<T>::PrivateData {
+ std::atomic<int> refcounter;
+ ScopedPointer<dpf_message>* self;
+ String id;
+ const T value;
+
+ PrivateData(ScopedPointer<dpf_message>* const s, const char* const id2, T value2)
+ : refcounter(1),
+ self(s),
+ id(id2),
+ value(value2) {}
+};
+
+static V3_API v3_result dpf_message__query_interface(void* self, const v3_tuid iid, void** iface)
+{
+ d_stdout("dpf_message::query_interface => %p %s %p", self, tuid2str(iid), iface);
+ *iface = NULL;
+ DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE);
+
+ static const uint8_t* kSupportedInterfaces[] = {
+ v3_funknown_iid,
+ v3_message_iid
+ };
+
+ for (const uint8_t* interface_iid : kSupportedInterfaces)
+ {
+ if (v3_tuid_match(interface_iid, iid))
+ {
+ *iface = self;
+ return V3_OK;
+ }
+ }
+
+ return V3_NO_INTERFACE;
+}
+
+template<typename T>
+static V3_API uint32_t dpf_message__ref(void* const self)
+{
+ d_stdout("dpf_message::ref => %p", self);
+ dpf_message<T>* const message = *(dpf_message<T>**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
+
+ return ++message->pData->refcounter;
+}
+
+template<typename T>
+static V3_API uint32_t dpf_message__unref(void* const self)
+{
+ d_stdout("dpf_message::unref => %p", self);
+ dpf_message<T>* const message = *(dpf_message<T>**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, 0);
+
+ if (const int refcounter = --message->pData->refcounter)
+ return refcounter;
+
+ dpf_message<T>* const messageptr = message->pData->self->release();
+ delete message->pData;
+ delete messageptr;
+ delete (dpf_message<T>**)self;
+ return 0;
+}
+
+template<typename T>
+static V3_API const char* dpf_message__get_message_id(void* const self)
+{
+ d_stdout("dpf_message::get_message_id => %p", self);
+ dpf_message<T>* const message = *(dpf_message<T>**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
+
+ return message->pData->id;
+}
+
+template<typename T>
+static V3_API void dpf_message__set_message_id(void* const self, const char* const id)
+{
+ d_stdout("dpf_message::set_message_id => %p %s", self, id);
+ dpf_message<T>* const message = *(dpf_message<T>**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,);
+
+ message->pData->id = id;
+}
+
+template<typename T>
+static V3_API v3_attribute_list* dpf_message__get_attributes(void* const self)
+{
+ d_stdout("dpf_message::get_attributes => %p", self);
+ dpf_message<T>* const message = *(dpf_message<T>**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(message != nullptr, nullptr);
+
+ // TODO
+ return nullptr;
+}
+
+template<typename T>
+dpf_message<T>::dpf_message(ScopedPointer<dpf_message>* const self, const char* const id, const T value)
+ : pData(new PrivateData(self, id, value))
+{
+ query_interface = dpf_message__query_interface;
+ ref = dpf_message__ref<T>;
+ unref = dpf_message__unref<T>;
+ msg.get_message_id = dpf_message__get_message_id<T>;
+ msg.set_message_id = dpf_message__set_message_id<T>;
+ msg.get_attributes = dpf_message__get_attributes<T>;
+}
+
+template struct dpf_message<float>;
+
+// --------------------------------------------------------------------------------------------------------------------
// dpf_plugin_view_content_scale
struct v3_plugin_view_content_scale_cpp : v3_funknown {
@@ -390,21 +528,18 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
ScopedPointer<dpf_plugin_view_content_scale> scale;
ScopedPointer<UIVst3> uivst3;
// cached values
- v3_edit_controller** const controller;
- v3_component_handler** const handler;
+ v3_connection_point** const connection;
void* const instancePointer;
double sampleRate;
v3_plugin_frame** frame = nullptr;
dpf_plugin_view(ScopedPointer<dpf_plugin_view>* selfptr,
- v3_edit_controller** const controllerptr,
- v3_component_handler** const handlerptr,
+ v3_connection_point** const connectionptr,
void* const instance,
const double sr)
: refcounter(1),
self(selfptr),
- controller(controllerptr),
- handler(handlerptr),
+ connection(connectionptr),
instancePointer(instance),
sampleRate(sr)
{
@@ -508,9 +643,8 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0)
{
const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f;
- view->uivst3 = new UIVst3((v3_plugin_view**)self,
- view->controller,
- view->handler,
+ view->uivst3 = new UIVst3((v3_plugin_view**)view->self,
+ view->connection,
(uintptr_t)parent,
scaleFactor,
view->sampleRate,
@@ -654,14 +788,13 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
// --------------------------------------------------------------------------------------------------------------------
// dpf_plugin_view_create (called from plugin side)
-v3_funknown** dpf_plugin_view_create(v3_edit_controller** controller, v3_component_handler** handler,
- void* instancePointer, double sampleRate);
+v3_funknown** dpf_plugin_view_create(v3_connection_point** connection, void* instancePointer, double sampleRate);
-v3_funknown** dpf_plugin_view_create(v3_edit_controller** const controller, v3_component_handler** const handler,
+v3_funknown** dpf_plugin_view_create(v3_connection_point** const connection,
void* const instancePointer, const double sampleRate)
{
ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>;
- *viewptr = new dpf_plugin_view(viewptr, controller, handler, instancePointer, sampleRate);
+ *viewptr = new dpf_plugin_view(viewptr, connection, instancePointer, sampleRate);
return (v3_funknown**)viewptr;
}
diff --git a/distrho/src/travesty/edit_controller.h b/distrho/src/travesty/edit_controller.h
@@ -26,6 +26,19 @@
* component handler
*/
+enum {
+ V3_RESTART_RELOAD_COMPONENT = 1 << 0,
+ V3_RESTART_IO_CHANGED = 1 << 1,
+ V3_RESTART_PARAM_VALUES_CHANGED = 1 << 2,
+ V3_RESTART_LATENCY_CHANGED = 1 << 3,
+ V3_RESTART_PARAM_TITLES_CHANGED = 1 << 4,
+ V3_RESTART_MIDI_CC_ASSIGNMENT_CHANGED = 1 << 5,
+ V3_RESTART_NOTE_EXPRESSION_CHANGED = 1 << 6,
+ V3_RESTART_IO_TITLES_CHANGED = 1 << 7,
+ V3_RESTART_PREFETCHABLE_SUPPORT_CHANGED = 1 << 8,
+ V3_RESTART_ROUTING_INFO_CHANGED = 1 << 9
+};
+
struct v3_component_handler {
struct v3_funknown;
diff --git a/distrho/src/travesty/message.h b/distrho/src/travesty/message.h
@@ -0,0 +1,55 @@
+/*
+ * travesty, pure C VST3-compatible interface
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include "base.h"
+
+#include "align_push.h"
+
+/**
+ * message
+ */
+
+struct v3_attribute_list;
+
+struct v3_message {
+ struct v3_funknown;
+
+ V3_API const char* (*get_message_id)(void* self);
+ V3_API void (*set_message_id)(void* self, const char* id);
+ V3_API v3_attribute_list* (*get_attributes)(void* self);
+};
+
+static constexpr const v3_tuid v3_message_iid =
+ V3_ID(0x936F033B, 0xC6C047DB, 0xBB0882F8, 0x13C1E613);
+
+/**
+ * connection point
+ */
+
+struct v3_connection_point {
+ struct v3_funknown;
+
+ V3_API v3_result (*connect)(void* self, struct v3_connection_point** other);
+ V3_API v3_result (*disconnect)(void* self, struct v3_connection_point** other);
+ V3_API v3_result (*notify)(void* self, struct v3_message** message);
+};
+
+static constexpr const v3_tuid v3_connection_point_iid =
+ V3_ID(0x70A4156F, 0x6E6E4026, 0x989148BF, 0xAA60D8D1);
+
+#include "align_pop.h"