DPF

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

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:
Mdistrho/src/DistrhoPluginVST3.cpp | 251++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mdistrho/src/DistrhoUIVST3.cpp | 213++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mdistrho/src/travesty/edit_controller.h | 13+++++++++++++
Adistrho/src/travesty/message.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
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"