diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp index 2dad509f..d92dd48c 100644 --- a/distrho/src/DistrhoPluginVST3.cpp +++ b/distrho/src/DistrhoPluginVST3.cpp @@ -37,7 +37,21 @@ #include "travesty/factory.h" #include "travesty/host.h" -#include +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +# include +#else +// quick and dirty std::atomic replacement for the things we need +namespace std { + struct atomic_int { + volatile int value; + explicit atomic_int(volatile int v) noexcept : value(v) {} + int operator++() volatile noexcept { return __atomic_add_fetch(&value, 1, __ATOMIC_RELAXED); } + int operator--() volatile noexcept { return __atomic_sub_fetch(&value, 1, __ATOMIC_RELAXED); } + operator int() volatile noexcept { return __atomic_load_n(&value, __ATOMIC_RELAXED); } + }; +} +#endif + #include #include #include @@ -80,7 +94,9 @@ typedef std::map StringMap; // custom v3_tuid compatible type typedef uint32_t dpf_tuid[4]; +#ifdef DISTRHO_PROPER_CPP11_SUPPORT static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch"); +#endif // -------------------------------------------------------------------------------------------------------------------- // custom, constant uids related to DPF @@ -246,16 +262,16 @@ void strncpy_utf16(int16_t* const dst, const char* const src, const size_t lengt // -------------------------------------------------------------------------------------------------------------------- -template -static void snprintf_t(char* const dst, const T value, const size_t size) +template +static void snprintf_t(char* const dst, const T value, const char* const format, const size_t size) { DISTRHO_SAFE_ASSERT_RETURN(size > 0,); std::snprintf(dst, size-1, format, value); dst[size-1] = '\0'; } -template -static void snprintf_utf16_t(int16_t* const dst, const T value, const size_t size) +template +static void snprintf_utf16_t(int16_t* const dst, const T value, const char* const format, const size_t size) { DISTRHO_SAFE_ASSERT_RETURN(size > 0,); @@ -269,16 +285,26 @@ static void snprintf_utf16_t(int16_t* const dst, const T value, const size_t siz std::free(tmpbuf); } -static constexpr const char format_i32[] = "%d"; -static constexpr const char format_f32[] = "%f"; -static constexpr const char format_u32[] = "%u"; +static inline +void snprintf_u32(char* const dst, const uint32_t value, const size_t size) +{ + return snprintf_t(dst, value, "%u", size); +} + +static inline +void snprintf_f32_utf16(int16_t* const dst, const float value, const size_t size) +{ + return snprintf_utf16_t(dst, value, "%f", size); +} -static constexpr void (*const snprintf_u32)(char*, uint32_t, size_t) = snprintf_t; -static constexpr void (*const snprintf_f32_utf16)(int16_t*, float, size_t) = snprintf_utf16_t; -static constexpr void (*const snprintf_u32_utf16)(int16_t*, uint32_t, size_t) = snprintf_utf16_t; +static inline +void snprintf_u32_utf16(int16_t* const dst, const uint32_t value, const size_t size) +{ + return snprintf_utf16_t(dst, value, "%u", size); +} // -------------------------------------------------------------------------------------------------------------------- -// handy way to create a utf16 string during the current function scope, used for DSP->UI communication +// handy way to create a utf16 string on the current function scope, used for message strings struct ScopedUTF16String { int16_t* str; @@ -333,11 +359,18 @@ class PluginVst3 * MIDI will have a single bus, nothing special there. */ struct BusInfo { - uint8_t audio = 0; // either 0 or 1 - uint8_t sidechain = 0; // either 0 or 1 - uint32_t numMainAudio = 0; - uint32_t numSidechain = 0; - uint32_t numCV = 0; + uint8_t audio; // either 0 or 1 + uint8_t sidechain; // either 0 or 1 + uint32_t numMainAudio; + uint32_t numSidechain; + uint32_t numCV; + + BusInfo() + : audio(0), + sidechain(0), + numMainAudio(0), + numSidechain(0), + numCV(0) {} } inputBuses, outputBuses; public: @@ -1410,12 +1443,10 @@ public: // set up flags int32_t flags = 0; - const auto desig = fPlugin.getParameterDesignation(index); - const auto hints = fPlugin.getParameterHints(index); - const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); + const uint32_t hints = fPlugin.getParameterHints(index); - switch (desig) + switch (fPlugin.getParameterDesignation(index)) { case kParameterDesignationNull: break; @@ -2155,6 +2186,65 @@ private: * VST3 low-level pointer thingies follow, proceed with care. */ +// -------------------------------------------------------------------------------------------------------------------- +// v3_funknown for static and single instances of classes + +template +static V3_API v3_result dpf_static__query_interface(void* self, const v3_tuid iid, void** iface) +{ + if (v3_tuid_match(iid, v3_funknown_iid)) + { + *iface = self; + return V3_OK; + } + + if (v3_tuid_match(iid, v3_interface)) + { + *iface = self; + return V3_OK; + } + + *iface = NULL; + return V3_NO_INTERFACE; +} + +template +static V3_API v3_result dpf_static__query_interface(void* self, const v3_tuid iid, void** iface) +{ + if (v3_tuid_match(iid, v3_funknown_iid)) + { + *iface = self; + return V3_OK; + } + + if (v3_tuid_match(iid, v3_interface1) || v3_tuid_match(iid, v3_interface2) || v3_tuid_match(iid, v3_interface3)) + { + *iface = self; + return V3_OK; + } + + *iface = NULL; + return V3_NO_INTERFACE; +} + +static V3_API uint32_t dpf_static__ref(void*) { return 1; } +static V3_API uint32_t dpf_static__unref(void*) { return 0; } + +// -------------------------------------------------------------------------------------------------------------------- +// v3_funknown with refcounter + +template +static V3_API uint32_t dpf_refcounter__ref(void* self) +{ + return ++(*(T**)self)->refcounter; +} + +template +static V3_API uint32_t dpf_refcounter__unref(void* self) +{ + return --(*(T**)self)->refcounter; +} + #if DISTRHO_PLUGIN_HAS_UI // -------------------------------------------------------------------------------------------------------------------- // dpf_dsp_connection_point @@ -2165,11 +2255,8 @@ enum ConnectionPointType { kConnectionPointBridge }; -struct v3_connection_point_cpp : v3_funknown { - v3_connection_point point; -}; - struct dpf_dsp_connection_point : v3_connection_point_cpp { + std::atomic_int refcounter; ScopedPointer& vst3; const ConnectionPointType type; v3_connection_point** other; @@ -2177,154 +2264,137 @@ struct dpf_dsp_connection_point : v3_connection_point_cpp { bool shortcircuit; // plugin as controller, should pass directly to view dpf_dsp_connection_point(const ConnectionPointType t, ScopedPointer& v) - : vst3(v), + : refcounter(1), + vst3(v), type(t), other(nullptr), bridge(nullptr), shortcircuit(false) { - static const uint8_t* kSupportedInterfaces[] = { - v3_funknown_iid, - v3_connection_point_iid - }; + static constexpr const v3_tuid interface = V3_ID_COPY(v3_connection_point_iid); - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown - - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - 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); - - for (const uint8_t* interface_iid : kSupportedInterfaces) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } + // v3_funknown, single instance + query_interface = dpf_static__query_interface; + ref = dpf_refcounter__ref; + unref = dpf_refcounter__unref; - return V3_NO_INTERFACE; - }; + // v3_connection_point + point.connect = connect; + point.disconnect = disconnect; + point.notify = notify; + } - // 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 - // ------------------------------------------------------------------------------------------------------------ - // v3_connection_point + static V3_API v3_result connect(void* self, v3_connection_point** other) + { + 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_INITIALIZED); + DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT(point->bridge == nullptr); - point.connect = []V3_API(void* self, v3_connection_point** other) -> v3_result - { - 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; - point->other = other; + if (point->type == kConnectionPointComponent) + if (PluginVst3* const vst3 = point->vst3) + vst3->connect((v3_connection_point**)self); - if (point->type == kConnectionPointComponent) - if (PluginVst3* const vst3 = point->vst3) - vst3->connect((v3_connection_point**)self); + return V3_OK; + } - return V3_OK; - }; + static V3_API v3_result disconnect(void* self, v3_connection_point** other) + { + 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_INITIALIZED); + DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); - point.disconnect = []V3_API(void* self, v3_connection_point** other) -> v3_result - { - 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; - point->other = nullptr; - point->bridge = nullptr; + if (point->type == kConnectionPointComponent) + if (PluginVst3* const vst3 = point->vst3) + vst3->disconnect(); - if (point->type == kConnectionPointComponent) - if (PluginVst3* const vst3 = point->vst3) - vst3->disconnect(); + return V3_OK; + } - return V3_OK; - }; + static V3_API v3_result notify(void* self, v3_message** message) + { + dpf_dsp_connection_point* const point = *(dpf_dsp_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALIZED); - point.notify = []V3_API(void* self, v3_message** message) -> v3_result - { - 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_INITIALIZED); - PluginVst3* const vst3 = point->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + v3_connection_point** const other = point->other; + DISTRHO_SAFE_ASSERT_RETURN(other != nullptr, V3_NOT_INITIALIZED); - 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); - 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_INT_RETURN(target == 1 || target == 2, target, V3_INTERNAL_ERR); - 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_INT_RETURN(target == 1 || target == 2, target, V3_INTERNAL_ERR); + switch (point->type) + { + // message belongs to component (aka plugin) + case kConnectionPointComponent: + if (target == 1) + { + // view -> edit controller -> component + return vst3->notify(message); + } + else + { + // message is from component to controller to view + return v3_cpp_obj(other)->notify(other, message); + } - switch (point->type) + // message belongs to edit controller + case kConnectionPointController: + if (target == 1) { - // message belongs to component (aka plugin) - case kConnectionPointComponent: - if (target == 1) - { - // view -> edit controller -> component + // we are in view<->dsp short-circuit, all happens in the controller without bridge + if (point->shortcircuit) return vst3->notify(message); - } - else - { - // message is from component to controller to view - return v3_cpp_obj(other)->notify(other, message); - } - // message belongs to edit controller - case kConnectionPointController: - if (target == 1) - { - // we are in view<->dsp short-circuit, all happens in the controller without bridge - if (point->shortcircuit) - return vst3->notify(message); - - // view -> edit controller -> component + // view -> edit controller -> component + return v3_cpp_obj(other)->notify(other, message); + } + else + { + // we are in view<->dsp short-circuit, all happens in the controller without bridge + if (point->shortcircuit) return v3_cpp_obj(other)->notify(other, message); - } - else - { - // we are in view<->dsp short-circuit, all happens in the controller without bridge - if (point->shortcircuit) - return v3_cpp_obj(other)->notify(other, message); - - // 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); - } - // message belongs to bridge (aka ui) - case kConnectionPointBridge: - if (target == 1) - { - // view -> edit controller -> 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); - } - else - { - // message is from component to controller to view - return v3_cpp_obj(other)->notify(other, message); - } + // message is from component to controller to view + v3_connection_point** const bridge = point->bridge; + DISTRHO_SAFE_ASSERT_RETURN(bridge != nullptr, V3_NOT_INITIALIZED); + return v3_cpp_obj(bridge)->notify(bridge, message); + } + + // message belongs to bridge (aka ui) + case kConnectionPointBridge: + if (target == 1) + { + // view -> edit controller -> component + v3_connection_point** const bridge = point->bridge; + DISTRHO_SAFE_ASSERT_RETURN(bridge != nullptr, V3_NOT_INITIALIZED); + return v3_cpp_obj(bridge)->notify(bridge, message); + } + else + { + // message is from component to controller to view + return v3_cpp_obj(other)->notify(other, message); } + } - return V3_INTERNAL_ERR; - }; + return V3_INTERNAL_ERR; } }; #endif @@ -2334,60 +2404,39 @@ struct dpf_dsp_connection_point : v3_connection_point_cpp { // dpf_midi_mapping struct dpf_midi_mapping : v3_midi_mapping_cpp { - ScopedPointer& vst3; - - dpf_midi_mapping(ScopedPointer& v) - : vst3(v) + dpf_midi_mapping() { - static const uint8_t* kSupportedInterfaces[] = { - v3_funknown_iid, - v3_midi_mapping_iid - }; + static constexpr const v3_tuid interface = V3_ID_COPY(v3_midi_mapping_iid); - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown + // v3_funknown, used statically + query_interface = dpf_static__query_interface; + ref = dpf_static__ref; + unref = dpf_static__unref; - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_midi_mapping::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_midi_mapping + map.get_midi_controller_assignment = get_midi_controller_assignment; + } - map.get_midi_controller_assignment = []V3_API(void*, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id) -> v3_result - { - DISTRHO_SAFE_ASSERT_INT_RETURN(bus == 0, bus, V3_FALSE); - DISTRHO_SAFE_ASSERT_INT_RETURN(channel >= 0 && channel < 16, channel, V3_FALSE); - DISTRHO_SAFE_ASSERT_INT_RETURN(cc >= 0 && cc < 130, cc, V3_FALSE); + // ---------------------------------------------------------------------------------------------------------------- + // v3_midi_mapping -#if DISTRHO_PLUGIN_WANT_PROGRAMS - static constexpr const v3_param_id offset = 1; -#else - static const constexpr v3_param_id offset = 0; -#endif + static V3_API v3_result get_midi_controller_assignment(void*, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id) + { + DISTRHO_SAFE_ASSERT_INT_RETURN(bus == 0, bus, V3_FALSE); + DISTRHO_SAFE_ASSERT_INT_RETURN(channel >= 0 && channel < 16, channel, V3_FALSE); + DISTRHO_SAFE_ASSERT_INT_RETURN(cc >= 0 && cc < 130, cc, V3_FALSE); - *id = offset + channel * 130 + cc; - return V3_OK; - }; +# if DISTRHO_PLUGIN_WANT_PROGRAMS + static constexpr const v3_param_id offset = 1; +# else + static const constexpr v3_param_id offset = 0; +# endif + + *id = offset + channel * 130 + cc; + return V3_OK; } + + DISTRHO_PREVENT_HEAP_ALLOCATION }; #endif @@ -2395,12 +2444,10 @@ struct dpf_midi_mapping : v3_midi_mapping_cpp { // dpf_edit_controller struct dpf_edit_controller : v3_edit_controller_cpp { + std::atomic_int refcounter; #if DISTRHO_PLUGIN_HAS_UI ScopedPointer connectionComp; // kConnectionPointController ScopedPointer connectionBridge; // kConnectionPointBridge -#endif -#if DISTRHO_PLUGIN_WANT_MIDI_INPUT - ScopedPointer midiMapping; #endif ScopedPointer& vst3; bool initialized; @@ -2409,389 +2456,401 @@ struct dpf_edit_controller : v3_edit_controller_cpp { v3_plugin_base::v3_funknown** hostContext; dpf_edit_controller(ScopedPointer& v) - : vst3(v), + : refcounter(1), + vst3(v), initialized(false), handler(nullptr), hostContext(nullptr) { - static const uint8_t* kSupportedInterfacesBase[] = { - v3_funknown_iid, - v3_edit_controller_iid - }; + // v3_funknown, single instance with custom query + query_interface = query_interface_edit_controller; + ref = dpf_refcounter__ref; + unref = dpf_refcounter__unref; + + // v3_plugin_base + base.initialize = initialize; + base.terminate = terminate; + + // v3_edit_controller + ctrl.set_component_state = set_component_state; + ctrl.set_state = set_state; + ctrl.get_state = get_state; + ctrl.get_parameter_count = get_parameter_count; + ctrl.get_parameter_info = get_parameter_info; + ctrl.get_parameter_string_for_value = get_parameter_string_for_value; + ctrl.get_parameter_value_for_string = get_parameter_value_for_string; + ctrl.normalised_parameter_to_plain = normalised_parameter_to_plain; + ctrl.plain_parameter_to_normalised = plain_parameter_to_normalised; + ctrl.get_parameter_normalised = get_parameter_normalised; + ctrl.set_parameter_normalised = set_parameter_normalised; + ctrl.set_component_handler = set_component_handler; + ctrl.create_view = create_view; + } + + // ---------------------------------------------------------------------------------------------------------------- + // v3_funknown - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown + static V3_API v3_result query_interface_edit_controller(void* self, const v3_tuid iid, void** iface) + { + if (v3_tuid_match(iid, v3_funknown_iid)) + { + *iface = self; + return V3_OK; + } - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + if (v3_tuid_match(iid, v3_plugin_base_iid)) { - d_stdout("dpf_edit_controller::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + *iface = self; + return V3_OK; + } - for (const uint8_t* interface_iid : kSupportedInterfacesBase) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } + if (v3_tuid_match(iid, v3_edit_controller_iid)) + { + *iface = self; + return V3_OK; + } - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NO_INTERFACE); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NO_INTERFACE); #if DISTRHO_PLUGIN_HAS_UI - if (v3_tuid_match(v3_connection_point_iid, iid)) - { - if (controller->connectionComp == nullptr) - controller->connectionComp = new dpf_dsp_connection_point(kConnectionPointController, - controller->vst3); - *iface = &controller->connectionComp; - return V3_OK; - } + if (v3_tuid_match(iid, v3_connection_point_iid)) + { + if (controller->connectionComp == nullptr) + controller->connectionComp = new dpf_dsp_connection_point(kConnectionPointController, + controller->vst3); + else + ++controller->connectionComp->refcounter; + *iface = &controller->connectionComp; + return V3_OK; + } #endif #if DISTRHO_PLUGIN_WANT_MIDI_INPUT - if (v3_tuid_match(v3_midi_mapping_iid, iid)) - { - if (controller->midiMapping == nullptr) - controller->midiMapping = new dpf_midi_mapping(controller->vst3); - *iface = &controller->midiMapping; - return V3_OK; - } + if (v3_tuid_match(iid, v3_midi_mapping_iid)) + { + static dpf_midi_mapping midi_mapping; + static dpf_midi_mapping* midi_mapping_ptr = &midi_mapping; + *iface = &midi_mapping_ptr; + return V3_OK; + } #endif - return V3_NO_INTERFACE; - }; + *iface = NULL; + 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_plugin_base - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_base + static V3_API v3_result initialize(void* self, v3_plugin_base::v3_funknown** context) + { + d_stdout("dpf_edit_controller::initialize => %p %p", self, context); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - base.initialize = []V3_API(void* self, v3_plugin_base::v3_funknown** context) -> v3_result - { - d_stdout("dpf_edit_controller::initialize => %p %p", self, context); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + const bool initialized = controller->initialized; + DISTRHO_SAFE_ASSERT_RETURN(! initialized, V3_INVALID_ARG); - const bool initialized = controller->initialized; - DISTRHO_SAFE_ASSERT_RETURN(! initialized, V3_INVALID_ARG); + controller->initialized = true; + controller->hostContext = context; + return V3_OK; + } - controller->initialized = true; - controller->hostContext = context; - return V3_OK; - }; + static V3_API v3_result terminate(void* self) + { + d_stdout("dpf_edit_controller::terminate => %p", self); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - base.terminate = []V3_API(void* self) -> v3_result - { - d_stdout("dpf_edit_controller::terminate => %p", self); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + const bool initialized = controller->initialized; + DISTRHO_SAFE_ASSERT_RETURN(initialized, V3_INVALID_ARG); - const bool initialized = controller->initialized; - DISTRHO_SAFE_ASSERT_RETURN(initialized, V3_INVALID_ARG); + controller->initialized = false; + controller->hostContext = nullptr; - controller->initialized = false; - controller->hostContext = nullptr; - return V3_OK; - }; +#if DISTRHO_PLUGIN_HAS_UI + // take the chance to do some cleanup if possible (we created the bridge, we need to destroy it) + if (controller->connectionBridge != nullptr) + if (controller->connectionBridge->refcounter == 1) + controller->connectionBridge = nullptr; - // ------------------------------------------------------------------------------------------------------------ - // v3_edit_controller + if (controller->connectionComp != nullptr && controller->connectionComp->shortcircuit) + if (controller->connectionComp->refcounter == 1) + controller->connectionComp = nullptr; +#endif - ctrl.set_component_state = []V3_API(void* self, v3_bstream* stream) -> v3_result - { - d_stdout("dpf_edit_controller::set_component_state => %p %p", self, stream); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + return V3_OK; + } + + // ---------------------------------------------------------------------------------------------------------------- + // v3_edit_controller + + static V3_API v3_result set_component_state(void* self, v3_bstream* stream) + { + d_stdout("dpf_edit_controller::set_component_state => %p %p", self, stream); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); #if 0 - return vst3->setComponentState(stream); + return vst3->setComponentState(stream); #endif - // TODO, returning ok to make renoise happy - return V3_OK; - }; + // TODO, returning ok to make renoise happy + return V3_OK; + } - ctrl.set_state = []V3_API(void* self, v3_bstream* stream) -> v3_result - { - d_stdout("dpf_edit_controller::set_state => %p %p", self, stream); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_state(void* self, v3_bstream* stream) + { + d_stdout("dpf_edit_controller::set_state => %p %p", self, stream); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); #if 0 - return vst3->setState(stream); + return vst3->setState(stream); #endif - return V3_NOT_IMPLEMENTED; - }; + return V3_NOT_IMPLEMENTED; + } - ctrl.get_state = []V3_API(void* self, v3_bstream* stream) -> v3_result - { - d_stdout("dpf_edit_controller::get_state => %p %p", self, stream); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_state(void* self, v3_bstream* stream) + { + d_stdout("dpf_edit_controller::get_state => %p %p", self, stream); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); #if 0 - return vst3->getState(stream); + return vst3->getState(stream); #endif - return V3_NOT_IMPLEMENTED; - }; + return V3_NOT_IMPLEMENTED; + } - ctrl.get_parameter_count = []V3_API(void* self) -> int32_t - { - // 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); + static V3_API int32_t get_parameter_count(void* 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_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getParameterCount(); - }; + return vst3->getParameterCount(); + } - ctrl.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); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_parameter_info(void* self, int32_t param_idx, v3_param_info* param_info) + { + // 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_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getParameterInfo(param_idx, param_info); - }; + return vst3->getParameterInfo(param_idx, param_info); + } - ctrl.get_parameter_string_for_value = []V3_API(void* self, v3_param_id index, double normalised, v3_str_128 output) -> v3_result - { - // NOTE very noisy, called many times - // d_stdout("dpf_edit_controller::get_parameter_string_for_value => %p %u %f %p", self, index, normalised, output); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_parameter_string_for_value(void* self, v3_param_id index, double normalised, v3_str_128 output) + { + // NOTE very noisy, called many times + // d_stdout("dpf_edit_controller::get_parameter_string_for_value => %p %u %f %p", self, index, normalised, output); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getParameterStringForValue(index, normalised, output); - }; + return vst3->getParameterStringForValue(index, normalised, output); + } - ctrl.get_parameter_value_for_string = []V3_API(void* self, v3_param_id index, int16_t* input, double* output) -> v3_result - { - d_stdout("dpf_edit_controller::get_parameter_value_for_string => %p %u %p %p", self, index, input, output); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_parameter_value_for_string(void* self, v3_param_id index, int16_t* input, double* output) + { + d_stdout("dpf_edit_controller::get_parameter_value_for_string => %p %u %p %p", self, index, input, output); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getParameterValueForString(index, input, output); - }; + return vst3->getParameterValueForString(index, input, output); + } - ctrl.normalised_parameter_to_plain = []V3_API(void* self, v3_param_id index, double normalised) -> double - { - d_stdout("dpf_edit_controller::normalised_parameter_to_plain => %p %u %f", self, index, normalised); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API double normalised_parameter_to_plain(void* self, v3_param_id index, double normalised) + { + d_stdout("dpf_edit_controller::normalised_parameter_to_plain => %p %u %f", self, index, normalised); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->normalisedParameterToPlain(index, normalised); - }; + return vst3->normalisedParameterToPlain(index, normalised); + } - ctrl.plain_parameter_to_normalised = []V3_API(void* self, v3_param_id index, double plain) -> double - { - d_stdout("dpf_edit_controller::plain_parameter_to_normalised => %p %u %f", self, index, plain); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API double plain_parameter_to_normalised(void* self, v3_param_id index, double plain) + { + d_stdout("dpf_edit_controller::plain_parameter_to_normalised => %p %u %f", self, index, plain); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->plainParameterToNormalised(index, plain); - }; + return vst3->plainParameterToNormalised(index, plain); + } - ctrl.get_parameter_normalised = []V3_API(void* self, v3_param_id index) -> double - { - // NOTE very noisy, called many times - // d_stdout("dpf_edit_controller::get_parameter_normalised => %p %u", self, index); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0.0); + static V3_API double get_parameter_normalised(void* self, v3_param_id index) + { + // NOTE very noisy, called many times + // d_stdout("dpf_edit_controller::get_parameter_normalised => %p %u", self, index); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, 0.0); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0.0); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0.0); - return vst3->getParameterNormalized(index); - }; + return vst3->getParameterNormalized(index); + } - ctrl.set_parameter_normalised = []V3_API(void* self, v3_param_id index, double normalised) -> v3_result - { - d_stdout("dpf_edit_controller::set_parameter_normalised => %p %u %f", self, index, normalised); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_parameter_normalised(void* self, v3_param_id index, double normalised) + { + d_stdout("dpf_edit_controller::set_parameter_normalised => %p %u %f", self, index, normalised); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->setParameterNormalized(index, normalised); - }; + return vst3->setParameterNormalized(index, normalised); + } - ctrl.set_component_handler = []V3_API(void* self, v3_component_handler** handler) -> v3_result - { - d_stdout("dpf_edit_controller::set_component_handler => %p %p", self, handler); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_component_handler(void* self, v3_component_handler** handler) + { + d_stdout("dpf_edit_controller::set_component_handler => %p %p", self, handler); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, V3_NOT_INITIALIZED); - controller->handler = handler; + controller->handler = handler; - if (PluginVst3* const vst3 = controller->vst3) - return vst3->setComponentHandler(handler); + if (PluginVst3* const vst3 = controller->vst3) + return vst3->setComponentHandler(handler); - return V3_NOT_INITIALISED; - }; + return V3_NOT_INITIALIZED; + } - ctrl.create_view = []V3_API(void* self, const char* name) -> v3_plugin_view** - { - d_stdout("dpf_edit_controller::create_view => %p %s", self, name); - dpf_edit_controller* const controller = *(dpf_edit_controller**)self; - DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); + static V3_API v3_plugin_view** create_view(void* self, const char* name) + { + d_stdout("dpf_edit_controller::create_view => %p %s", self, name); + dpf_edit_controller* const controller = *(dpf_edit_controller**)self; + DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); #if DISTRHO_PLUGIN_HAS_UI - // plugin must be initialized - PluginVst3* const vst3 = controller->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); + // plugin must be initialized + PluginVst3* const vst3 = controller->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); - // we require host context for message creation - DISTRHO_SAFE_ASSERT_RETURN(controller->hostContext != nullptr, nullptr); + // we require host context for message creation + DISTRHO_SAFE_ASSERT_RETURN(controller->hostContext != nullptr, nullptr); - v3_host_application** host = nullptr; - v3_cpp_obj_query_interface(controller->hostContext, v3_host_application_iid, &host); - DISTRHO_SAFE_ASSERT_RETURN(host != nullptr, nullptr); + v3_host_application** host = nullptr; + v3_cpp_obj_query_interface(controller->hostContext, v3_host_application_iid, &host); + DISTRHO_SAFE_ASSERT_RETURN(host != nullptr, nullptr); - // if there is a component connection, we require it to be active - if (controller->connectionComp != nullptr) - { - DISTRHO_SAFE_ASSERT_RETURN(controller->connectionComp->other != nullptr, nullptr); - } - // otherwise short-circuit and deal with this ourselves (assume local usage) - else - { - controller->connectionComp = new dpf_dsp_connection_point(kConnectionPointController, - controller->vst3); - controller->connectionComp->shortcircuit = true; - } + // if there is a component connection, we require it to be active + if (controller->connectionComp != nullptr) + { + DISTRHO_SAFE_ASSERT_RETURN(controller->connectionComp->other != nullptr, nullptr); + } + // otherwise short-circuit and deal with this ourselves (assume local usage) + else + { + controller->connectionComp = new dpf_dsp_connection_point(kConnectionPointController, + controller->vst3); + controller->connectionComp->shortcircuit = true; + } - v3_plugin_view** const view = dpf_plugin_view_create(host, - vst3->getInstancePointer(), - vst3->getSampleRate()); - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, nullptr); + v3_plugin_view** const view = dpf_plugin_view_create(host, + vst3->getInstancePointer(), + vst3->getSampleRate()); + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, nullptr); - v3_connection_point** uiconn = nullptr; - if (v3_cpp_obj_query_interface(view, v3_connection_point_iid, &uiconn) == V3_OK) - { - d_stdout("view connection query ok %p | shortcircuit %d", - uiconn, controller->connectionComp->shortcircuit); + v3_connection_point** uiconn = nullptr; + if (v3_cpp_obj_query_interface(view, v3_connection_point_iid, &uiconn) == V3_OK) + { + d_stdout("view connection query ok %p | shortcircuit %d", + uiconn, controller->connectionComp->shortcircuit); - v3_connection_point** const ctrlconn = (v3_connection_point**)&controller->connectionComp; + v3_connection_point** const ctrlconn = (v3_connection_point**)&controller->connectionComp; - if (controller->connectionComp->shortcircuit) - { - vst3->disconnect(); + if (controller->connectionComp->shortcircuit) + { + vst3->disconnect(); - v3_cpp_obj(uiconn)->connect(uiconn, ctrlconn); - v3_cpp_obj(ctrlconn)->connect(ctrlconn, uiconn); + v3_cpp_obj(uiconn)->connect(uiconn, ctrlconn); + v3_cpp_obj(ctrlconn)->connect(ctrlconn, uiconn); - vst3->connect(ctrlconn); - } - else - { - controller->connectionBridge = new dpf_dsp_connection_point(kConnectionPointBridge, - controller->vst3); + vst3->connect(ctrlconn); + } + else + { + controller->connectionBridge = new dpf_dsp_connection_point(kConnectionPointBridge, + controller->vst3); - v3_connection_point** const bridgeconn = (v3_connection_point**)&controller->connectionBridge; - v3_cpp_obj(uiconn)->connect(uiconn, bridgeconn); - v3_cpp_obj(bridgeconn)->connect(bridgeconn, uiconn); + v3_connection_point** const bridgeconn = (v3_connection_point**)&controller->connectionBridge; + v3_cpp_obj(uiconn)->connect(uiconn, bridgeconn); + v3_cpp_obj(bridgeconn)->connect(bridgeconn, uiconn); - controller->connectionComp->bridge = bridgeconn; - controller->connectionBridge->bridge = ctrlconn; - } + controller->connectionComp->bridge = bridgeconn; + controller->connectionBridge->bridge = ctrlconn; } + } - return view; + return view; #else - return nullptr; + return nullptr; #endif - }; } }; // -------------------------------------------------------------------------------------------------------------------- // dpf_process_context_requirements -struct v3_process_context_requirements_cpp : v3_funknown { - v3_process_context_requirements req; -}; - struct dpf_process_context_requirements : v3_process_context_requirements_cpp { dpf_process_context_requirements() { - static const uint8_t* kSupportedInterfaces[] = { - v3_funknown_iid, - v3_process_context_requirements_iid - }; - - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown - - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_process_context_requirements::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; - } - } + static constexpr const v3_tuid interface = V3_ID_COPY(v3_process_context_requirements_iid); - return V3_NO_INTERFACE; - }; + // v3_funknown, used statically + query_interface = dpf_static__query_interface; + ref = dpf_static__ref; + unref = dpf_static__unref; - // this is used statically, 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_process_context_requirements + req.get_process_context_requirements = get_process_context_requirements; + } - req.get_process_context_requirements = []V3_API(void*) -> uint32_t - { + // ---------------------------------------------------------------------------------------------------------------- + // v3_process_context_requirements + + static uint32_t get_process_context_requirements(void*) + { #if DISTRHO_PLUGIN_WANT_TIMEPOS - return 0x0 - |V3_PROCESS_CTX_NEED_CONTINUOUS_TIME // V3_PROCESS_CTX_CONT_TIME_VALID - |V3_PROCESS_CTX_NEED_PROJECT_TIME // V3_PROCESS_CTX_PROJECT_TIME_VALID - |V3_PROCESS_CTX_NEED_TEMPO // V3_PROCESS_CTX_TEMPO_VALID - |V3_PROCESS_CTX_NEED_TIME_SIG // V3_PROCESS_CTX_TIME_SIG_VALID - |V3_PROCESS_CTX_NEED_TRANSPORT_STATE; // V3_PROCESS_CTX_PLAYING + return 0x0 + |V3_PROCESS_CTX_NEED_CONTINUOUS_TIME // V3_PROCESS_CTX_CONT_TIME_VALID + |V3_PROCESS_CTX_NEED_PROJECT_TIME // V3_PROCESS_CTX_PROJECT_TIME_VALID + |V3_PROCESS_CTX_NEED_TEMPO // V3_PROCESS_CTX_TEMPO_VALID + |V3_PROCESS_CTX_NEED_TIME_SIG // V3_PROCESS_CTX_TIME_SIG_VALID + |V3_PROCESS_CTX_NEED_TRANSPORT_STATE; // V3_PROCESS_CTX_PLAYING #else - return 0x0; + return 0x0; #endif - }; } DISTRHO_PREVENT_HEAP_ALLOCATION @@ -2800,161 +2859,171 @@ struct dpf_process_context_requirements : v3_process_context_requirements_cpp { // -------------------------------------------------------------------------------------------------------------------- // dpf_audio_processor -struct v3_audio_processor_cpp : v3_funknown { - v3_audio_processor processor; -}; - struct dpf_audio_processor : v3_audio_processor_cpp { + std::atomic_int refcounter; ScopedPointer& vst3; dpf_audio_processor(ScopedPointer& v) - : vst3(v) + : refcounter(1), + vst3(v) { - static const uint8_t* kSupportedInterfacesBase[] = { - v3_funknown_iid, - v3_audio_processor_iid - }; + // v3_funknown, single instance with custom query + query_interface = query_interface_with_proc_ctx_reqs; + ref = dpf_refcounter__ref; + unref = dpf_refcounter__unref; - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown + // v3_audio_processor + proc.set_bus_arrangements = set_bus_arrangements; + proc.get_bus_arrangement = get_bus_arrangement; + proc.can_process_sample_size = can_process_sample_size; + proc.get_latency_samples = get_latency_samples; + proc.setup_processing = setup_processing; + proc.set_processing = set_processing; + proc.process = process; + proc.get_tail_samples = get_tail_samples; + } - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_audio_processor::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + // ---------------------------------------------------------------------------------------------------------------- + // v3_funknown - for (const uint8_t* interface_iid : kSupportedInterfacesBase) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } + static V3_API v3_result query_interface_with_proc_ctx_reqs(void* self, const v3_tuid iid, void** iface) + { + static constexpr const v3_tuid interface = V3_ID_COPY(v3_audio_processor_iid); - if (v3_tuid_match(v3_process_context_requirements_iid, iid)) - { - static dpf_process_context_requirements context_req; - static dpf_process_context_requirements* context_req_ptr = &context_req;; - *iface = &context_req_ptr; - return V3_OK; - } + if (dpf_static__query_interface(self, iid, iface) == V3_OK) + return V3_OK; - return V3_NO_INTERFACE; - }; + if (v3_tuid_match(iid, v3_process_context_requirements_iid)) + { + static dpf_process_context_requirements context_req; + static dpf_process_context_requirements* context_req_ptr = &context_req; + *iface = &context_req_ptr; + return V3_OK; + } - // 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; }; + *iface = NULL; + return V3_NO_INTERFACE; + } - // ------------------------------------------------------------------------------------------------------------ - // v3_audio_processor + // ---------------------------------------------------------------------------------------------------------------- + // v3_audio_processor - processor.set_bus_arrangements = []V3_API(void* self, - v3_speaker_arrangement* inputs, int32_t num_inputs, - v3_speaker_arrangement* outputs, int32_t num_outputs) -> v3_result - { - // NOTE this is called a bunch of times - // d_stdout("dpf_audio_processor::set_bus_arrangements => %p %p %i %p %i", self, inputs, num_inputs, outputs, num_outputs); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_bus_arrangements(void* self, + v3_speaker_arrangement* inputs, int32_t num_inputs, + v3_speaker_arrangement* outputs, int32_t num_outputs) + { + // NOTE this is called a bunch of times + // d_stdout("dpf_audio_processor::set_bus_arrangements => %p %p %i %p %i", self, inputs, num_inputs, outputs, num_outputs); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return processor->vst3->setBusArrangements(inputs, num_inputs, outputs, num_outputs); - }; + return processor->vst3->setBusArrangements(inputs, num_inputs, outputs, num_outputs); + } - processor.get_bus_arrangement = []V3_API(void* self, int32_t bus_direction, - int32_t idx, v3_speaker_arrangement* arr) -> v3_result - { - d_stdout("dpf_audio_processor::get_bus_arrangement => %p %i %i %p", self, bus_direction, idx, arr); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_bus_arrangement(void* self, int32_t bus_direction, + int32_t idx, v3_speaker_arrangement* arr) + { + d_stdout("dpf_audio_processor::get_bus_arrangement => %p %i %i %p", self, bus_direction, idx, arr); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return processor->vst3->getBusArrangement(bus_direction, idx, arr); - }; + return processor->vst3->getBusArrangement(bus_direction, idx, arr); + } - processor.can_process_sample_size = []V3_API(void* self, int32_t symbolic_sample_size) -> v3_result - { - d_stdout("dpf_audio_processor::can_process_sample_size => %p %i", self, symbolic_sample_size); - return symbolic_sample_size == V3_SAMPLE_32 ? V3_OK : V3_NOT_IMPLEMENTED; - }; + static V3_API v3_result can_process_sample_size(void* self, int32_t symbolic_sample_size) + { + d_stdout("dpf_audio_processor::can_process_sample_size => %p %i", self, symbolic_sample_size); + return symbolic_sample_size == V3_SAMPLE_32 ? V3_OK : V3_NOT_IMPLEMENTED; + } - processor.get_latency_samples = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_audio_processor::get_latency_samples => %p", self); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0); + static V3_API uint32_t get_latency_samples(void* self) + { + d_stdout("dpf_audio_processor::get_latency_samples => %p", self); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0); - return processor->vst3->getLatencySamples(); - }; + return processor->vst3->getLatencySamples(); + } - processor.setup_processing = []V3_API(void* self, v3_process_setup* setup) -> v3_result - { - d_stdout("dpf_audio_processor::setup_processing => %p", self); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result setup_processing(void* self, v3_process_setup* setup) + { + d_stdout("dpf_audio_processor::setup_processing => %p", self); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - d_lastBufferSize = setup->max_block_size; - d_lastSampleRate = setup->sample_rate; - return processor->vst3->setupProcessing(setup); - }; + d_lastBufferSize = setup->max_block_size; + d_lastSampleRate = setup->sample_rate; + return processor->vst3->setupProcessing(setup); + } - processor.set_processing = []V3_API(void* self, v3_bool state) -> v3_result - { - d_stdout("dpf_audio_processor::set_processing => %p %u", self, state); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_processing(void* self, v3_bool state) + { + d_stdout("dpf_audio_processor::set_processing => %p %u", self, state); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return processor->vst3->setProcessing(state); - }; + return processor->vst3->setProcessing(state); + } - processor.process = []V3_API(void* self, v3_process_data* data) -> v3_result - { - // NOTE runs during RT - // d_stdout("dpf_audio_processor::process => %p", self); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result process(void* self, v3_process_data* data) + { + // NOTE runs during RT + // d_stdout("dpf_audio_processor::process => %p", self); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return processor->vst3->process(data); - }; + return processor->vst3->process(data); + } - processor.get_tail_samples = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_audio_processor::get_tail_samples => %p", self); - dpf_audio_processor* const processor = *(dpf_audio_processor**)self; - DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0); + static V3_API uint32_t get_tail_samples(void* self) + { + d_stdout("dpf_audio_processor::get_tail_samples => %p", self); + dpf_audio_processor* const processor = *(dpf_audio_processor**)self; + DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, 0); - PluginVst3* const vst3 = processor->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0); + PluginVst3* const vst3 = processor->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, 0); - return processor->vst3->getTailSamples(); - }; + return processor->vst3->getTailSamples(); } }; +// -------------------------------------------------------------------------------------------------------------------- +// Store components that we can't delete properly, to be cleaned up on module unload + +struct dpf_component; + +std::vector*> gComponentGarbage; + +static v3_result handleUncleanComponent(ScopedPointer* const componentptr) +{ + gComponentGarbage.push_back(componentptr); + return V3_INVALID_ARG; +} + // -------------------------------------------------------------------------------------------------------------------- // dpf_component struct dpf_component : v3_component_cpp { - std::atomic refcounter; + std::atomic_int refcounter; ScopedPointer* self; ScopedPointer processor; #if DISTRHO_PLUGIN_HAS_UI @@ -2967,418 +3036,498 @@ struct dpf_component : v3_component_cpp { : refcounter(1), self(s) { - static const uint8_t* kSupportedInterfacesBase[] = { - v3_funknown_iid, - v3_plugin_base_iid, - v3_component_iid - }; + // v3_funknown, everything custom + query_interface = query_interface_component; + ref = ref_component; + unref = unref_component; + + // v3_plugin_base + base.initialize = initialize; + base.terminate = terminate; + + // v3_component + comp.get_controller_class_id = get_controller_class_id; + comp.set_io_mode = set_io_mode; + comp.get_bus_count = get_bus_count; + comp.get_bus_info = get_bus_info; + comp.get_routing_info = get_routing_info; + comp.activate_bus = activate_bus; + comp.set_active = set_active; + comp.set_state = set_state; + comp.get_state = get_state; + } - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown + // ---------------------------------------------------------------------------------------------------------------- + // v3_funknown - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + static V3_API v3_result query_interface_component(void* self, const v3_tuid iid, void** iface) + { + if (v3_tuid_match(iid, v3_funknown_iid)) { - d_stdout("dpf_component::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; + *iface = self; + return V3_OK; + } - for (const uint8_t* interface_iid : kSupportedInterfacesBase) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } + if (v3_tuid_match(iid, v3_plugin_base_iid)) + { + *iface = self; + return V3_OK; + } + + if (v3_tuid_match(iid, v3_component_iid)) + { + *iface = self; + return V3_OK; + } - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NO_INTERFACE); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NO_INTERFACE); - if (v3_tuid_match(v3_audio_processor_iid, iid)) - { - if (component->processor == nullptr) - component->processor = new dpf_audio_processor(component->vst3); - *iface = &component->processor; - return V3_OK; - } + if (v3_tuid_match(iid, v3_audio_processor_iid)) + { + if (component->processor == nullptr) + component->processor = new dpf_audio_processor(component->vst3); + else + ++component->processor->refcounter; + *iface = &component->processor; + return V3_OK; + } #if DISTRHO_PLUGIN_HAS_UI - if (v3_tuid_match(v3_connection_point_iid, iid)) - { - if (component->connection == nullptr) - component->connection = new dpf_dsp_connection_point(kConnectionPointComponent, - component->vst3); - *iface = &component->connection; - return V3_OK; - } + if (v3_tuid_match(iid, v3_connection_point_iid)) + { + if (component->connection == nullptr) + component->connection = new dpf_dsp_connection_point(kConnectionPointComponent, + component->vst3); + else + ++component->connection->refcounter; + *iface = &component->connection; + return V3_OK; + } #endif - if (v3_tuid_match(v3_edit_controller_iid, iid)) - { - if (component->controller == nullptr) - component->controller = new dpf_edit_controller(component->vst3); - *iface = &component->controller; - return V3_OK; - } + if (v3_tuid_match(iid, v3_edit_controller_iid)) + { + if (component->controller == nullptr) + component->controller = new dpf_edit_controller(component->vst3); + else + ++component->controller->refcounter; + *iface = &component->controller; + return V3_OK; + } - return V3_NO_INTERFACE; - }; + *iface = NULL; + return V3_NO_INTERFACE; + } -#if 1 - // TODO fix this up later - ref = []V3_API(void*) -> uint32_t { return 1; }; - unref = []V3_API(void*) -> uint32_t { return 0; }; -#else - ref = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_component::ref => %p", self); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, 0); + static V3_API uint32_t ref_component(void* self) + { + return ++(*(dpf_component**)self)->refcounter; + } - return ++component->refcounter; - }; + static V3_API uint32_t unref_component(void* self) + { + ScopedPointer* const componentptr = (ScopedPointer*)self; + dpf_component* const component = *componentptr; - unref = []V3_API(void* self) -> uint32_t + if (const int refcount = --component->refcounter) { - d_stdout("dpf_component::unref => %p", self); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, 0); + d_stdout("dpf_component::unref => %p | refcount %i", self, refcount); + return refcount; + } - if (const int refcount = --component->refcounter) + /** + * Some hosts will have unclean instances of a few of the component child classes at this point. + * We check for those here, going through the whole possible chain to see if it is safe to delete. + * If not, we add this component to the `gComponentGarbage` global which will take care of it during unload. + */ + + bool unclean = false; + if (dpf_audio_processor* const proc = component->processor) + { + if (const int refcount = proc->refcounter) { - d_stdout("dpf_component::unref => %p | refcount %i", self, refcount); - return refcount; + unclean = true; + d_stderr("DPF warning: asked to delete component while audio processor still active (refcount %d)", refcount); } + } - d_stdout("dpf_component::unref => %p | refcount is zero, deleting everything now!", self); - *component->self = nullptr; - delete (dpf_component**)self; - return 0; - }; +#if DISTRHO_PLUGIN_HAS_UI + if (dpf_dsp_connection_point* const conn = component->connection) + { + if (const int refcount = conn->refcounter) + { + unclean = true; + d_stderr("DPF warning: asked to delete component while connection point still active (refcount %d)", refcount); + } + } #endif - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_base - - base.initialize = []V3_API(void* self, v3_plugin_base::v3_funknown** context) -> v3_result + if (dpf_edit_controller* const ctrl = component->controller) { - d_stdout("dpf_component::initialize => %p %p", self, context); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + if (const int refcount = ctrl->refcounter) + { + unclean = true; + d_stderr("DPF warning: asked to delete component while edit controller still active (refcount %d)", refcount); + } - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 == nullptr, V3_INVALID_ARG); +#if DISTRHO_PLUGIN_HAS_UI + if (dpf_dsp_connection_point* const comp = ctrl->connectionComp) + { + if (const int refcount = comp->refcounter) + { + unclean = true; + d_stderr("DPF warning: asked to delete component while edit controller connection point still active (refcount %d)", refcount); + } + } - d_lastCanRequestParameterValueChanges = true; + if (dpf_dsp_connection_point* const bridge = ctrl->connectionBridge) + { + if (const int refcount = bridge->refcounter) + { + unclean = true; + d_stderr("DPF warning: asked to delete component while view bridge connection still active (refcount %d)", refcount); + } + } +#endif + } - // default early values - if (d_lastBufferSize == 0) - d_lastBufferSize = 2048; - if (d_lastSampleRate <= 0.0) - d_lastSampleRate = 44100.0; + if (unclean) + return handleUncleanComponent(componentptr); - // query for host context - v3_host_application** host = nullptr; - v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); + d_stdout("dpf_component::unref => %p | refcount is zero, deleting everything now!", self); + *(component->self) = nullptr; + delete componentptr; + return 0; + } - component->vst3 = new PluginVst3(host); - return V3_OK; - }; + // ---------------------------------------------------------------------------------------------------------------- + // v3_plugin_base - base.terminate = []V3_API(void* self) -> v3_result - { - d_stdout("dpf_component::terminate => %p", self); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result initialize(void* self, v3_plugin_base::v3_funknown** context) + { + d_stdout("dpf_component::initialize => %p %p", self, context); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_INVALID_ARG); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 == nullptr, V3_INVALID_ARG); - component->vst3 = nullptr; - return V3_OK; - }; + d_lastCanRequestParameterValueChanges = true; - // ------------------------------------------------------------------------------------------------------------ - // v3_component + // default early values + if (d_lastBufferSize == 0) + d_lastBufferSize = 2048; + if (d_lastSampleRate <= 0.0) + d_lastSampleRate = 44100.0; - comp.get_controller_class_id = []V3_API(void* self, v3_tuid class_id) -> v3_result - { - d_stdout("dpf_component::get_controller_class_id => %p %s", self, tuid2str(class_id)); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + // query for host context + v3_host_application** host = nullptr; + v3_cpp_obj_query_interface(context, v3_host_application_iid, &host); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + component->vst3 = new PluginVst3(host); + return V3_OK; + } - // TODO - return V3_NOT_IMPLEMENTED; - }; + static V3_API v3_result terminate(void* self) + { + d_stdout("dpf_component::terminate => %p", self); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - comp.set_io_mode = []V3_API(void* self, int32_t io_mode) -> v3_result - { - d_stdout("dpf_component::set_io_mode => %p %i", self, io_mode); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_INVALID_ARG); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + component->vst3 = nullptr; + return V3_OK; + } - // TODO - return V3_NOT_IMPLEMENTED; - }; + // ---------------------------------------------------------------------------------------------------------------- + // v3_component - comp.get_bus_count = []V3_API(void* self, int32_t media_type, int32_t bus_direction) -> int32_t - { - // NOTE runs during RT - // d_stdout("dpf_component::get_bus_count => %p %i %i", self, media_type, bus_direction); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_controller_class_id(void* self, v3_tuid class_id) + { + d_stdout("dpf_component::get_controller_class_id => %p %s", self, tuid2str(class_id)); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getBusCount(media_type, bus_direction); - }; + // TODO + return V3_NOT_IMPLEMENTED; + } - comp.get_bus_info = []V3_API(void* self, int32_t media_type, int32_t bus_direction, - int32_t bus_idx, v3_bus_info* info) -> v3_result - { - d_stdout("dpf_component::get_bus_info => %p %i %i %i %p", self, media_type, bus_direction, bus_idx, info); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_io_mode(void* self, int32_t io_mode) + { + d_stdout("dpf_component::set_io_mode => %p %i", self, io_mode); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getBusInfo(media_type, bus_direction, bus_idx, info); - }; + // TODO + return V3_NOT_IMPLEMENTED; + } - comp.get_routing_info = []V3_API(void* self, v3_routing_info* input, v3_routing_info* output) -> v3_result - { - d_stdout("dpf_component::get_routing_info => %p %p %p", self, input, output); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API int32_t get_bus_count(void* self, int32_t media_type, int32_t bus_direction) + { + // NOTE runs during RT + // d_stdout("dpf_component::get_bus_count => %p %i %i", self, media_type, bus_direction); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getRoutingInfo(input, output); - }; + return vst3->getBusCount(media_type, bus_direction); + } - comp.activate_bus = []V3_API(void* self, int32_t media_type, int32_t bus_direction, - int32_t bus_idx, v3_bool state) -> v3_result - { - // NOTE this is called a bunch of times - // d_stdout("dpf_component::activate_bus => %p %i %i %i %u", self, media_type, bus_direction, bus_idx, state); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_bus_info(void* self, int32_t media_type, int32_t bus_direction, + int32_t bus_idx, v3_bus_info* info) + { + d_stdout("dpf_component::get_bus_info => %p %i %i %i %p", self, media_type, bus_direction, bus_idx, info); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->activateBus(media_type, bus_direction, bus_idx, state); - }; + return vst3->getBusInfo(media_type, bus_direction, bus_idx, info); + } - comp.set_active = []V3_API(void* self, v3_bool state) -> v3_result - { - d_stdout("dpf_component::set_active => %p %u", self, state); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result get_routing_info(void* self, v3_routing_info* input, v3_routing_info* output) + { + d_stdout("dpf_component::get_routing_info => %p %p %p", self, input, output); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return component->vst3->setActive(state); - }; + return vst3->getRoutingInfo(input, output); + } - comp.set_state = []V3_API(void* self, v3_bstream** stream) -> v3_result - { - d_stdout("dpf_component::set_state => %p", self); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result activate_bus(void* self, int32_t media_type, int32_t bus_direction, + int32_t bus_idx, v3_bool state) + { + // NOTE this is called a bunch of times + // d_stdout("dpf_component::activate_bus => %p %i %i %i %u", self, media_type, bus_direction, bus_idx, state); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->setState(stream); - }; + return vst3->activateBus(media_type, bus_direction, bus_idx, state); + } - comp.get_state = []V3_API(void* self, v3_bstream** stream) -> v3_result - { - d_stdout("dpf_component::get_state => %p %p", self, stream); - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result set_active(void* self, v3_bool state) + { + d_stdout("dpf_component::set_active => %p %u", self, state); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - PluginVst3* const vst3 = component->vst3; - DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - return vst3->getState(stream); - }; + return component->vst3->setActive(state); } -}; -// -------------------------------------------------------------------------------------------------------------------- -// dpf_factory + static V3_API v3_result set_state(void* self, v3_bstream** stream) + { + d_stdout("dpf_component::set_state => %p", self); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); -struct v3_plugin_factory_cpp : v3_funknown { - v3_plugin_factory v1; - v3_plugin_factory_2 v2; - v3_plugin_factory_3 v3; -}; + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); -struct dpf_factory : v3_plugin_factory_cpp { - std::vector*> components; + return vst3->setState(stream); + } - dpf_factory() + static V3_API v3_result get_state(void* self, v3_bstream** stream) { - static const uint8_t* kSupportedFactories[] = { - v3_funknown_iid, - v3_plugin_factory_iid, - v3_plugin_factory_2_iid, - v3_plugin_factory_3_iid - }; + d_stdout("dpf_component::get_state => %p %p", self, stream); + dpf_component* const component = *(dpf_component**)self; + DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NOT_INITIALIZED); - // ------------------------------------------------------------------------------------------------------------ - // Dummy plugin to get data from + PluginVst3* const vst3 = component->vst3; + DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALIZED); - d_lastBufferSize = 512; - d_lastSampleRate = 44100.0; - d_lastCanRequestParameterValueChanges = true; - static const PluginExporter gPluginInfo(nullptr, nullptr, nullptr); - d_lastBufferSize = 0; - d_lastSampleRate = 0.0; - d_lastCanRequestParameterValueChanges = false; + return vst3->getState(stream); + } +}; - dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2] - = dpf_tuid_processor[2] = dpf_tuid_view[2] = gPluginInfo.getUniqueId(); +// -------------------------------------------------------------------------------------------------------------------- +// Dummy plugin to get data from - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown +static const PluginExporter& _getPluginInfo() +{ + d_lastBufferSize = 512; + d_lastSampleRate = 44100.0; + d_lastCanRequestParameterValueChanges = true; + static const PluginExporter gPluginInfo(nullptr, nullptr, nullptr); + d_lastBufferSize = 0; + d_lastSampleRate = 0.0; + d_lastCanRequestParameterValueChanges = false; + + dpf_tuid_class[2] = dpf_tuid_component[2] = dpf_tuid_controller[2] + = dpf_tuid_processor[2] = dpf_tuid_view[2] = gPluginInfo.getUniqueId(); + + return gPluginInfo; +} - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_factory::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); +static const PluginExporter& getPluginInfo() +{ + static const PluginExporter& info(_getPluginInfo()); + return info; +} - for (const uint8_t* factory_iid : kSupportedFactories) - { - if (v3_tuid_match(factory_iid, iid)) - { - *iface = self; - return V3_OK; - } - } +// -------------------------------------------------------------------------------------------------------------------- +// dpf_factory - return V3_NO_INTERFACE; - }; +struct dpf_factory : v3_plugin_factory_cpp { + dpf_factory() + { + static constexpr const v3_tuid interface_v1 = V3_ID_COPY(v3_plugin_factory_iid); + static constexpr const v3_tuid interface_v2 = V3_ID_COPY(v3_plugin_factory_2_iid); + static constexpr const v3_tuid interface_v3 = V3_ID_COPY(v3_plugin_factory_3_iid); - // we only support 1 plugin per binary, so don't have to care here - ref = []V3_API(void*) -> uint32_t { return 1; }; - unref = []V3_API(void*) -> uint32_t { return 0; }; + // v3_funknown, used statically + query_interface = dpf_static__query_interface; + ref = dpf_static__ref; + unref = dpf_static__unref; - // ------------------------------------------------------------------------------------------------------------ // v3_plugin_factory + v1.get_factory_info = get_factory_info; + v1.num_classes = num_classes; + v1.get_class_info = get_class_info; + v1.create_instance = create_instance; - v1.get_factory_info = []V3_API(void*, v3_factory_info* const info) -> v3_result - { - std::memset(info, 0, sizeof(*info)); - DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo.getMaker(), sizeof(info->vendor)); - DISTRHO_NAMESPACE::strncpy(info->url, gPluginInfo.getHomePage(), sizeof(info->url)); - // DISTRHO_NAMESPACE::strncpy(info->email, "", sizeof(info->email)); // TODO - return V3_OK; - }; + // v3_plugin_factory_2 + v2.get_class_info_2 = get_class_info_2; - v1.num_classes = []V3_API(void*) -> int32_t - { - return 1; - }; + // v3_plugin_factory_3 + v3.get_class_info_utf16 = get_class_info_utf16; + v3.set_host_context = set_host_context; + } - v1.get_class_info = []V3_API(void*, int32_t idx, v3_class_info* const info) -> v3_result - { - std::memset(info, 0, sizeof(*info)); - DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE); + ~dpf_factory() + { + if (gComponentGarbage.size() == 0) + return; - std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); - info->cardinality = 0x7FFFFFFF; - DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category)); - DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo.getName(), sizeof(info->name)); - return V3_OK; - }; + d_stdout("DPF notice: cleaning up previously undeleted components now"); - v1.create_instance = []V3_API(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance) -> v3_result + for (std::vector*>::iterator it = gComponentGarbage.begin(); + it != gComponentGarbage.end(); ++it) { - d_stdout("dpf_factory::create_instance => %p %s %s %p", self, tuid2str(class_id), tuid2str(iid), instance); - DISTRHO_SAFE_ASSERT_RETURN(v3_tuid_match(class_id, *(v3_tuid*)&dpf_tuid_class) && - v3_tuid_match(iid, v3_component_iid), V3_NO_INTERFACE); + ScopedPointer* const componentptr = *it; + dpf_component* const component = *componentptr; +#if DISTRHO_PLUGIN_HAS_UI + component->connection = nullptr; +#endif + component->processor = nullptr; + component->controller = nullptr; + *(component->self) = nullptr; + delete componentptr; + } - dpf_factory* const factory = *(dpf_factory**)self; - DISTRHO_SAFE_ASSERT_RETURN(factory != nullptr, V3_NOT_INITIALISED); + gComponentGarbage.clear(); + } - ScopedPointer* const componentptr = new ScopedPointer; - *componentptr = new dpf_component(componentptr); - *instance = componentptr; - factory->components.push_back(componentptr); - return V3_OK; - }; + // ---------------------------------------------------------------------------------------------------------------- + // v3_plugin_factory - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_factory_2 + static V3_API v3_result get_factory_info(void*, v3_factory_info* const info) + { + std::memset(info, 0, sizeof(*info)); + DISTRHO_NAMESPACE::strncpy(info->vendor, getPluginInfo().getMaker(), sizeof(info->vendor)); + DISTRHO_NAMESPACE::strncpy(info->url, getPluginInfo().getHomePage(), sizeof(info->url)); + // DISTRHO_NAMESPACE::strncpy(info->email, "", sizeof(info->email)); // TODO + return V3_OK; + } - v2.get_class_info_2 = []V3_API(void*, int32_t idx, v3_class_info_2* info) -> v3_result - { - std::memset(info, 0, sizeof(*info)); - DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE); + static V3_API int32_t num_classes(void*) + { + return 1; + } - std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); - info->cardinality = 0x7FFFFFFF; - DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category)); - DISTRHO_NAMESPACE::strncpy(info->name, gPluginInfo.getName(), ARRAY_SIZE(info->name)); + static V3_API v3_result get_class_info(void*, int32_t idx, v3_class_info* const info) + { + std::memset(info, 0, sizeof(*info)); + DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE); - info->class_flags = 0; - // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO - DISTRHO_NAMESPACE::strncpy(info->vendor, gPluginInfo.getMaker(), ARRAY_SIZE(info->vendor)); - DISTRHO_NAMESPACE::snprintf_u32(info->version, gPluginInfo.getVersion(), ARRAY_SIZE(info->version)); // FIXME - DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ? - return V3_OK; - }; + std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); + info->cardinality = 0x7FFFFFFF; + DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", sizeof(info->category)); + DISTRHO_NAMESPACE::strncpy(info->name, getPluginInfo().getName(), sizeof(info->name)); + return V3_OK; + } - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_factory_3 + static V3_API v3_result create_instance(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance) + { + d_stdout("dpf_factory::create_instance => %p %s %s %p", self, tuid2str(class_id), tuid2str(iid), instance); + DISTRHO_SAFE_ASSERT_RETURN(v3_tuid_match(class_id, *(v3_tuid*)&dpf_tuid_class) && + v3_tuid_match(iid, v3_component_iid), V3_NO_INTERFACE); - v3.get_class_info_utf16 = []V3_API(void*, int32_t idx, v3_class_info_3* info) -> v3_result - { - std::memset(info, 0, sizeof(*info)); - DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE); + dpf_factory* const factory = *(dpf_factory**)self; + DISTRHO_SAFE_ASSERT_RETURN(factory != nullptr, V3_NOT_INITIALIZED); - std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); - info->cardinality = 0x7FFFFFFF; - DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category)); - DISTRHO_NAMESPACE::strncpy_utf16(info->name, gPluginInfo.getName(), ARRAY_SIZE(info->name)); + ScopedPointer* const componentptr = new ScopedPointer; + *componentptr = new dpf_component(componentptr); + *instance = componentptr; + return V3_OK; + } - info->class_flags = 0; - // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", ARRAY_SIZE(info->sub_categories)); // TODO - DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, gPluginInfo.getMaker(), sizeof(info->vendor)); - DISTRHO_NAMESPACE::snprintf_u32_utf16(info->version, gPluginInfo.getVersion(), ARRAY_SIZE(info->version)); // FIXME - DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ? - return V3_OK; - }; + // ---------------------------------------------------------------------------------------------------------------- + // v3_plugin_factory_2 - v3.set_host_context = []V3_API (void* self, v3_funknown* host) -> v3_result - { - d_stdout("dpf_factory::set_host_context => %p %p", self, host); - return V3_NOT_IMPLEMENTED; - }; + static V3_API v3_result get_class_info_2(void*, int32_t idx, v3_class_info_2* info) + { + std::memset(info, 0, sizeof(*info)); + DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE); + + std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); + info->cardinality = 0x7FFFFFFF; + DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category)); + DISTRHO_NAMESPACE::strncpy(info->name, getPluginInfo().getName(), ARRAY_SIZE(info->name)); + + info->class_flags = 0; + // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", sizeof(info->sub_categories)); // TODO + DISTRHO_NAMESPACE::strncpy(info->vendor, getPluginInfo().getMaker(), ARRAY_SIZE(info->vendor)); + DISTRHO_NAMESPACE::snprintf_u32(info->version, getPluginInfo().getVersion(), ARRAY_SIZE(info->version)); // FIXME + DISTRHO_NAMESPACE::strncpy(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ? + return V3_OK; } - ~dpf_factory() + // ------------------------------------------------------------------------------------------------------------ + // v3_plugin_factory_3 + + static V3_API v3_result get_class_info_utf16(void*, int32_t idx, v3_class_info_3* info) { - d_stdout("dpf_factory deleting"); + std::memset(info, 0, sizeof(*info)); + DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_NO_INTERFACE); + + std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); + info->cardinality = 0x7FFFFFFF; + DISTRHO_NAMESPACE::strncpy(info->category, "Audio Module Class", ARRAY_SIZE(info->category)); + DISTRHO_NAMESPACE::strncpy_utf16(info->name, getPluginInfo().getName(), ARRAY_SIZE(info->name)); + + info->class_flags = 0; + // DISTRHO_NAMESPACE::strncpy(info->sub_categories, "", ARRAY_SIZE(info->sub_categories)); // TODO + DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, getPluginInfo().getMaker(), sizeof(info->vendor)); + DISTRHO_NAMESPACE::snprintf_u32_utf16(info->version, getPluginInfo().getVersion(), ARRAY_SIZE(info->version)); // FIXME + DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty", ARRAY_SIZE(info->sdk_version)); // TESTING use "VST 3.7" ? + return V3_OK; + } - for (ScopedPointer* componentptr : components) - { - *componentptr = nullptr; - delete componentptr; - } + static V3_API v3_result set_host_context(void* self, v3_funknown* host) + { + d_stdout("dpf_factory::set_host_context => %p %p", self, host); + return V3_NOT_IMPLEMENTED; } DISTRHO_PREVENT_HEAP_ALLOCATION diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp index 42a708de..f0eee106 100644 --- a/distrho/src/DistrhoUIVST3.cpp +++ b/distrho/src/DistrhoUIVST3.cpp @@ -16,12 +16,24 @@ #include "DistrhoUIInternal.hpp" -#include - #include "travesty/edit_controller.h" #include "travesty/host.h" #include "travesty/view.h" +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +# include +#else +// quick and dirty std::atomic replacement for the things we need +namespace std { + struct atomic_int { + volatile int value; + explicit atomic_int(volatile int v) noexcept : value(v) {} + int operator++() volatile noexcept { return __atomic_add_fetch(&value, 1, __ATOMIC_RELAXED); } + int operator--() volatile noexcept { return __atomic_sub_fetch(&value, 1, __ATOMIC_RELAXED); } + }; +}; +#endif + /* TODO items: * - mousewheel event * - key down/up events @@ -555,6 +567,31 @@ private: * VST3 low-level pointer thingies follow, proceed with care. */ +// -------------------------------------------------------------------------------------------------------------------- +// v3_funknown for static and single instances of classes + +template +static V3_API v3_result dpf_static__query_interface(void* self, const v3_tuid iid, void** iface) +{ + if (v3_tuid_match(iid, v3_funknown_iid)) + { + *iface = self; + return V3_OK; + } + + if (v3_tuid_match(iid, v3_interface)) + { + *iface = self; + return V3_OK; + } + + *iface = NULL; + return V3_NO_INTERFACE; +} + +static V3_API uint32_t dpf_static__ref(void*) { return 1; } +static V3_API uint32_t dpf_static__unref(void*) { return 0; } + // -------------------------------------------------------------------------------------------------------------------- // dpf_ui_connection_point @@ -566,79 +603,61 @@ struct dpf_ui_connection_point : v3_connection_point_cpp { : uivst3(v), other(nullptr) { - static const uint8_t* kSupportedInterfaces[] = { - v3_funknown_iid, - v3_connection_point_iid - }; + static constexpr const v3_tuid interface = V3_ID_COPY(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); + // v3_funknown, single instance + query_interface = dpf_static__query_interface; + ref = dpf_static__ref; + unref = dpf_static__unref; - 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 = connect; + point.disconnect = disconnect; + point.notify = notify; + } - point.connect = []V3_API(void* self, 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); + // ---------------------------------------------------------------------------------------------------------------- + // v3_connection_point - point->other = other; + static V3_API v3_result connect(void* self, v3_connection_point** other) + { + 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_INITIALIZED); + DISTRHO_SAFE_ASSERT_RETURN(point->other == nullptr, V3_INVALID_ARG); - if (UIVst3* const uivst3 = point->uivst3) - uivst3->connect(other); + point->other = other; - return V3_OK; - }; + if (UIVst3* const uivst3 = point->uivst3) + uivst3->connect(other); - point.disconnect = []V3_API(void* self, 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); + return V3_OK; + }; - point->other = nullptr; + static V3_API v3_result disconnect(void* self, v3_connection_point** other) + { + 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_INITIALIZED); + DISTRHO_SAFE_ASSERT_RETURN(point->other != nullptr, V3_INVALID_ARG); - if (UIVst3* const uivst3 = point->uivst3) - uivst3->disconnect(); + point->other = nullptr; - return V3_OK; - }; + if (UIVst3* const uivst3 = point->uivst3) + uivst3->disconnect(); - point.notify = []V3_API(void* self, v3_message** message) -> v3_result - { - dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; - DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALISED); + return V3_OK; + }; + + static V3_API v3_result notify(void* self, v3_message** message) + { + dpf_ui_connection_point* const point = *(dpf_ui_connection_point**)self; + DISTRHO_SAFE_ASSERT_RETURN(point != nullptr, V3_NOT_INITIALIZED); - UIVst3* const uivst3 = point->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + UIVst3* const uivst3 = point->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - return uivst3->notify(message); - }; + return uivst3->notify(message); } }; @@ -654,57 +673,32 @@ struct dpf_plugin_view_content_scale : v3_plugin_view_content_scale_cpp { : uivst3(v), scaleFactor(0.0f) { - query_interface = query_interface_fn; - ref = ref_fn; - unref = unref_fn; - scale.set_content_scale_factor = set_content_scale_factor_fn; - } - - // ---------------------------------------------------------------------------------------------------------------- - // v3_funknown - - static v3_result V3_API query_interface_fn(void* self, const v3_tuid iid, void** iface) - { - d_stdout("dpf_plugin_view_content_scale::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + static constexpr const v3_tuid interface = V3_ID_COPY(v3_plugin_view_content_scale_iid); - static const uint8_t* kSupportedInterfaces[] = { - v3_funknown_iid, - v3_plugin_view_content_scale_iid - }; + // v3_funknown, single instance + query_interface = dpf_static__query_interface; + ref = dpf_static__ref; + unref = dpf_static__unref; - for (const uint8_t* interface_iid : kSupportedInterfaces) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } - - return V3_NO_INTERFACE; + // v3_plugin_view_content_scale + scale.set_content_scale_factor = set_content_scale_factor; } - // there is only a single instance of this, so we don't have to care here - static uint32_t V3_API ref_fn(void*) { return 1; }; - static uint32_t V3_API unref_fn(void*) { return 0; }; - // ---------------------------------------------------------------------------------------------------------------- - // v3_plugin_view_content_scale_steinberg + // v3_plugin_view_content_scale - static v3_result V3_API set_content_scale_factor_fn(void* self, float factor) + static V3_API v3_result set_content_scale_factor(void* self, float factor) { d_stdout("dpf_plugin_view::set_content_scale_factor => %p %f", self, factor); dpf_plugin_view_content_scale* const scale = *(dpf_plugin_view_content_scale**)self; - DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, V3_NOT_INITIALISED); + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, V3_NOT_INITIALIZED); scale->scaleFactor = factor; if (UIVst3* const uivst3 = scale->uivst3) return uivst3->setContentScaleFactor(factor); - return V3_NOT_INITIALISED; + return V3_NOT_INITIALIZED; } }; @@ -718,46 +712,21 @@ struct dpf_timer_handler : v3_timer_handler_cpp { dpf_timer_handler(ScopedPointer& v) : uivst3(v) { - query_interface = query_interface_fn; - ref = ref_fn; - unref = unref_fn; - handler.on_timer = on_timer; - } + static constexpr const v3_tuid interface = V3_ID_COPY(v3_timer_handler_iid); - // ---------------------------------------------------------------------------------------------------------------- - // v3_funknown + // v3_funknown, single instance + query_interface = dpf_static__query_interface; + ref = dpf_static__ref; + unref = dpf_static__unref; - static v3_result V3_API query_interface_fn(void* self, const v3_tuid iid, void** iface) - { - d_stdout("dpf_plugin_view_content_scale::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_plugin_view_content_scale_iid - }; - - for (const uint8_t* interface_iid : kSupportedInterfaces) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } - - return V3_NO_INTERFACE; + // v3_timer_handler + handler.on_timer = on_timer; } - // there is only a single instance of this, so we don't have to care here - static uint32_t V3_API ref_fn(void*) { return 1; }; - static uint32_t V3_API unref_fn(void*) { return 0; }; - // ---------------------------------------------------------------------------------------------------------------- // v3_timer_handler - static void V3_API on_timer(void* self) + static V3_API void on_timer(void* self) { dpf_timer_handler* const handler = *(dpf_timer_handler**)self; DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); @@ -770,8 +739,18 @@ struct dpf_timer_handler : v3_timer_handler_cpp { // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view +static const char* const kSupportedPlatforms[] = { +#ifdef _WIN32 + V3_VIEW_PLATFORM_TYPE_HWND, +#elif defined(__APPLE__) + V3_VIEW_PLATFORM_TYPE_NSVIEW, +#else + V3_VIEW_PLATFORM_TYPE_X11, +#endif +}; + struct dpf_plugin_view : v3_plugin_view_cpp { - std::atomic refcounter; + std::atomic_int refcounter; ScopedPointer* self; ScopedPointer connection; ScopedPointer scale; @@ -794,294 +773,301 @@ struct dpf_plugin_view : v3_plugin_view_cpp { sampleRate(sr), frame(nullptr) { - static const uint8_t* kSupportedInterfacesBase[] = { - v3_funknown_iid, - v3_plugin_view_iid - }; - - static const char* const kSupportedPlatforms[] = { -#ifdef _WIN32 - V3_VIEW_PLATFORM_TYPE_HWND, -#elif defined(__APPLE__) - V3_VIEW_PLATFORM_TYPE_NSVIEW, -#else - V3_VIEW_PLATFORM_TYPE_X11, -#endif - }; + // v3_funknown, everything custom + query_interface = query_interface_view; + ref = ref_view; + unref = unref_view; - // ------------------------------------------------------------------------------------------------------------ - // v3_funknown + // v3_plugin_view + view.is_platform_type_supported = is_platform_type_supported; + view.attached = attached; + view.removed = removed; + view.on_wheel = on_wheel; + view.on_key_down = on_key_down; + view.on_key_up = on_key_up; + view.get_size = get_size; + view.on_size = on_size; + view.on_focus = on_focus; + view.set_frame = set_frame; + view.can_resize = can_resize; + view.check_size_constraint = check_size_constraint; + } - query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result - { - d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface); - *iface = NULL; - DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); + // ---------------------------------------------------------------------------------------------------------------- + // v3_funknown - for (const uint8_t* interface_iid : kSupportedInterfacesBase) - { - if (v3_tuid_match(interface_iid, iid)) - { - *iface = self; - return V3_OK; - } - } + static V3_API v3_result query_interface_view(void* self, const v3_tuid iid, void** iface) + { + d_stdout("dpf_plugin_view::query_interface => %p %s %p", self, tuid2str(iid), iface); + *iface = NULL; + DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE); + if (v3_tuid_match(iid, v3_funknown_iid)) + { + *iface = self; + return V3_OK; + } - 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(iid, v3_plugin_view_iid)) + { + *iface = self; + return V3_OK; + } - if (v3_tuid_match(v3_plugin_view_content_scale_iid, iid)) - { - if (view->scale == nullptr) - view->scale = new dpf_plugin_view_content_scale(view->uivst3); - *iface = &view->scale; - return V3_OK; - } + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE); - return 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; + } - ref = []V3_API(void* self) -> uint32_t + if (v3_tuid_match(v3_plugin_view_content_scale_iid, iid)) { - d_stdout("dpf_plugin_view::ref => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); + if (view->scale == nullptr) + view->scale = new dpf_plugin_view_content_scale(view->uivst3); + *iface = &view->scale; + return V3_OK; + } - return ++view->refcounter; - }; + return V3_NO_INTERFACE; + } - unref = []V3_API(void* self) -> uint32_t - { - d_stdout("dpf_plugin_view::unref => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); + static V3_API uint32_t ref_view(void* self) + { + return ++(*(dpf_plugin_view**)self)->refcounter; + } - if (const int refcounter = --view->refcounter) - return refcounter; + static V3_API uint32_t unref_view(void* self) + { + ScopedPointer* const viewptr = (ScopedPointer*)self; + dpf_plugin_view* const view = *viewptr; - if (view->connection != nullptr && view->connection->other) - v3_cpp_obj(view->connection->other)->disconnect(view->connection->other, - (v3_connection_point**)&view->connection); + if (const int refcount = --view->refcounter) + { + d_stdout("dpf_plugin_view::unref => %p | refcount %i", self, refcount); + return refcount; + } - *view->self = nullptr; - delete (dpf_plugin_view**)self; - return 0; - }; + d_stdout("dpf_plugin_view::unref => %p | refcount is zero, deleting everything now!", self); - // ------------------------------------------------------------------------------------------------------------ - // v3_plugin_view + if (view->connection != nullptr && view->connection->other) + v3_cpp_obj(view->connection->other)->disconnect(view->connection->other, + (v3_connection_point**)&view->connection); - view.is_platform_type_supported = []V3_API(void* self, const char* platform_type) -> v3_result - { - d_stdout("dpf_plugin_view::is_platform_type_supported => %p %s", self, platform_type); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + *(view->self) = nullptr; + delete viewptr; + return 0; + } - for (size_t i=0; i %p %s", self, platform_type); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result + for (size_t i=0; i %p %p %s", self, parent, platform_type); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG); + if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) + return V3_OK; + } - for (size_t i=0; iframe != nullptr, V3_INVALID_ARG); - - v3_run_loop** runloop = nullptr; - v3_cpp_obj_query_interface(view->frame, v3_run_loop_iid, &runloop); - DISTRHO_SAFE_ASSERT_RETURN(runloop != nullptr, V3_INVALID_ARG); - #endif - - const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; - view->uivst3 = new UIVst3((v3_plugin_view**)view->self, - view->host, - (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); - - #ifdef DPF_VST3_USING_HOST_RUN_LOOP - // register a timer host run loop stuff - view->timer = new dpf_timer_handler(view->uivst3); - v3_cpp_obj(runloop)->register_timer(runloop, - (v3_timer_handler**)&view->timer, - DPF_VST3_TIMER_INTERVAL); - #endif - - return V3_OK; - } - } + return V3_NOT_IMPLEMENTED; + }; - return V3_NOT_IMPLEMENTED; - }; + static V3_API v3_result attached(void* self, void* parent, const char* platform_type) + { + d_stdout("dpf_plugin_view::attached => %p %p %s", self, parent, platform_type); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); + DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG); - view.removed = []V3_API(void* self) -> v3_result + for (size_t i=0; i %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); - DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); - - #ifdef DPF_VST3_USING_HOST_RUN_LOOP - // unregister our timer as needed - if (view->timer != nullptr) + if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) { + #ifdef DPF_VST3_USING_HOST_RUN_LOOP + // find host run loop to plug ourselves into (required on some systems) + DISTRHO_SAFE_ASSERT_RETURN(view->frame != nullptr, V3_INVALID_ARG); + v3_run_loop** runloop = nullptr; - if (v3_cpp_obj_query_interface(view->host, v3_run_loop_iid, &runloop) == V3_OK && runloop != nullptr) - v3_cpp_obj(runloop)->unregister_timer(runloop, (v3_timer_handler**)&view->timer); + v3_cpp_obj_query_interface(view->frame, v3_run_loop_iid, &runloop); + DISTRHO_SAFE_ASSERT_RETURN(runloop != nullptr, V3_INVALID_ARG); + #endif + + const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; + view->uivst3 = new UIVst3((v3_plugin_view**)view->self, + view->host, + (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); + + #ifdef DPF_VST3_USING_HOST_RUN_LOOP + // register a timer host run loop stuff + view->timer = new dpf_timer_handler(view->uivst3); + v3_cpp_obj(runloop)->register_timer(runloop, + (v3_timer_handler**)&view->timer, + DPF_VST3_TIMER_INTERVAL); + #endif - view->timer = nullptr; + return V3_OK; } - #endif + } - view->uivst3 = nullptr; - return V3_OK; - }; + return V3_NOT_IMPLEMENTED; + }; - view.on_wheel = []V3_API(void* self, float distance) -> v3_result + static V3_API v3_result removed(void* self) + { + d_stdout("dpf_plugin_view::removed => %p", self); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); + DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG); + + #ifdef DPF_VST3_USING_HOST_RUN_LOOP + // unregister our timer as needed + if (view->timer != nullptr) { - d_stdout("dpf_plugin_view::on_wheel => %p %f", self, distance); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + v3_run_loop** runloop = nullptr; + if (v3_cpp_obj_query_interface(view->host, v3_run_loop_iid, &runloop) == V3_OK && runloop != nullptr) + v3_cpp_obj(runloop)->unregister_timer(runloop, (v3_timer_handler**)&view->timer); - UIVst3* const uivst3 = view->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + view->timer = nullptr; + } + #endif - return uivst3->onWheel(distance); - }; + view->uivst3 = nullptr; + return V3_OK; + }; - view.on_key_down = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result - { - d_stdout("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result on_wheel(void* self, float distance) + { + d_stdout("dpf_plugin_view::on_wheel => %p %f", self, distance); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - UIVst3* const uivst3 = view->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - return uivst3->onKeyDown(key_char, key_code, modifiers); - }; + return uivst3->onWheel(distance); + }; - view.on_key_up = []V3_API(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) -> v3_result - { - d_stdout("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result on_key_down(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) + { + d_stdout("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - UIVst3* const uivst3 = view->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - return uivst3->onKeyUp(key_char, key_code, modifiers); - }; + return uivst3->onKeyDown(key_char, key_code, modifiers); + }; - view.get_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result - { - d_stdout("dpf_plugin_view::get_size => %p", self); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result on_key_up(void* self, int16_t key_char, int16_t key_code, int16_t modifiers) + { + d_stdout("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - if (UIVst3* const uivst3 = view->uivst3) - return uivst3->getSize(rect); + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - // special case: allow UI to not be attached yet, as a way to get size before window creation + return uivst3->onKeyUp(key_char, key_code, modifiers); + }; - const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; - UIExporter tmpUI(nullptr, 0, view->sampleRate, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - view->instancePointer, scaleFactor); - rect->right = tmpUI.getWidth(); - rect->bottom = tmpUI.getHeight(); - return V3_OK; - }; + static V3_API v3_result get_size(void* self, v3_view_rect* rect) + { + d_stdout("dpf_plugin_view::get_size => %p", self); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - view.on_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result - { - d_stdout("dpf_plugin_view::on_size => %p %p", self, rect); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + if (UIVst3* const uivst3 = view->uivst3) + return uivst3->getSize(rect); - UIVst3* const uivst3 = view->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + // special case: allow UI to not be attached yet, as a way to get size before window creation - return uivst3->onSize(rect); - }; + const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; + UIExporter tmpUI(nullptr, 0, view->sampleRate, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + view->instancePointer, scaleFactor); + rect->right = tmpUI.getWidth(); + rect->bottom = tmpUI.getHeight(); + return V3_OK; + }; - view.on_focus = []V3_API(void* self, v3_bool state) -> v3_result - { - d_stdout("dpf_plugin_view::on_focus => %p %u", self, state); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result on_size(void* self, v3_view_rect* rect) + { + d_stdout("dpf_plugin_view::on_size => %p %p", self, rect); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - UIVst3* const uivst3 = view->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - return uivst3->onFocus(state); - }; + return uivst3->onSize(rect); + }; - view.set_frame = []V3_API(void* self, v3_plugin_frame** frame) -> v3_result - { - d_stdout("dpf_plugin_view::set_frame => %p %p", self, frame); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result on_focus(void* self, v3_bool state) + { + d_stdout("dpf_plugin_view::on_focus => %p %u", self, state); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - view->frame = frame; + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - if (UIVst3* const uivst3 = view->uivst3) - return uivst3->setFrame(frame); + return uivst3->onFocus(state); + }; - return V3_NOT_INITIALISED; - }; + static V3_API v3_result set_frame(void* self, v3_plugin_frame** frame) + { + d_stdout("dpf_plugin_view::set_frame => %p %p", self, frame); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - view.can_resize = []V3_API(void* self) -> v3_result - { - d_stdout("dpf_plugin_view::can_resize => %p", self); + view->frame = frame; + + if (UIVst3* const uivst3 = view->uivst3) + return uivst3->setFrame(frame); + + return V3_NOT_INITIALIZED; + }; + + static V3_API v3_result can_resize(void* self) + { + d_stdout("dpf_plugin_view::can_resize => %p", self); // #if DISTRHO_UI_USER_RESIZABLE // return V3_OK; // #else - return V3_NOT_IMPLEMENTED; + return V3_NOT_IMPLEMENTED; // #endif - }; + }; - view.check_size_constraint = []V3_API(void* self, v3_view_rect* rect) -> v3_result - { - d_stdout("dpf_plugin_view::check_size_constraint => %p %p", self, rect); - dpf_plugin_view* const view = *(dpf_plugin_view**)self; - DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED); + static V3_API v3_result check_size_constraint(void* self, v3_view_rect* rect) + { + d_stdout("dpf_plugin_view::check_size_constraint => %p %p", self, rect); + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALIZED); - UIVst3* const uivst3 = view->uivst3; - DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED); + UIVst3* const uivst3 = view->uivst3; + DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED); - return uivst3->checkSizeConstraint(rect); - }; - } + return uivst3->checkSizeConstraint(rect); + }; }; // -------------------------------------------------------------------------------------------------------------------- diff --git a/distrho/src/travesty/audio_processor.h b/distrho/src/travesty/audio_processor.h index 6f00d89b..85b2297d 100644 --- a/distrho/src/travesty/audio_processor.h +++ b/distrho/src/travesty/audio_processor.h @@ -238,4 +238,28 @@ struct v3_audio_processor { static constexpr const v3_tuid v3_audio_processor_iid = V3_ID(0x42043F99, 0xB7DA453C, 0xA569E79D, 0x9AAEC33D); +#ifdef __cplusplus + +/** + * C++ variants + */ + +struct v3_param_value_queue_cpp : v3_funknown { + v3_param_value_queue queue; +}; + +struct v3_param_changes_cpp : v3_funknown { + v3_param_changes changes; +}; + +struct v3_process_context_requirements_cpp : v3_funknown { + v3_process_context_requirements req; +}; + +struct v3_audio_processor_cpp : v3_funknown { + v3_audio_processor proc; +}; + +#endif + #include "align_pop.h" diff --git a/distrho/src/travesty/base.h b/distrho/src/travesty/base.h index bc7b5fd1..86a2378c 100644 --- a/distrho/src/travesty/base.h +++ b/distrho/src/travesty/base.h @@ -128,7 +128,7 @@ enum { V3_INVALID_ARG, V3_NOT_IMPLEMENTED, V3_INTERNAL_ERR, - V3_NOT_INITIALISED, + V3_NOT_INITIALIZED, V3_NOMEM }; @@ -155,6 +155,10 @@ enum { } #endif // V3_COM_COMPAT +#define V3_ID_COPY(iid) \ + { iid[0], iid[1], iid[ 2], iid[ 3], iid[ 4], iid[ 5], iid[ 6], iid[ 7], \ + iid[8], iid[9], iid[10], iid[11], iid[12], iid[13], iid[14], iid[15] } + /** * funknown */ diff --git a/distrho/src/travesty/factory.h b/distrho/src/travesty/factory.h index db3f46be..4db5eb91 100644 --- a/distrho/src/travesty/factory.h +++ b/distrho/src/travesty/factory.h @@ -101,3 +101,17 @@ struct v3_plugin_factory_3 { static constexpr const v3_tuid v3_plugin_factory_3_iid = V3_ID(0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931); + +#ifdef __cplusplus + +/** + * C++ variants + */ + +struct v3_plugin_factory_cpp : v3_funknown { + v3_plugin_factory v1; + v3_plugin_factory_2 v2; + v3_plugin_factory_3 v3; +}; + +#endif diff --git a/distrho/src/travesty/message.h b/distrho/src/travesty/message.h index 733a0e2b..3cd77a68 100644 --- a/distrho/src/travesty/message.h +++ b/distrho/src/travesty/message.h @@ -77,11 +77,11 @@ static constexpr const v3_tuid v3_connection_point_iid = */ struct v3_attribute_list_cpp : v3_funknown { - v3_attribute_list attrlist; + v3_attribute_list attrlist; }; struct v3_message_cpp : v3_funknown { - v3_message msg; + v3_message msg; }; struct v3_connection_point_cpp : v3_funknown {