DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 4c59baa3140863353827038b1e5966d7c1166880
parent 8e25227168fb528aaedf84efb0e875f9c248fbe8
Author: falkTX <falktx@falktx.com>
Date:   Sun, 26 Sep 2021 15:35:44 +0100

Experiments with VST3 full data passing

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
Mdistrho/src/DistrhoPluginVST3.cpp | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mdistrho/src/DistrhoUIVST3.cpp | 275++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mdistrho/src/travesty/message.h | 20++++++++++++++++++++
Mdistrho/src/travesty/view.h | 24++++++++++++++++++++++++
4 files changed, 449 insertions(+), 136 deletions(-)

diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -257,6 +257,11 @@ static constexpr void (*const snprintf_f32_utf16)(int16_t*, float, size_t) = snp static constexpr void (*const snprintf_u32_utf16)(int16_t*, uint32_t, size_t) = snprintf_utf16_t<uint32_t, format_u32>; // -------------------------------------------------------------------------------------------------------------------- +// TESTING + +v3_message** dpf_message_create(const char* id); + +// -------------------------------------------------------------------------------------------------------------------- /** * VST3 DSP class. @@ -287,6 +292,7 @@ public: PluginVst3() : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), fComponentHandler(nullptr), + fConnectionToUI(nullptr), fParameterOffset(fPlugin.getParameterOffset()), fRealParameterCount(fParameterOffset + fPlugin.getParameterCount()), fParameterValues(nullptr) @@ -394,6 +400,11 @@ public: return fPlugin.getSampleRate(); } + void setConnectionToUI(v3_connection_point** const point) noexcept + { + fConnectionToUI = point; + } + // ---------------------------------------------------------------------------------------------------------------- // v3_component interface calls @@ -1257,6 +1268,9 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fRealParameterCount, rindex, V3_INVALID_ARG); DISTRHO_SAFE_ASSERT_RETURN(value >= 0.0 && value <= 1.0, V3_INVALID_ARG); + // TESTING remove this + sendParameterChangeTest(rindex, value); + #if DISTRHO_PLUGIN_WANT_PROGRAMS if (rindex == 0) { @@ -1294,7 +1308,21 @@ public: } // ---------------------------------------------------------------------------------------------------------------- - // dpf_connection_point + // dpf_dsp_connection_point + + void connect(v3_connection_point** const other) + { + fConnectionToUI = other; + + d_stdout("---------------------------------------------------------- will send plugin state now"); + } + + void disconnect() + { + fConnectionToUI = nullptr; + + d_stdout("---------------------------------------------------------- ui conn now null"); + } v3_result notify(v3_message** const message) { @@ -1399,6 +1427,7 @@ private: // VST3 stuff v3_component_handler** fComponentHandler; + v3_connection_point** fConnectionToUI; // Temporary data const uint32_t fParameterOffset; @@ -1422,7 +1451,7 @@ private: #endif // ---------------------------------------------------------------------------------------------------------------- - // functions called from the plugin side, RT no block + // helper functions called during process, cannot block void updateParameterOutputsAndTriggers() { @@ -1460,6 +1489,28 @@ private: } // ---------------------------------------------------------------------------------------------------------------- + // helper functions called during message passing, can block + + void sendParameterChangeTest(const v3_param_id rindex, const double value) + { + d_stdout("will send message now"); + DISTRHO_SAFE_ASSERT_RETURN(fConnectionToUI != nullptr,); + + v3_message** const message = dpf_message_create("parameter-set"); + DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,); + + v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,); + + v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 2); + v3_cpp_obj(attrlist)->set_int(attrlist, "rindex", rindex); + v3_cpp_obj(attrlist)->set_float(attrlist, "value", value); + v3_cpp_obj(fConnectionToUI)->notify(fConnectionToUI, message); + + v3_cpp_obj_unref(message); + } + + // ---------------------------------------------------------------------------------------------------------------- // DPF callbacks bool requestParameterValueChange(const uint32_t index, const float value) @@ -1554,25 +1605,33 @@ private: // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_create (called from DSP side) -v3_funknown** dpf_plugin_view_create(v3_connection_point** connection, void* instancePointer, double sampleRate); +v3_plugin_view** dpf_plugin_view_create(void* instancePointer, double sampleRate); #endif // -------------------------------------------------------------------------------------------------------------------- -// dpf_connection_point +// dpf_dsp_connection_point + +enum ConnectionPointType { + kConnectionPointComponent, + kConnectionControllerToComponent, + kConnectionControllerToView +}; struct v3_connection_point_cpp : v3_funknown { v3_connection_point point; }; -struct dpf_connection_point : v3_connection_point_cpp { +struct dpf_dsp_connection_point : v3_connection_point_cpp { ScopedPointer<PluginVst3>& vst3; - const bool controller; // component otherwise - bool connected; + const ConnectionPointType type; + v3_connection_point** other; + v3_connection_point** bridge; // when type is controller this points to ctrl<->view point - dpf_connection_point(const bool isEditCtrl, ScopedPointer<PluginVst3>& v) + dpf_dsp_connection_point(const ConnectionPointType t, ScopedPointer<PluginVst3>& v) : vst3(v), - controller(isEditCtrl), - connected(false) + type(t), + other(nullptr), + bridge(nullptr) { static const uint8_t* kSupportedInterfaces[] = { v3_funknown_iid, @@ -1584,7 +1643,7 @@ struct dpf_connection_point : v3_connection_point_cpp { 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); + d_stdout("dpf_dsp_connection_point::query_interface => %p %s %p", self, tuid2str(iid), iface); *iface = NULL; DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); @@ -1609,40 +1668,121 @@ struct dpf_connection_point : v3_connection_point_cpp { 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; + d_stdout("dpf_dsp_connection_point::connect => %p %p", self, other); + dpf_dsp_connection_point* const point = *(dpf_dsp_connection_point**)self; DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT(point->bridge == nullptr); + + point->other = other; - const bool connected = point->connected; - DISTRHO_SAFE_ASSERT_RETURN(! connected, V3_INVALID_ARG); + if (point->type == kConnectionPointComponent) + if (PluginVst3* const vst3 = point->vst3) + vst3->connect((v3_connection_point**)self); - 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; + d_stdout("dpf_dsp_connection_point::disconnect => %p %p", self, other); + dpf_dsp_connection_point* const point = *(dpf_dsp_connection_point**)self; DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); + + point->other = nullptr; + point->bridge = nullptr; - const bool connected = point->connected; - DISTRHO_SAFE_ASSERT_RETURN(connected, V3_INVALID_ARG); + if (point->type == kConnectionPointComponent) + if (PluginVst3* const vst3 = point->vst3) + vst3->disconnect(); - 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; + d_stdout("dpf_dsp_connection_point::notify => %p %p", self, message); + dpf_dsp_connection_point* const point = *(dpf_dsp_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); + v3_connection_point** const other = point->other; + DISTRHO_SAFE_ASSERT_RETURN(other != nullptr, V3_NOT_INITIALISED); + + v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr, V3_INVALID_ARG); + + int64_t target = 0; + const v3_result res = v3_cpp_obj(attrlist)->get_int(attrlist, "__dpf_msg_target__", &target); + DISTRHO_SAFE_ASSERT_RETURN(res == V3_OK, res); + DISTRHO_SAFE_ASSERT_RETURN(target != 0, V3_INTERNAL_ERR); + + switch (point->type) + { + // pass message from component (aka plugin) to controller + case kConnectionPointComponent: + { + d_stdout("dpf_dsp_connection_point::notify kConnectionPointComponent"); + + switch (target) + { + case 1: + // message is from view to controller to component + return vst3->notify(message); + case 2: + // message is from component to controller to view + return v3_cpp_obj(other)->notify(other, message); + } + break; + } + + // pass message from controller to component (aka plugin) + case kConnectionControllerToComponent: + { + d_stdout("dpf_dsp_connection_point::notify kConnectionControllerToComponent"); + + switch (target) + { + case 1: + // message is from view to controller to component + return v3_cpp_obj(other)->notify(other, message); + case 2: + { + // message is from component to controller to view + v3_connection_point** const bridge = point->bridge; + DISTRHO_SAFE_ASSERT_RETURN(bridge != nullptr, V3_NOT_INITIALISED); + return v3_cpp_obj(bridge)->notify(bridge, message); + } + } + break; + } + + // pass message from from view (aka ui) to controller + case kConnectionControllerToView: + { + d_stdout("dpf_dsp_connection_point::notify kConnectionControllerToView"); + + switch (target) + { + case 1: + { + // message is from view to controller to component + v3_connection_point** const bridge = point->bridge; + DISTRHO_SAFE_ASSERT_RETURN(bridge != nullptr, V3_NOT_INITIALISED); + return v3_cpp_obj(bridge)->notify(bridge, message); + } + case 2: + // message is from component to controller to view + return v3_cpp_obj(other)->notify(other, message); + } + break; + } + } + + return V3_INTERNAL_ERR; }; } }; @@ -1656,15 +1796,18 @@ struct v3_edit_controller_cpp : v3_funknown { }; struct dpf_edit_controller : v3_edit_controller_cpp { - ScopedPointer<dpf_connection_point> connection; + ScopedPointer<dpf_dsp_connection_point> connectionComp; // kConnectionControllerToComponent + ScopedPointer<dpf_dsp_connection_point> connectionView; // kConnectionControllerToView ScopedPointer<PluginVst3>& vst3; bool initialized; // cached values + v3_connection_point** connectionToUI; v3_component_handler** handler; dpf_edit_controller(ScopedPointer<PluginVst3>& v) : vst3(v), initialized(false), + connectionToUI(nullptr), handler(nullptr) { static const uint8_t* kSupportedInterfacesBase[] = { @@ -1695,9 +1838,10 @@ struct dpf_edit_controller : v3_edit_controller_cpp { 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; + if (controller->connectionComp == nullptr) + controller->connectionComp = new dpf_dsp_connection_point(kConnectionControllerToComponent, + controller->vst3); + *iface = &controller->connectionComp; return V3_OK; } @@ -1734,6 +1878,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { DISTRHO_SAFE_ASSERT_RETURN(initialized, V3_INVALID_ARG); controller->initialized = false; + controller->connectionToUI = nullptr; return V3_OK; }; @@ -1880,14 +2025,6 @@ struct dpf_edit_controller : v3_edit_controller_cpp { PluginVst3* const vst3 = controller->vst3; DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); -// if (dpf_plugin_view* const view = controller->view) -// { -// if (UIVst3* const uivst3 = view->uivst3) -// { -// uivst3->setParameterValueFromDSP(index, vst3->normalisedParameterToPlain(index, normalised)); -// } -// } - return vst3->setParameterNormalized(index, normalised); }; @@ -1911,39 +2048,37 @@ struct dpf_edit_controller : v3_edit_controller_cpp { dpf_edit_controller* const controller = *(dpf_edit_controller**)self; DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); -#if DISTRHO_PLUGIN_HAS_UI - // 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); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); - if (controller->connection != nullptr) - { - // if there is a connection point, 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; - } +#if 1 // DISTRHO_PLUGIN_HAS_UI + // we require a component connection + DISTRHO_SAFE_ASSERT_RETURN(controller->connectionComp != nullptr, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(controller->connectionComp->other != nullptr, nullptr); - void* instancePointer; - double sampleRate; + v3_plugin_view** const view = dpf_plugin_view_create(vst3->getInstancePointer(), + vst3->getSampleRate()); + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, nullptr); - if (PluginVst3* const vst3 = controller->vst3) - { - instancePointer = vst3->getInstancePointer(); - sampleRate = vst3->getSampleRate(); - } - else + v3_connection_point** connection = nullptr; + if (v3_cpp_obj_query_interface(view, v3_connection_point_iid, &connection) == V3_OK) { - instancePointer = nullptr; - sampleRate = 44100.0; + d_stdout("view connection query ok %p", connection); + + v3_connection_point** const bridge = (v3_connection_point**)&controller->connectionComp; + controller->connectionView = new dpf_dsp_connection_point(kConnectionControllerToView, + controller->vst3); + + v3_connection_point** const other = (v3_connection_point**)&controller->connectionView; + v3_cpp_obj(connection)->connect(connection, other); + v3_cpp_obj(other)->connect(other, connection); + + controller->connectionComp->bridge = other; + controller->connectionView->bridge = bridge; + } - return (v3_plugin_view**)dpf_plugin_view_create((v3_connection_point**)&controller->connection, - instancePointer, sampleRate); + return view; #else return nullptr; #endif @@ -2275,7 +2410,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_dsp_connection_point> connection; // kConnectionPointComponent ScopedPointer<dpf_edit_controller> controller; // ScopedPointer<dpf_state_stream> stream; ScopedPointer<PluginVst3> vst3; @@ -2321,7 +2456,8 @@ struct dpf_component : v3_component_cpp { if (v3_tuid_match(v3_connection_point_iid, iid)) { if (component->connection == nullptr) - component->connection = new dpf_connection_point(false, component->vst3); + component->connection = new dpf_dsp_connection_point(kConnectionPointComponent, + component->vst3); *iface = &component->connection; return V3_OK; } diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp @@ -49,11 +49,9 @@ /* TODO items: * - disable UI if non-embed UI build * - parameter change listener - * - parameter change sender * - program change listener * - program change sender * - state change listener - * - state change sender * - sample rate change listener * - call component handler restart with params-changed flag when setting program? */ @@ -78,12 +76,13 @@ void strncpy_utf16(int16_t* dst, const char* src, size_t length); // -------------------------------------------------------------------------------------------------------------------- // create message object (needed by the UI class, implementation comes later) -static v3_message** dpf_message_create(const char* id); +v3_message** dpf_message_create(const char* id); // -------------------------------------------------------------------------------------------------------------------- // custom attribute list struct, used for sending utf8 strings struct v3_attribute_list_utf8 { + struct v3_funknown; V3_API v3_result (*set_string_utf8)(void* self, const char* id, const char* string); V3_API v3_result (*get_string_utf8)(void* self, const char* id, char* string, uint32_t size); }; @@ -112,7 +111,6 @@ class UIVst3 : public Thread { public: UIVst3(v3_plugin_view** const view, - v3_connection_point** const connection, const intptr_t winId, const float scaleFactor, const double sampleRate, @@ -128,7 +126,7 @@ public: instancePointer, scaleFactor), fView(view), - fConnection(connection), + fConnection(nullptr), fFrame(nullptr), fScaleFactor(scaleFactor) { @@ -231,6 +229,53 @@ public: } // ---------------------------------------------------------------------------------------------------------------- + // dpf_ui_connection_point + + void connect(v3_connection_point** const point) noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr,); + + fConnection = point; + } + + void disconnect() noexcept + { + fConnection = nullptr; + } + + v3_result notify(v3_message** const message) + { + const char* const msgid = v3_cpp_obj(message)->get_message_id(message); + DISTRHO_SAFE_ASSERT_RETURN(msgid != nullptr, V3_INVALID_ARG); + + v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr, V3_INVALID_ARG); + + if (std::strcmp(msgid, "parameter-set") == 0) + { + int64_t rindex; + double value; + v3_result res; + + res = v3_cpp_obj(attrs)->get_int(attrs, "rindex", &rindex); + DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); + + res = v3_cpp_obj(attrs)->get_float(attrs, "value", &value); + DISTRHO_SAFE_ASSERT_INT_RETURN(res == V3_OK, res, res); + + rindex -= fUI.getParameterOffset(); + DISTRHO_SAFE_ASSERT_RETURN(rindex >= 0, V3_INTERNAL_ERR); + + fUI.parameterChanged(rindex, value); + return V3_OK; + } + + d_stdout("UIVst3 received unknown msg '%s'", msgid); + + return V3_NOT_IMPLEMENTED; + } + + // ---------------------------------------------------------------------------------------------------------------- private: // Plugin UI @@ -238,7 +283,7 @@ private: // VST3 stuff v3_plugin_view** const fView; - v3_connection_point** const fConnection; + v3_connection_point** fConnection; v3_plugin_frame** fFrame; // Temporary data @@ -254,11 +299,12 @@ private: v3_message** const message = dpf_message_create("parameter-edit"); DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,); - v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message); - DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr,); + v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,); - v3_cpp_obj(attrs)->set_int(attrs, "rindex", rindex); - v3_cpp_obj(attrs)->set_int(attrs, "started", started ? 1 : 0); + v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 1); + v3_cpp_obj(attrlist)->set_int(attrlist, "rindex", rindex); + v3_cpp_obj(attrlist)->set_int(attrlist, "started", started ? 1 : 0); v3_cpp_obj(fConnection)->notify(fConnection, message); v3_cpp_obj_unref(message); @@ -276,11 +322,12 @@ private: v3_message** const message = dpf_message_create("parameter-set"); DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,); - v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message); - DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr,); + v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,); - v3_cpp_obj(attrs)->set_int(attrs, "rindex", rindex); - v3_cpp_obj(attrs)->set_float(attrs, "value", realValue); + v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 1); + v3_cpp_obj(attrlist)->set_int(attrlist, "rindex", rindex); + v3_cpp_obj(attrlist)->set_float(attrlist, "value", realValue); v3_cpp_obj(fConnection)->notify(fConnection, message); v3_cpp_obj_unref(message); @@ -323,15 +370,16 @@ private: v3_message** const message = dpf_message_create("midi"); DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,); - v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message); - DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr,); + v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,); uint8_t midiData[3]; midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel; midiData[1] = note; midiData[2] = velocity; - v3_cpp_obj(attrs)->set_binary(attrs, "data", midiData, sizeof(midiData)); + v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 1); + v3_cpp_obj(attrlist)->set_binary(attrlist, "data", midiData, sizeof(midiData)); v3_cpp_obj(fConnection)->notify(fConnection, message); v3_cpp_obj_unref(message); @@ -351,15 +399,16 @@ private: v3_message** const message = dpf_message_create("state-set"); DISTRHO_SAFE_ASSERT_RETURN(message != nullptr,); - v3_attribute_list** const attrs = v3_cpp_obj(message)->get_attributes(message); - DISTRHO_SAFE_ASSERT_RETURN(attrs != nullptr,); + v3_attribute_list** const attrlist = v3_cpp_obj(message)->get_attributes(message); + DISTRHO_SAFE_ASSERT_RETURN(attrlist != nullptr,); - v3_attribute_list_utf8** utf8attrs = nullptr; - DISTRHO_SAFE_ASSERT_RETURN(v3_cpp_obj_query_interface(attrs, v3_attribute_list_utf8_iid, &utf8attrs) == V3_OK,); - DISTRHO_SAFE_ASSERT_RETURN(utf8attrs != nullptr,); + v3_attribute_list_utf8** utf8attrlist = nullptr; + DISTRHO_SAFE_ASSERT_RETURN(v3_cpp_obj_query_interface(attrlist, v3_attribute_list_utf8_iid, &utf8attrs) == V3_OK,); + DISTRHO_SAFE_ASSERT_RETURN(utf8attrlist != nullptr,); - v3_cpp_obj(utf8attrs)->set_string_utf8(utf8attrs, "key", key); - v3_cpp_obj(utf8attrs)->set_string_utf8(utf8attrs, "value", value); + v3_cpp_obj(attrlist)->set_int(attrlist, "__dpf_msg_target__", 1); + v3_cpp_obj(utf8attrlist)->set_string_utf8(utf8attrlist, "key", key); + v3_cpp_obj(utf8attrlist)->set_string_utf8(utf8attrlist, "value", value); v3_cpp_obj(fConnection)->notify(fConnection, message); v3_cpp_obj_unref(message); @@ -410,16 +459,16 @@ static void dpf_attribute_list_free(std::map<std::string, dpf_attribute_value>& } // -------------------------------------------------------------------------------------------------------------------- -// dpf_attribute_list_dpf (the custom utf8 variant) +// dpf_attribute_list_utf8 (the custom variant) struct v3_attribute_list_utf8_cpp : v3_funknown { v3_attribute_list_utf8 attr; }; -struct dpf_attribute_list_dpf : v3_attribute_list_utf8_cpp { +struct dpf_attribute_list_utf8 : v3_attribute_list_utf8_cpp { std::map<std::string, dpf_attribute_value>& attrs; - dpf_attribute_list_dpf(std::map<std::string, dpf_attribute_value>& a) + dpf_attribute_list_utf8(std::map<std::string, dpf_attribute_value>& a) : attrs(a) { static const uint8_t* kSupportedInterfaces[] = { @@ -432,7 +481,7 @@ struct dpf_attribute_list_dpf : v3_attribute_list_utf8_cpp { query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result { - d_stdout("dpf_attribute_list_dpf::query_interface => %p %s %p", self, tuid2str(iid), iface); + d_stdout("dpf_attribute_list_utf8::query_interface => %p %s %p", self, tuid2str(iid), iface); *iface = NULL; DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); @@ -457,7 +506,7 @@ struct dpf_attribute_list_dpf : v3_attribute_list_utf8_cpp { attr.set_string_utf8 = []V3_API(void* self, const char* id, const char* string) -> v3_result { - dpf_attribute_list_dpf* const attr = *(dpf_attribute_list_dpf**)self; + dpf_attribute_list_utf8* const attr = *(dpf_attribute_list_utf8**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); const uint32_t size = std::strlen(string) + 1; @@ -475,7 +524,7 @@ struct dpf_attribute_list_dpf : v3_attribute_list_utf8_cpp { attr.get_string_utf8 = []V3_API(void* self, const char* id, char*, uint32_t) -> v3_result { - dpf_attribute_list_dpf* const attr = *(dpf_attribute_list_dpf**)self; + dpf_attribute_list_utf8* const attr = *(dpf_attribute_list_utf8**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); if (attr->attrs.find(id) == attr->attrs.end()) @@ -489,12 +538,8 @@ struct dpf_attribute_list_dpf : v3_attribute_list_utf8_cpp { // -------------------------------------------------------------------------------------------------------------------- // dpf_attribute_list -struct v3_attribute_list_cpp : v3_funknown { - v3_attribute_list attr; -}; - struct dpf_attribute_list : v3_attribute_list_cpp { - ScopedPointer<dpf_attribute_list_dpf> attrdpf; + ScopedPointer<dpf_attribute_list_utf8> attrutf8; std::map<std::string, dpf_attribute_value> attrs; dpf_attribute_list() @@ -527,9 +572,9 @@ struct dpf_attribute_list : v3_attribute_list_cpp { if (v3_tuid_match(v3_attribute_list_utf8_iid, iid)) { - if (attr->attrdpf == nullptr) - attr->attrdpf = new dpf_attribute_list_dpf(attr->attrs); - *iface = &attr->attrdpf; + if (attr->attrutf8 == nullptr) + attr->attrutf8 = new dpf_attribute_list_utf8(attr->attrs); + *iface = &attr->attrutf8; return V3_OK; } @@ -543,7 +588,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { // ------------------------------------------------------------------------------------------------------------ // v3_attribute_list - attr.set_int = []V3_API(void* self, const char* id, int64_t value) -> v3_result + attrlist.set_int = []V3_API(void* self, const char* id, int64_t value) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -554,7 +599,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_OK; }; - attr.get_int = []V3_API(void* self, const char* id, int64_t* value) -> v3_result + attrlist.get_int = []V3_API(void* self, const char* id, int64_t* value) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -569,7 +614,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_OK; }; - attr.set_float = []V3_API(void* self, const char* id, double value) -> v3_result + attrlist.set_float = []V3_API(void* self, const char* id, double value) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -580,7 +625,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_OK; }; - attr.get_float = []V3_API(void* self, const char* id, double* value) -> v3_result + attrlist.get_float = []V3_API(void* self, const char* id, double* value) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -595,7 +640,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_OK; }; - attr.set_string = []V3_API(void* self, const char* id, const int16_t* /*string*/) -> v3_result + attrlist.set_string = []V3_API(void* self, const char* id, const int16_t* /*string*/) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -607,7 +652,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_NOT_IMPLEMENTED; }; - attr.get_string = []V3_API(void* self, const char* id, int16_t* /*string*/, uint32_t /*size*/) -> v3_result + attrlist.get_string = []V3_API(void* self, const char* id, int16_t* /*string*/, uint32_t /*size*/) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -621,7 +666,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_NOT_IMPLEMENTED; }; - attr.set_binary = []V3_API(void* self, const char* id, const void* data, uint32_t size) -> v3_result + attrlist.set_binary = []V3_API(void* self, const char* id, const void* data, uint32_t size) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -638,7 +683,7 @@ struct dpf_attribute_list : v3_attribute_list_cpp { return V3_NOT_IMPLEMENTED; }; - attr.get_binary = []V3_API(void* self, const char* id, const void** data, uint32_t* size) -> v3_result + attrlist.get_binary = []V3_API(void* self, const char* id, const void** data, uint32_t* size) -> v3_result { dpf_attribute_list* const attr = *(dpf_attribute_list**)self; DISTRHO_SAFE_ASSERT_RETURN(attr != nullptr, V3_NOT_INITIALISED); @@ -659,10 +704,6 @@ struct dpf_attribute_list : v3_attribute_list_cpp { // -------------------------------------------------------------------------------------------------------------------- // dpf_message -struct v3_message_cpp : v3_funknown { - v3_message msg; -}; - struct dpf_message : v3_message_cpp { std::atomic<int> refcounter; ScopedPointer<dpf_message>* self; @@ -761,7 +802,7 @@ struct dpf_message : v3_message_cpp { } }; -static v3_message** dpf_message_create(const char* const id) +v3_message** dpf_message_create(const char* const id) { ScopedPointer<dpf_message>* const messageptr = new ScopedPointer<dpf_message>; *messageptr = new dpf_message(messageptr, id); @@ -771,10 +812,6 @@ static v3_message** dpf_message_create(const char* const id) // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_content_scale -struct v3_plugin_view_content_scale_cpp : v3_funknown { - v3_plugin_view_content_scale scale; -}; - struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp { ScopedPointer<UIVst3>& uivst3; // cached values @@ -839,32 +876,113 @@ struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp { }; // -------------------------------------------------------------------------------------------------------------------- -// dpf_plugin_view +// dpf_ui_connection_point + +struct dpf_ui_connection_point : v3_connection_point_cpp { + ScopedPointer<UIVst3>& uivst3; + v3_connection_point** other; + + dpf_ui_connection_point(ScopedPointer<UIVst3>& v) + : uivst3(v), + other(nullptr) + { + 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_ui_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_ui_connection_point::connect => %p %p", self, other); + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG); + + point->other = other; + + if (UIVst3* const uivst3 = point->uivst3) + uivst3->connect(other); + + return V3_OK; + }; + + point.disconnect = []V3_API(void* self, struct v3_connection_point** other) -> v3_result + { + d_stdout("dpf_ui_connection_point::disconnect => %p %p", self, other); + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); + + point->other = nullptr; + + if (UIVst3* const uivst3 = point->uivst3) + uivst3->disconnect(); + + return V3_OK; + }; + + point.notify = []V3_API(void* self, struct v3_message** message) -> v3_result + { + d_stdout("dpf_ui_connection_point::notify => %p %p", self, message); + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + + UIVst3* const uivst3 = point->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); -struct v3_plugin_view_cpp : v3_funknown { - v3_plugin_view view; + return uivst3->notify(message); + }; + } }; +// -------------------------------------------------------------------------------------------------------------------- +// dpf_plugin_view + struct dpf_plugin_view : v3_plugin_view_cpp { std::atomic<int> refcounter; ScopedPointer<dpf_plugin_view>* self; ScopedPointer<dpf_plugin_view_content_scale> scale; + ScopedPointer<dpf_ui_connection_point> connection; ScopedPointer<UIVst3> uivst3; // cached values - v3_connection_point** const connection; void* const instancePointer; double sampleRate; v3_plugin_frame** frame = nullptr; - dpf_plugin_view(ScopedPointer<dpf_plugin_view>* selfptr, - v3_connection_point** const connectionptr, - void* const instance, - const double sr) + dpf_plugin_view(ScopedPointer<dpf_plugin_view>* selfptr, void* const instance, const double sr) : refcounter(1), self(selfptr), - connection(connectionptr), instancePointer(instance), - sampleRate(sr) + sampleRate(sr), + frame(nullptr) { static const uint8_t* kSupportedInterfacesBase[] = { v3_funknown_iid, @@ -902,6 +1020,14 @@ struct dpf_plugin_view : v3_plugin_view_cpp { dpf_plugin_view* const view = *(dpf_plugin_view**)self; DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE); + if (v3_tuid_match(v3_connection_point_iid, iid)) + { + if (view->connection == nullptr) + view->connection = new dpf_ui_connection_point(view->uivst3); + *iface = &view->connection; + return V3_OK; + } + if (v3_tuid_match(v3_plugin_view_content_scale_iid, iid)) { if (view->scale == nullptr) @@ -931,6 +1057,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { if (const int refcounter = --view->refcounter) return refcounter; + if (view->connection != nullptr && view->connection->other) + v3_cpp_obj(view->connection->other)->disconnect(view->connection->other, + (v3_connection_point**)&view->connection); + *view->self = nullptr; delete (dpf_plugin_view**)self; return 0; @@ -967,11 +1097,15 @@ struct dpf_plugin_view : v3_plugin_view_cpp { { const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; view->uivst3 = new UIVst3((v3_plugin_view**)view->self, - view->connection, (uintptr_t)parent, scaleFactor, view->sampleRate, view->instancePointer); + + if (dpf_ui_connection_point* const point = view->connection) + if (point->other != nullptr) + view->uivst3->connect(point->other); + view->uivst3->setFrame(view->frame); return V3_OK; } @@ -1111,14 +1245,13 @@ struct dpf_plugin_view : v3_plugin_view_cpp { // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_create (called from plugin side) -v3_funknown** dpf_plugin_view_create(v3_connection_point** connection, void* instancePointer, double sampleRate); +v3_plugin_view** dpf_plugin_view_create(void* instancePointer, double sampleRate); -v3_funknown** dpf_plugin_view_create(v3_connection_point** const connection, - void* const instancePointer, const double sampleRate) +v3_plugin_view** dpf_plugin_view_create(void* const instancePointer, const double sampleRate) { ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>; - *viewptr = new dpf_plugin_view(viewptr, connection, instancePointer, sampleRate); - return (v3_funknown**)viewptr; + *viewptr = new dpf_plugin_view(viewptr, instancePointer, sampleRate); + return (v3_plugin_view**)static_cast<void*>(viewptr); } // -------------------------------------------------------------------------------------------------------------------- diff --git a/distrho/src/travesty/message.h b/distrho/src/travesty/message.h @@ -70,4 +70,24 @@ struct v3_connection_point { static constexpr const v3_tuid v3_connection_point_iid = V3_ID(0x70A4156F, 0x6E6E4026, 0x989148BF, 0xAA60D8D1); +#ifdef __cplusplus + +/** + * C++ variants + */ + +struct v3_attribute_list_cpp : v3_funknown { + v3_attribute_list attrlist; +}; + +struct v3_message_cpp : v3_funknown { + v3_message msg; +}; + +struct v3_connection_point_cpp : v3_funknown { + v3_connection_point point; +}; + +#endif + #include "align_pop.h" diff --git a/distrho/src/travesty/view.h b/distrho/src/travesty/view.h @@ -106,3 +106,27 @@ struct v3_plugin_view_parameter_finder { static constexpr const v3_tuid v3_plugin_view_parameter_finder_iid = V3_ID(0x0F618302, 0x215D4587, 0xA512073C, 0x77B9D383); + +#ifdef __cplusplus + +/** + * C++ variants + */ + +struct v3_plugin_view_cpp : v3_funknown { + v3_plugin_view view; +}; + +struct v3_plugin_frame_cpp : v3_funknown { + v3_plugin_frame frame; +}; + +struct v3_plugin_view_content_scale_cpp : v3_funknown { + v3_plugin_view_content_scale scale; +}; + +struct v3_plugin_view_parameter_finder_cpp : v3_funknown { + v3_plugin_view_parameter_finder finder; +}; + +#endif