DPF

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

commit c1684b1078a5f902fe5805689a1cacac621b6807
parent 63c52b3b38497bbfb9cd57bfcc8ab7e4a2a3a9e8
Author: falkTX <falktx@falktx.com>
Date:   Fri, 24 Sep 2021 00:37:27 +0100

Setup/testing basic VST3 UI interaction

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

Diffstat:
Mdistrho/src/DistrhoPluginVST3.cpp | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 205 insertions(+), 34 deletions(-)

diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -762,14 +762,14 @@ public: return V3_NOT_IMPLEMENTED; }; - v3_result normalisedParameterToPlain(const v3_param_id index, const double normalised) + double normalisedParameterToPlain(const v3_param_id index, const double normalised) { DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG); return fPlugin.getParameterRanges(index).getUnnormalizedValue(normalised); }; - v3_result plainParameterToNormalised(const v3_param_id index, const double plain) + double plainParameterToNormalised(const v3_param_id index, const double plain) { DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount(), V3_INVALID_ARG); @@ -856,6 +856,10 @@ static const sendNoteFunc sendNoteCallback = nullptr; static const setStateFunc setStateCallback = nullptr; #endif +struct v3_component_handler_cpp : v3_funknown { + v3_component_handler handler; +}; + class UIVst3 : public Thread { public: @@ -931,6 +935,17 @@ public: return fUI.getScaleFactor(); } + void notifyScaleFactorChanged(const double scaleFactor) + { + fUI.notifyScaleFactorChanged(scaleFactor); + } + + // TODO dont use this + void setParameterValueFromDSP(const uint32_t index, const float value) + { + fUI.parameterChanged(index, value); + } + // ---------------------------------------------------------------------------------------------------------------- // v3_plugin_view interface calls @@ -939,7 +954,7 @@ public: frame = f; } - void setHandler(v3_component_handler** const h) noexcept + void setHandler(v3_component_handler_cpp** const h) noexcept { handler = h; } @@ -947,18 +962,30 @@ public: // ---------------------------------------------------------------------------------------------------------------- protected: - void editParameter(const uint32_t /*index*/, const bool /*started*/) const + void editParameter(const uint32_t index, const bool started) const { - // hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index); + DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); + + v3_component_handler_cpp* const chandler = *handler; + DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); + + if (started) + chandler->handler.begin_edit(handler, index); + else + chandler->handler.end_edit(handler, index); } - void setParameterValue(const uint32_t /*index*/, const float /*realValue*/) + void setParameterValue(const uint32_t index, const float realValue) { - // const ParameterRanges& ranges(fPlugin->getParameterRanges(index)); - // const float perValue(ranges.getNormalizedValue(realValue)); + DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); + + v3_component_handler_cpp* const chandler = *handler; + DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); - // fPlugin->setParameterValue(index, realValue); - // hostCallback(audioMasterAutomate, index, 0, nullptr, perValue); + const double value = vst3->plainParameterToNormalised(index, realValue); + chandler->handler.perform_edit(handler, index, value); + + // TODO send change to DSP side? } void setSize(uint width, uint height) @@ -1001,7 +1028,7 @@ private: // VST3 stuff ScopedPointer<PluginVst3>& vst3; v3_plugin_frame* frame; - v3_component_handler** handler = nullptr; + v3_component_handler_cpp** handler = nullptr; // Plugin UI UIExporter fUI; @@ -1053,25 +1080,116 @@ private: static ScopedPointer<PluginExporter> gPluginInfo; +#if DISTRHO_PLUGIN_HAS_UI +// -------------------------------------------------------------------------------------------------------------------- +// dpf_plugin_view_content_scale + +struct v3_plugin_view_content_scale_steinberg_cpp : v3_funknown { + v3_plugin_view_content_scale_steinberg scale; +}; + +struct dpf_plugin_view_scale : v3_plugin_view_content_scale_steinberg_cpp { + std::atomic<int> refcounter; + ScopedPointer<dpf_plugin_view_scale>* self; + ScopedPointer<UIVst3>& uivst3; + float lastScaleFactor = 0.0f; + + dpf_plugin_view_scale(ScopedPointer<dpf_plugin_view_scale>* s, ScopedPointer<UIVst3>& v) + : refcounter(1), + self(s), + uivst3(v) + { + static const uint8_t* kSupportedInterfaces[] = { + v3_funknown_iid, + v3_plugin_view_content_scale_steinberg_iid + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_funknown + + query_interface = []V3_API(void* self, const v3_tuid iid, void** iface) -> v3_result + { + d_stdout("dpf_plugin_view_scale::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; + }; + + ref = []V3_API(void* self) -> uint32_t + { + d_stdout("dpf_plugin_view_scale::ref => %p", self); + dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, 0); + + return ++scale->refcounter; + }; + + unref = []V3_API(void* self) -> uint32_t + { + d_stdout("dpf_plugin_view_scale::unref => %p", self); + dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, 0); + + if (const int refcounter = --scale->refcounter) + return refcounter; + + *(dpf_plugin_view_scale**)self = nullptr; + *scale->self = nullptr; + return 0; + }; + + // ------------------------------------------------------------------------------------------------------------ + // v3_plugin_view_content_scale_steinberg + + scale.set_content_scale_factor = []V3_API(void* self, float factor) -> v3_result + { + d_stdout("dpf_plugin_view::set_content_scale_factor => %p %f", self, factor); + dpf_plugin_view_scale* const scale = *(dpf_plugin_view_scale**)self; + DISTRHO_SAFE_ASSERT_RETURN(scale != nullptr, V3_NOT_INITIALISED); + + if (UIVst3* const uivst3 = scale->uivst3) + if (d_isNotZero(scale->lastScaleFactor) && d_isNotEqual(scale->lastScaleFactor, factor)) + uivst3->notifyScaleFactorChanged(factor); + + scale->lastScaleFactor = factor; + return V3_OK; + }; + } +}; + // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view -#if DISTRHO_PLUGIN_HAS_UI struct v3_plugin_view_cpp : v3_funknown { v3_plugin_view view; }; struct dpf_plugin_view : v3_plugin_view_cpp { + std::atomic<int> refcounter; + ScopedPointer<dpf_plugin_view>* self; + ScopedPointer<dpf_plugin_view_scale> scale; ScopedPointer<PluginVst3>& vst3; ScopedPointer<UIVst3> uivst3; - double lastScaleFactor = 0.0; - v3_component_handler** handler = nullptr; + // cached values + v3_component_handler_cpp** handler = nullptr; v3_plugin_frame* hostframe = nullptr; - dpf_plugin_view(ScopedPointer<PluginVst3>& v) - : vst3(v) + dpf_plugin_view(ScopedPointer<dpf_plugin_view>* s, ScopedPointer<PluginVst3>& v) + : refcounter(1), + self(s), + vst3(v) { - static const uint8_t* kSupportedFactories[] = { + static const uint8_t* kSupportedInterfacesBase[] = { v3_funknown_iid, v3_plugin_view_iid }; @@ -1085,28 +1203,49 @@ struct dpf_plugin_view : v3_plugin_view_cpp { *iface = NULL; DISTRHO_SAFE_ASSERT_RETURN(self != nullptr, V3_NO_INTERFACE); - for (const uint8_t* factory_iid : kSupportedFactories) + for (const uint8_t* interface_iid : kSupportedInterfacesBase) { - if (v3_tuid_match(factory_iid, iid)) + if (v3_tuid_match(interface_iid, iid)) { *iface = self; return V3_OK; } } + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NO_INTERFACE); + + if (v3_tuid_match(v3_plugin_view_content_scale_steinberg_iid, iid)) + { + if (view->scale == nullptr) + view->scale = new dpf_plugin_view_scale(&view->scale, view->uivst3); + *iface = &view->scale; + return V3_OK; + } + return V3_NO_INTERFACE; }; - // we only support 1 plugin per binary, so don't have to care here ref = []V3_API(void* self) -> uint32_t { d_stdout("dpf_plugin_view::ref => %p", self); - return 1; + dpf_plugin_view* const view = *(dpf_plugin_view**)self; + DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, 0); + + return ++view->refcounter; }; 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); + + if (const int refcounter = --view->refcounter) + return refcounter; + + *(dpf_plugin_view**)self = nullptr; + *view->self = nullptr; return 0; }; @@ -1141,7 +1280,9 @@ struct dpf_plugin_view : v3_plugin_view_cpp { 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); - view->uivst3 = new UIVst3(view->vst3, view->hostframe, (uintptr_t)parent, view->lastScaleFactor); + + const double scaleFactor = view->scale != nullptr ? view->scale->lastScaleFactor : 0.0; + view->uivst3 = new UIVst3(view->vst3, view->hostframe, (uintptr_t)parent, scaleFactor); view->uivst3->setHandler(view->handler); return V3_OK; }; @@ -1203,9 +1344,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp { } else { + const double scaleFactor = view->scale != nullptr ? view->scale->lastScaleFactor : 0.0; UIExporter tmpUI(nullptr, 0, view->vst3->getSampleRate(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - view->vst3->getInstancePointer(), view->lastScaleFactor); + view->vst3->getInstancePointer(), scaleFactor); rect->right = tmpUI.getWidth(); rect->bottom = tmpUI.getHeight(); # ifdef DISTRHO_OS_MAC @@ -1284,6 +1426,8 @@ struct dpf_edit_controller : v3_edit_controller_cpp { ScopedPointer<dpf_plugin_view> view; ScopedPointer<PluginVst3>& vst3; bool initialized; + // cached values + v3_component_handler_cpp** handler = nullptr; dpf_edit_controller(ScopedPointer<dpf_edit_controller>* const s, ScopedPointer<PluginVst3>& v) : refcounter(1), @@ -1502,6 +1646,15 @@ struct dpf_edit_controller : v3_edit_controller_cpp { DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, V3_NOT_INITIALISED); vst3->setParameterNormalized(index, normalised); + + if (dpf_plugin_view* const view = controller->view) + { + if (UIVst3* const uivst3 = view->uivst3) + { + uivst3->setParameterValueFromDSP(index, vst3->normalisedParameterToPlain(index, normalised)); + } + } + return V3_OK; }; @@ -1510,12 +1663,18 @@ struct dpf_edit_controller : v3_edit_controller_cpp { 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); - DISTRHO_SAFE_ASSERT_RETURN(controller->view != nullptr, V3_NOT_INITIALISED); - controller->view->handler = handler; + v3_component_handler_cpp** const cpphandler = (v3_component_handler_cpp**)handler; - if (UIVst3* const uivst3 = controller->view->uivst3) - uivst3->setHandler(handler); + controller->handler = cpphandler; + + if (controller->view != nullptr) + { + controller->view->handler = cpphandler; + + if (UIVst3* const uivst3 = controller->view->uivst3) + uivst3->setHandler(cpphandler); + } return V3_OK; }; @@ -1527,7 +1686,10 @@ struct dpf_edit_controller : v3_edit_controller_cpp { DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr); if (controller->view == nullptr) - controller->view = new dpf_plugin_view(controller->vst3); + { + controller->view = new dpf_plugin_view(&controller->view, controller->vst3); + controller->view->handler = controller->handler; + } return (v3_plugin_view**)&controller->view; }; @@ -1714,13 +1876,14 @@ struct dpf_component : v3_component_cpp { ScopedPointer<dpf_component>* self; ScopedPointer<dpf_audio_processor> processor; ScopedPointer<dpf_edit_controller> controller; + ScopedPointer<dpf_plugin_view> view; ScopedPointer<PluginVst3> vst3; dpf_component(ScopedPointer<dpf_component>* const s) : refcounter(1), self(s) { - static const uint8_t* kSupportedBaseFactories[] = { + static const uint8_t* kSupportedInterfacesBase[] = { v3_funknown_iid, v3_plugin_base_iid, v3_component_iid @@ -1734,18 +1897,18 @@ struct dpf_component : v3_component_cpp { d_stdout("dpf_component::query_interface => %p %s %p", self, tuid2str(iid), iface); *iface = NULL; - dpf_component* const component = *(dpf_component**)self; - DISTRHO_SAFE_ASSERT_RETURN(component != nullptr, V3_NO_INTERFACE); - - for (const uint8_t* factory_iid : kSupportedBaseFactories) + for (const uint8_t* interface_iid : kSupportedInterfacesBase) { - if (v3_tuid_match(factory_iid, iid)) + if (v3_tuid_match(interface_iid, iid)) { *iface = self; return V3_OK; } } + 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) @@ -1762,6 +1925,14 @@ struct dpf_component : v3_component_cpp { return V3_OK; } + if (v3_tuid_match(v3_plugin_view_iid, iid)) + { + if (component->view == nullptr) + component->view = new dpf_plugin_view(&component->view, component->vst3); + *iface = &component->view; + return V3_OK; + } + return V3_NO_INTERFACE; };