DPF

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

commit 4645f65e9610262aff8ed8db0537ec7743bf6658
parent 80824ae66632dddbbfa7484ddd6e9afe934c28d2
Author: falkTX <falktx@falktx.com>
Date:   Sat, 25 Sep 2021 18:35:55 +0100

VST3: Implement UI->DSP parameter changes

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

Diffstat:
Mdistrho/src/DistrhoPluginInternal.hpp | 6++++++
Mdistrho/src/DistrhoPluginVST3.cpp | 75++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mdistrho/src/DistrhoUIPrivateData.hpp | 1+
Mdistrho/src/DistrhoUIVST3.cpp | 79+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mdistrho/src/travesty/base.h | 6+++++-
Mdistrho/src/travesty/edit_controller.h | 13+++++++++++++
6 files changed, 112 insertions(+), 68 deletions(-)

diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp @@ -171,6 +171,12 @@ struct Plugin::PrivateData { parameterOffset += 1; # endif #endif + +#ifdef DISTRHO_PLUGIN_TARGET_VST3 +# if DISTRHO_PLUGIN_WANT_PROGRAMS + parameterOffset += 1; +# endif +#endif } ~PrivateData() noexcept diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp @@ -1048,15 +1048,15 @@ public: return fPlugin.getParameterCount() + fParameterOffset; } - v3_result getParameterInfo(const int32_t index, v3_param_info* const info) const noexcept + v3_result getParameterInfo(const int32_t rindex, v3_param_info* const info) const noexcept { - DISTRHO_SAFE_ASSERT_RETURN(index >= 0, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_RETURN(rindex >= 0, V3_INVALID_ARG); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) { std::memset(info, 0, sizeof(v3_param_info)); - info->param_id = index; + info->param_id = rindex; info->flags = V3_PARAM_CAN_AUTOMATE | V3_PARAM_IS_LIST | V3_PARAM_PROGRAM_CHANGE; info->step_count = fProgramCountMinusOne; strncpy_utf16(info->title, "Current Program", 128); @@ -1065,8 +1065,8 @@ public: } #endif - const uint32_t uindex = static_cast<uint32_t>(index) - fParameterOffset; - DISTRHO_SAFE_ASSERT_RETURN(uindex < fPlugin.getParameterCount(), V3_INVALID_ARG); + const uint32_t index = static_cast<uint32_t>(rindex) - fParameterOffset; + DISTRHO_SAFE_ASSERT_UINT_RETURN(index < fPlugin.getParameterCount(), index, V3_INVALID_ARG); // set up flags int32_t flags = 0; @@ -1100,7 +1100,7 @@ public: step_count = ranges.max - ranges.min - 1; std::memset(info, 0, sizeof(v3_param_info)); - info->param_id = index; + info->param_id = rindex; info->flags = flags; info->step_count = step_count; info->default_normalised_value = ranges.getNormalizedValue(ranges.def); @@ -1111,12 +1111,12 @@ public: return V3_OK; } - v3_result getParameterStringForValue(const v3_param_id index, const double normalised, v3_str_128 output) + v3_result getParameterStringForValue(const v3_param_id rindex, const double normalised, v3_str_128 output) { - DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount() + fParameterOffset, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fPlugin.getParameterCount() + fParameterOffset, rindex, V3_INVALID_ARG); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) { DISTRHO_SAFE_ASSERT_RETURN(normalised >= 0.0 && normalised <= 1.0, V3_INVALID_ARG); @@ -1126,17 +1126,17 @@ public: } #endif - const ParameterRanges& ranges(fPlugin.getParameterRanges(index - fParameterOffset)); + const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex - fParameterOffset)); snprintf_f32_utf16(output, ranges.getUnnormalizedValue(normalised), 128); return V3_OK; } - v3_result getParameterValueForString(const v3_param_id index, int16_t*, double*) + v3_result getParameterValueForString(const v3_param_id rindex, int16_t*, double*) { - DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount() + fParameterOffset, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fPlugin.getParameterCount() + fParameterOffset, rindex, V3_INVALID_ARG); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) { // TODO find program index based on name return V3_NOT_IMPLEMENTED; @@ -1147,53 +1147,53 @@ public: return V3_NOT_IMPLEMENTED; }; - double normalisedParameterToPlain(const v3_param_id index, const double normalised) + double normalisedParameterToPlain(const v3_param_id rindex, const double normalised) { - DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount() + fParameterOffset, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fPlugin.getParameterCount() + fParameterOffset, rindex, 0.0); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) return std::round(normalised * fProgramCountMinusOne); #endif - const ParameterRanges& ranges(fPlugin.getParameterRanges(index - fParameterOffset)); + const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex - fParameterOffset)); return ranges.getUnnormalizedValue(normalised); }; - double plainParameterToNormalised(const v3_param_id index, const double plain) + double plainParameterToNormalised(const v3_param_id rindex, const double plain) { - DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount() + fParameterOffset, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fPlugin.getParameterCount() + fParameterOffset, rindex, 0.0); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) return std::max(0.0, std::min(1.0, plain / fProgramCountMinusOne)); #endif - const ParameterRanges& ranges(fPlugin.getParameterRanges(index - fParameterOffset)); + const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex - fParameterOffset)); return ranges.getNormalizedValue(plain); }; - double getParameterNormalized(const v3_param_id index) + double getParameterNormalized(const v3_param_id rindex) { - DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount() + fParameterOffset, 0.0); + DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fPlugin.getParameterCount() + fParameterOffset, rindex, 0.0); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) return std::max(0.0, std::min(1.0, (double)fCurrentProgram / fProgramCountMinusOne)); #endif - const float value = fPlugin.getParameterValue(index); - const ParameterRanges& ranges(fPlugin.getParameterRanges(index - fParameterOffset)); + const float value = fPlugin.getParameterValue(rindex - fParameterOffset); + const ParameterRanges& ranges(fPlugin.getParameterRanges(rindex - fParameterOffset)); return ranges.getNormalizedValue(value); } - v3_result setParameterNormalized(const v3_param_id index, const double value) + v3_result setParameterNormalized(const v3_param_id rindex, const double value) { - DISTRHO_SAFE_ASSERT_RETURN(index < fPlugin.getParameterCount() + fParameterOffset, V3_INVALID_ARG); + DISTRHO_SAFE_ASSERT_UINT_RETURN(rindex < fPlugin.getParameterCount() + fParameterOffset, rindex, V3_INVALID_ARG); DISTRHO_SAFE_ASSERT_RETURN(value >= 0.0 && value <= 1.0, V3_INVALID_ARG); #if DISTRHO_PLUGIN_WANT_PROGRAMS - if (index == 0) + if (rindex == 0) { fCurrentProgram = std::round(value * fProgramCountMinusOne); fPlugin.loadProgram(fCurrentProgram); @@ -1201,6 +1201,7 @@ public: } #endif + const uint32_t index = rindex - fParameterOffset; const uint32_t hints = fPlugin.getParameterHints(index); const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); @@ -1378,7 +1379,8 @@ private: // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_create (called from DSP side) -v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate); +v3_funknown** dpf_plugin_view_create(v3_edit_controller** controller, v3_component_handler** handler, + void* instancePointer, double sampleRate); #endif // -------------------------------------------------------------------------------------------------------------------- @@ -1570,7 +1572,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { controller.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 %f", self, 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_INITIALISED); @@ -1583,7 +1585,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { controller.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", self); + // 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); @@ -1595,7 +1597,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { controller.set_parameter_normalised = []V3_API(void* self, v3_param_id index, double normalised) -> v3_result { - d_stdout("dpf_edit_controller::set_parameter_normalised => %p %f", self, 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_INITIALISED); @@ -1637,7 +1639,10 @@ struct dpf_edit_controller : v3_edit_controller_cpp { DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr); #if DISTRHO_PLUGIN_HAS_UI - return (v3_plugin_view**)dpf_plugin_view_create(vst3->getInstancePointer(), vst3->getSampleRate()); + return (v3_plugin_view**)dpf_plugin_view_create((v3_edit_controller**)self, + controller->handler, + vst3->getInstancePointer(), + vst3->getSampleRate()); #else return nullptr; #endif diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp @@ -332,6 +332,7 @@ struct UI::PrivateData { parameterOffset += 1; # endif #endif + #ifdef DISTRHO_PLUGIN_TARGET_VST3 # if DISTRHO_PLUGIN_WANT_PROGRAMS parameterOffset += 1; diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp @@ -74,8 +74,13 @@ const char* tuid2str(const v3_tuid iid); class UIVst3 : public Thread { public: - UIVst3(const intptr_t winId, const float scaleFactor, const double sampleRate, - void* const instancePointer, v3_plugin_view** const view) + UIVst3(v3_plugin_view** const view, + v3_edit_controller** const controller, + v3_component_handler** const handler, + const intptr_t winId, + const float scaleFactor, + const double sampleRate, + void* const instancePointer) : fUI(this, winId, sampleRate, editParameterCallback, setParameterCallback, @@ -87,6 +92,8 @@ public: instancePointer, scaleFactor), fView(view), + fController(controller), + fHandler(handler), fFrame(nullptr), fScaleFactor(scaleFactor) { @@ -196,41 +203,35 @@ private: // VST3 stuff v3_plugin_view** const fView; + v3_edit_controller** const fController; + v3_component_handler** const fHandler; v3_plugin_frame** fFrame; - // v3_component_handler_cpp** handler = nullptr; // Temporary data float fScaleFactor; - void editParameter(const uint32_t /*index*/, const bool /*started*/) const + void editParameter(const uint32_t rindex, const bool started) const { -// 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); + DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,); + + if (started) + v3_cpp_obj(fHandler)->begin_edit(fHandler, rindex); + else + v3_cpp_obj(fHandler)->end_edit(fHandler, rindex); } - static void editParameterCallback(void* ptr, uint32_t index, bool started) + static void editParameterCallback(void* ptr, uint32_t rindex, bool started) { - ((UIVst3*)ptr)->editParameter(index, started); + ((UIVst3*)ptr)->editParameter(rindex, started); } - void setParameterValue(const uint32_t /*index*/, const float /*realValue*/) + void setParameterValue(const uint32_t rindex, const float realValue) { -// DISTRHO_SAFE_ASSERT_RETURN(handler != nullptr,); -// -// v3_component_handler_cpp* const chandler = *handler; -// DISTRHO_SAFE_ASSERT_RETURN(chandler != nullptr,); - -// const double value = vst3->plainParameterToNormalised(index, realValue); -// chandler->handler.perform_edit(handler, index, value); + DISTRHO_SAFE_ASSERT_RETURN(fController != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fHandler != nullptr,); - // TODO send change to DSP side? + const double value = v3_cpp_obj(fController)->plain_parameter_to_normalised(fController, rindex, realValue); + v3_cpp_obj(fHandler)->perform_edit(fHandler, rindex, value); } static void setParameterCallback(void* ptr, uint32_t rindex, float value) @@ -370,14 +371,22 @@ struct dpf_plugin_view : v3_plugin_view_cpp { ScopedPointer<dpf_plugin_view_scale> scale; ScopedPointer<UIVst3> uivst3; // cached values + v3_edit_controller** const controller; + v3_component_handler** const handler; void* const instancePointer; double sampleRate; // v3_component_handler_cpp** handler = nullptr; v3_plugin_frame** frame = nullptr; - dpf_plugin_view(ScopedPointer<dpf_plugin_view>* s, void* const instance, const double sr) + dpf_plugin_view(ScopedPointer<dpf_plugin_view>* selfptr, + v3_edit_controller** const controllerptr, + v3_component_handler** const handlerptr, + void* const instance, + const double sr) : refcounter(1), - self(s), + self(selfptr), + controller(controllerptr), + handler(handlerptr), instancePointer(instance), sampleRate(sr) { @@ -481,10 +490,14 @@ struct dpf_plugin_view : v3_plugin_view_cpp { if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0) { const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f; - view->uivst3 = new UIVst3((uintptr_t)parent, scaleFactor, view->sampleRate, - view->instancePointer, (v3_plugin_view**)self); + view->uivst3 = new UIVst3((v3_plugin_view**)self, + view->controller, + view->handler, + (uintptr_t)parent, + scaleFactor, + view->sampleRate, + view->instancePointer); view->uivst3->setFrame(view->frame); - // view->uivst3->setHandler(view->handler); return V3_OK; } } @@ -623,12 +636,14 @@ struct dpf_plugin_view : v3_plugin_view_cpp { // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_create (called from plugin side) -v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate); +v3_funknown** dpf_plugin_view_create(v3_edit_controller** controller, v3_component_handler** handler, + void* instancePointer, double sampleRate); -v3_funknown** dpf_plugin_view_create(void* const instancePointer, const double sampleRate) +v3_funknown** dpf_plugin_view_create(v3_edit_controller** const controller, v3_component_handler** const handler, + void* const instancePointer, const double sampleRate) { ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>; - *viewptr = new dpf_plugin_view(viewptr, instancePointer, sampleRate); + *viewptr = new dpf_plugin_view(viewptr, controller, handler, instancePointer, sampleRate); return (v3_funknown**)viewptr; } diff --git a/distrho/src/travesty/base.h b/distrho/src/travesty/base.h @@ -28,7 +28,11 @@ template<class T> static inline constexpr T* v3_cpp_obj(T** obj) { - return (T*)((uint8_t*)*obj + sizeof(void*)*3); + /** + * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, + * but we need everything to be `static_cast` for it to be `constexpr` compatible. + */ + return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3)); } #else # ifndef constexpr diff --git a/distrho/src/travesty/edit_controller.h b/distrho/src/travesty/edit_controller.h @@ -84,4 +84,17 @@ struct v3_edit_controller { static constexpr const v3_tuid v3_edit_controller_iid = V3_ID(0xDCD7BBE3, 0x7742448D, 0xA874AACC, 0x979C759E); +#ifdef __cplusplus +template<> inline +constexpr v3_edit_controller* v3_cpp_obj(v3_edit_controller** obj) +{ + /** + * this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, + * but we need everything to be `static_cast` for it to be `constexpr` compatible. + */ + return static_cast<v3_edit_controller*>( + static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*5)); +} +#endif + #include "align_pop.h"