commit ba550f42fd9f366e633bf0b979a99825791f44ee
parent da528328bf4e13004bfddf9b71e214a5bea97e95
Author: falkTX <falktx@falktx.com>
Date: Fri, 24 Sep 2021 23:22:15 +0100
VST3: Cleanup UI side, make it appear again
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
4 files changed, 747 insertions(+), 676 deletions(-)
diff --git a/distrho/DistrhoUIMain.cpp b/distrho/DistrhoUIMain.cpp
@@ -27,7 +27,7 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST2)
// nothing
#elif defined(DISTRHO_PLUGIN_TARGET_VST3)
-// nothing
+# include "src/DistrhoUIVST3.cpp"
#else
# error unsupported format
#endif
diff --git a/distrho/src/DISTRHOUIVST3.cpp b/distrho/src/DISTRHOUIVST3.cpp
@@ -1,666 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any purpose with
- * or without fee is hereby granted, provided that the above copyright notice and this
- * permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "DistrhoUIInternal.hpp"
-
-#include "travesty/audio_processor.h"
-#include "travesty/component.h"
-#include "travesty/edit_controller.h"
-#include "travesty/factory.h"
-#include "travesty/view.h"
-
-#include <atomic>
-
-// TESTING awful idea dont reuse
-#include "../extra/Thread.hpp"
-
-// #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
-// # undef DISTRHO_PLUGIN_HAS_UI
-// # define DISTRHO_PLUGIN_HAS_UI 0
-// #endif
-//
-// #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
-// # undef DISTRHO_PLUGIN_HAS_UI
-// # define DISTRHO_PLUGIN_HAS_UI 0
-// #endif
-//
-// #undef DISTRHO_PLUGIN_HAS_UI
-// #define DISTRHO_PLUGIN_HAS_UI 1
-
-// #if DISTRHO_PLUGIN_HAS_UI
-# include "DistrhoUIInternal.hpp"
-// #endif
-
-// --------------------------------------------------------------------------------------------------------------------
-
-struct v3_component_handler_cpp : v3_funknown {
- v3_component_handler handler;
-};
-
-START_NAMESPACE_DISTRHO
-
-// --------------------------------------------------------------------------------------------------------------------
-
-#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
-static const sendNoteFunc sendNoteCallback = nullptr;
-#endif
-#if ! DISTRHO_PLUGIN_WANT_STATE
-static const setStateFunc setStateCallback = nullptr;
-#endif
-
-// --------------------------------------------------------------------------------------------------------------------
-// custom v3_tuid compatible type
-
-typedef uint32_t dpf_tuid[4];
-static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch");
-
-// --------------------------------------------------------------------------------------------------------------------
-// Utility functions
-
-const char* tuid2str(const v3_tuid iid)
-{
- if (v3_tuid_match(iid, v3_funknown_iid))
- return "{v3_funknown}";
- if (v3_tuid_match(iid, v3_plugin_base_iid))
- return "{v3_plugin_base}";
- if (v3_tuid_match(iid, v3_plugin_factory_iid))
- return "{v3_plugin_factory}";
- if (v3_tuid_match(iid, v3_plugin_factory_2_iid))
- return "{v3_plugin_factory_2}";
- if (v3_tuid_match(iid, v3_plugin_factory_3_iid))
- return "{v3_plugin_factory_3}";
- if (v3_tuid_match(iid, v3_component_iid))
- return "{v3_component}";
- if (v3_tuid_match(iid, v3_bstream_iid))
- return "{v3_bstream}";
- if (v3_tuid_match(iid, v3_event_list_iid))
- return "{v3_event_list}";
- if (v3_tuid_match(iid, v3_param_value_queue_iid))
- return "{v3_param_value_queue}";
- if (v3_tuid_match(iid, v3_param_changes_iid))
- return "{v3_param_changes}";
- if (v3_tuid_match(iid, v3_process_context_requirements_iid))
- return "{v3_process_context_requirements}";
- if (v3_tuid_match(iid, v3_audio_processor_iid))
- return "{v3_audio_processor}";
- if (v3_tuid_match(iid, v3_component_handler_iid))
- return "{v3_component_handler}";
- if (v3_tuid_match(iid, v3_edit_controller_iid))
- return "{v3_edit_controller}";
- if (v3_tuid_match(iid, v3_plugin_view_iid))
- return "{v3_plugin_view}";
- if (v3_tuid_match(iid, v3_plugin_frame_iid))
- return "{v3_plugin_frame}";
- if (v3_tuid_match(iid, v3_plugin_view_content_scale_steinberg_iid))
- return "{v3_plugin_view_content_scale_steinberg}";
- if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid))
- return "{v3_plugin_view_parameter_finder}";
- /*
- if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0)
- return "{dpf_tuid_class}";
- if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0)
- return "{dpf_tuid_component}";
- if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0)
- return "{dpf_tuid_controller}";
- if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0)
- return "{dpf_tuid_processor}";
- if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0)
- return "{dpf_tuid_view}";
- */
-
- static char buf[46];
- std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}",
- (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
- (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]),
- (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]),
- (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15]));
- return buf;
-}
-
-// --------------------------------------------------------------------------------------------------------------------
-
-class UIVst3 : public Thread
-{
-public:
- UIVst3(const intptr_t winId, const float scaleFactor, const double sampleRate, void* const instancePointer)
- : fUI(this, winId, sampleRate,
- editParameterCallback,
- setParameterCallback,
- setStateCallback,
- sendNoteCallback,
- setSizeCallback,
- nullptr, // TODO file request
- nullptr,
- instancePointer,
- scaleFactor)
- {
- // TESTING awful idea dont reuse
- startThread();
- }
-
- ~UIVst3() override
- {
- stopThread(5000);
- }
-
- // -------------------------------------------------------------------
-
- // TESTING awful idea dont reuse
- void run() override
- {
- while (! shouldThreadExit())
- {
- idle();
- d_msleep(50);
- }
- }
-
- void idle()
- {
- /*
- for (uint32_t i=0, count = fPlugin->getParameterCount(); i < count; ++i)
- {
- if (fUiHelper->parameterChecks[i])
- {
- fUiHelper->parameterChecks[i] = false;
- fUI.parameterChanged(i, fUiHelper->parameterValues[i]);
- }
- }
- */
-
- fUI.plugin_idle();
- }
-
- int16_t getWidth() const
- {
- return fUI.getWidth();
- }
-
- int16_t getHeight() const
- {
- return fUI.getHeight();
- }
-
- double getScaleFactor() const
- {
- 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
-
- void setFrame(v3_plugin_frame* const f) noexcept
- {
- frame = f;
- }
-
- void setHandler(v3_component_handler_cpp** const h) noexcept
- {
- handler = h;
- }
-
- // ----------------------------------------------------------------------------------------------------------------
-
-protected:
- void editParameter(const uint32_t index, 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);
- }
-
- void setParameterValue(const uint32_t index, 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);
-
- // TODO send change to DSP side?
- }
-
- void setSize(uint width, uint height)
- {
-# ifdef DISTRHO_OS_MAC
- const double scaleFactor = fUI.getScaleFactor();
- width /= scaleFactor;
- height /= scaleFactor;
-# endif
- if (frame == nullptr)
- return;
-
- v3_view_rect rect = {};
- rect.right = width;
- rect.bottom = height;
- (void)rect;
- // frame->resize_view(nullptr, uivst3, &rect);
- }
-
-# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
- void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
- {
- uint8_t midiData[3];
- midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel;
- midiData[1] = note;
- midiData[2] = velocity;
- fNotesRingBuffer.writeCustomData(midiData, 3);
- fNotesRingBuffer.commitWrite();
- }
-# endif
-
-# if DISTRHO_PLUGIN_WANT_STATE
- void setState(const char* const key, const char* const value)
- {
- // fUiHelper->setStateFromUI(key, value);
- }
-# endif
-
-private:
- // VST3 stuff
- v3_plugin_frame* frame;
- v3_component_handler_cpp** handler = nullptr;
-
- // Plugin UI
- UIExporter fUI;
-
- // -------------------------------------------------------------------
- // Callbacks
-
- #define handlePtr ((UIVst3*)ptr)
-
- static void editParameterCallback(void* ptr, uint32_t index, bool started)
- {
- handlePtr->editParameter(index, started);
- }
-
- static void setParameterCallback(void* ptr, uint32_t rindex, float value)
- {
- handlePtr->setParameterValue(rindex, value);
- }
-
- static void setSizeCallback(void* ptr, uint width, uint height)
- {
- handlePtr->setSize(width, height);
- }
-
-# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
- static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
- {
- handlePtr->sendNote(channel, note, velocity);
- }
-# endif
-
-# if DISTRHO_PLUGIN_WANT_STATE
- static void setStateCallback(void* ptr, const char* key, const char* value)
- {
- handlePtr->setState(key, value);
- }
-# endif
-
- #undef handlePtr
-};
-
-// --------------------------------------------------------------------------------------------------------------------
-// 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
-
-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<UIVst3> uivst3;
- // cached values
- v3_component_handler_cpp** handler = nullptr;
- v3_plugin_frame* hostframe = nullptr;
-
- dpf_plugin_view(ScopedPointer<dpf_plugin_view>* s)
- : refcounter(1),
- self(s)
- {
- static const uint8_t* kSupportedInterfacesBase[] = {
- v3_funknown_iid,
- v3_plugin_view_iid
- };
-
- // ------------------------------------------------------------------------------------------------------------
- // v3_funknown
-
- 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);
-
- for (const uint8_t* interface_iid : kSupportedInterfacesBase)
- {
- 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;
- };
-
- ref = []V3_API(void* self) -> uint32_t
- {
- d_stdout("dpf_plugin_view::ref => %p", self);
- 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;
- };
-
- // ------------------------------------------------------------------------------------------------------------
- // v3_plugin_view
-
- 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);
- const char* const supported[] = {
-#ifdef _WIN32
- V3_VIEW_PLATFORM_TYPE_HWND,
-#elif defined(__APPLE__)
- V3_VIEW_PLATFORM_TYPE_NSVIEW,
-#else
- V3_VIEW_PLATFORM_TYPE_X11,
-#endif
- };
-
- for (size_t i=0; i<sizeof(supported)/sizeof(supported[0]); ++i)
- {
- if (std::strcmp(supported[i], platform_type))
- return V3_OK;
- }
-
- return V3_NOT_IMPLEMENTED;
- };
-
- view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result
- {
- 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_INITIALISED);
- DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG);
-
- 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;
- };
-
- view.removed = []V3_API(void* self) -> v3_result
- {
- 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_INITIALISED);
- DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG);
- view->uivst3 = nullptr;
- return V3_OK;
- };
-
- view.on_wheel = []V3_API(void* self, float distance) -> v3_result
- {
- 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);
- DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED);
- return V3_NOT_IMPLEMENTED;
- };
-
- 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);
- DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED);
- return V3_NOT_IMPLEMENTED;
- };
-
- 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);
- DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED);
- return V3_NOT_IMPLEMENTED;
- };
-
- 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);
-
- std::memset(rect, 0, sizeof(v3_view_rect));
-
- if (view->uivst3 != nullptr)
- {
- rect->right = view->uivst3->getWidth();
- rect->bottom = view->uivst3->getHeight();
-# ifdef DISTRHO_OS_MAC
- const double scaleFactor = view->uivst3->getScaleFactor();
- rect->right /= scaleFactor;
- rect->bottom /= scaleFactor;
-# endif
- }
- 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(), scaleFactor);
- rect->right = tmpUI.getWidth();
- rect->bottom = tmpUI.getHeight();
-# ifdef DISTRHO_OS_MAC
- const double scaleFactor = tmpUI.getScaleFactor();
- rect->right /= scaleFactor;
- rect->bottom /= scaleFactor;
-# endif
- tmpUI.quit();
- }
-
- return V3_NOT_IMPLEMENTED;
- };
-
- view.set_size = []V3_API(void* self, v3_view_rect*) -> v3_result
- {
- d_stdout("dpf_plugin_view::set_size => %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_NOT_INITIALISED);
- return V3_NOT_IMPLEMENTED;
- };
-
- 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);
- DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_NOT_INITIALISED);
- return V3_NOT_IMPLEMENTED;
- };
-
- view.set_frame = []V3_API(void* self, v3_plugin_frame* frame) -> v3_result
- {
- d_stdout("dpf_plugin_view::set_frame => %p", self);
- dpf_plugin_view* const view = *(dpf_plugin_view**)self;
- DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
-
- view->hostframe = frame;
-
- if (view->uivst3 != nullptr)
- view->uivst3->setFrame(frame);
-
- return V3_OK;
- };
-
- view.can_resize = []V3_API(void* self) -> v3_result
- {
- d_stdout("dpf_plugin_view::can_resize => %p", self);
-#if DISTRHO_UI_USER_RESIZABLE
- return V3_OK;
-#else
- return V3_NOT_IMPLEMENTED;
-#endif
- };
-
- view.check_size_constraint = []V3_API(void* self, v3_view_rect*) -> v3_result
- {
- d_stdout("dpf_plugin_view::check_size_constraint => %p", self);
- return V3_NOT_IMPLEMENTED;
- };
- }
-};
-
-// --------------------------------------------------------------------------------------------------------------------
-
-END_NAMESPACE_DISTRHO
diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp
@@ -291,6 +291,19 @@ public:
}
// ----------------------------------------------------------------------------------------------------------------
+ // stuff called for UI creation
+
+ void* getInstancePointer() const noexcept
+ {
+ return fPlugin.getInstancePointer();
+ }
+
+ double getSampleRate() const noexcept
+ {
+ return fPlugin.getSampleRate();
+ }
+
+ // ----------------------------------------------------------------------------------------------------------------
// v3_component interface calls
int32_t getBusCount(const int32_t mediaType, const int32_t busDirection) const noexcept
@@ -1127,6 +1140,7 @@ private:
TimePosition fTimePosition;
#endif
+#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
bool requestParameterValueChange(const uint32_t index, const float value)
{
DISTRHO_SAFE_ASSERT_RETURN(fComponentHandler != nullptr, false);
@@ -1142,7 +1156,6 @@ private:
return ret;
}
-#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
{
return ((PluginVst3*)ptr)->requestParameterValueChange(index, value);
@@ -1211,6 +1224,13 @@ private:
};
+#if DISTRHO_PLUGIN_HAS_UI
+// --------------------------------------------------------------------------------------------------------------------
+// dpf_plugin_view_create (called from DSP side)
+
+v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate);
+#endif
+
// --------------------------------------------------------------------------------------------------------------------
// dpf_edit_controller
@@ -1511,15 +1531,14 @@ struct dpf_edit_controller : v3_edit_controller_cpp {
dpf_edit_controller* const controller = *(dpf_edit_controller**)self;
DISTRHO_SAFE_ASSERT_RETURN(controller != nullptr, nullptr);
- return nullptr;
-
-// if (controller->view == nullptr)
-// {
-// controller->view = new dpf_plugin_view(&controller->view, controller->vst3);
-// controller->view->handler = controller->handler;
-// }
+ PluginVst3* const vst3 = controller->vst3;
+ DISTRHO_SAFE_ASSERT_RETURN(vst3 != nullptr, nullptr);
-// return (v3_plugin_view**)&controller->view;
+#if DISTRHO_PLUGIN_HAS_UI
+ return (v3_plugin_view**)dpf_plugin_view_create(vst3->getInstancePointer(), vst3->getSampleRate());
+#else
+ return nullptr;
+#endif
};
}
};
diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp
@@ -0,0 +1,718 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "DistrhoUIInternal.hpp"
+
+#include "travesty/audio_processor.h"
+#include "travesty/component.h"
+#include "travesty/edit_controller.h"
+#include "travesty/factory.h"
+#include "travesty/view.h"
+
+#include <atomic>
+
+// TESTING awful idea dont reuse
+#include "../extra/Thread.hpp"
+
+// #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
+// # undef DISTRHO_PLUGIN_HAS_UI
+// # define DISTRHO_PLUGIN_HAS_UI 0
+// #endif
+//
+// #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
+// # undef DISTRHO_PLUGIN_HAS_UI
+// # define DISTRHO_PLUGIN_HAS_UI 0
+// #endif
+//
+// #undef DISTRHO_PLUGIN_HAS_UI
+// #define DISTRHO_PLUGIN_HAS_UI 1
+
+// #if DISTRHO_PLUGIN_HAS_UI
+# include "DistrhoUIInternal.hpp"
+// #endif
+
+// --------------------------------------------------------------------------------------------------------------------
+
+struct v3_component_handler_cpp : v3_funknown {
+ v3_component_handler handler;
+};
+
+START_NAMESPACE_DISTRHO
+
+// --------------------------------------------------------------------------------------------------------------------
+
+#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
+static const sendNoteFunc sendNoteCallback = nullptr;
+#endif
+#if ! DISTRHO_PLUGIN_WANT_STATE
+static const setStateFunc setStateCallback = nullptr;
+#endif
+
+// --------------------------------------------------------------------------------------------------------------------
+// custom v3_tuid compatible type
+
+typedef uint32_t dpf_tuid[4];
+static_assert(sizeof(v3_tuid) == sizeof(dpf_tuid), "uid size mismatch");
+
+// --------------------------------------------------------------------------------------------------------------------
+// Utility functions
+
+const char* tuid2str(const v3_tuid iid)
+{
+ if (v3_tuid_match(iid, v3_funknown_iid))
+ return "{v3_funknown}";
+ if (v3_tuid_match(iid, v3_plugin_base_iid))
+ return "{v3_plugin_base}";
+ if (v3_tuid_match(iid, v3_plugin_factory_iid))
+ return "{v3_plugin_factory}";
+ if (v3_tuid_match(iid, v3_plugin_factory_2_iid))
+ return "{v3_plugin_factory_2}";
+ if (v3_tuid_match(iid, v3_plugin_factory_3_iid))
+ return "{v3_plugin_factory_3}";
+ if (v3_tuid_match(iid, v3_component_iid))
+ return "{v3_component}";
+ if (v3_tuid_match(iid, v3_bstream_iid))
+ return "{v3_bstream}";
+ if (v3_tuid_match(iid, v3_event_list_iid))
+ return "{v3_event_list}";
+ if (v3_tuid_match(iid, v3_param_value_queue_iid))
+ return "{v3_param_value_queue}";
+ if (v3_tuid_match(iid, v3_param_changes_iid))
+ return "{v3_param_changes}";
+ if (v3_tuid_match(iid, v3_process_context_requirements_iid))
+ return "{v3_process_context_requirements}";
+ if (v3_tuid_match(iid, v3_audio_processor_iid))
+ return "{v3_audio_processor}";
+ if (v3_tuid_match(iid, v3_component_handler_iid))
+ return "{v3_component_handler}";
+ if (v3_tuid_match(iid, v3_edit_controller_iid))
+ return "{v3_edit_controller}";
+ if (v3_tuid_match(iid, v3_plugin_view_iid))
+ return "{v3_plugin_view}";
+ if (v3_tuid_match(iid, v3_plugin_frame_iid))
+ return "{v3_plugin_frame}";
+ if (v3_tuid_match(iid, v3_plugin_view_content_scale_steinberg_iid))
+ return "{v3_plugin_view_content_scale_steinberg}";
+ if (v3_tuid_match(iid, v3_plugin_view_parameter_finder_iid))
+ return "{v3_plugin_view_parameter_finder}";
+ /*
+ if (std::memcmp(iid, dpf_tuid_class, sizeof(dpf_tuid)) == 0)
+ return "{dpf_tuid_class}";
+ if (std::memcmp(iid, dpf_tuid_component, sizeof(dpf_tuid)) == 0)
+ return "{dpf_tuid_component}";
+ if (std::memcmp(iid, dpf_tuid_controller, sizeof(dpf_tuid)) == 0)
+ return "{dpf_tuid_controller}";
+ if (std::memcmp(iid, dpf_tuid_processor, sizeof(dpf_tuid)) == 0)
+ return "{dpf_tuid_processor}";
+ if (std::memcmp(iid, dpf_tuid_view, sizeof(dpf_tuid)) == 0)
+ return "{dpf_tuid_view}";
+ */
+
+ static char buf[46];
+ std::snprintf(buf, sizeof(buf), "{0x%08X,0x%08X,0x%08X,0x%08X}",
+ (uint32_t)d_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
+ (uint32_t)d_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]),
+ (uint32_t)d_cconst(iid[ 8], iid[ 9], iid[10], iid[11]),
+ (uint32_t)d_cconst(iid[12], iid[13], iid[14], iid[15]));
+ return buf;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+class UIVst3 : public Thread
+{
+public:
+ UIVst3(const intptr_t winId, const float scaleFactor, const double sampleRate, void* const instancePointer)
+ : fUI(this, winId, sampleRate,
+ editParameterCallback,
+ setParameterCallback,
+ setStateCallback,
+ sendNoteCallback,
+ setSizeCallback,
+ nullptr, // TODO file request
+ nullptr,
+ instancePointer,
+ scaleFactor),
+ fFrame(nullptr),
+ fScaleFactor(scaleFactor)
+ {
+ // TESTING awful idea dont reuse
+ startThread();
+ }
+
+ ~UIVst3() override
+ {
+ stopThread(5000);
+ }
+
+ // TESTING awful idea dont reuse
+ void run() override
+ {
+ while (! shouldThreadExit())
+ {
+ fUI.plugin_idle();
+ d_msleep(50);
+ }
+ }
+
+// // TODO dont use this
+// void setParameterValueFromDSP(const uint32_t index, const float value)
+// {
+// fUI.parameterChanged(index, value);
+// }
+
+// void setHandler(v3_component_handler_cpp** const h) noexcept
+// {
+// handler = h;
+// }
+
+ // ----------------------------------------------------------------------------------------------------------------
+ // v3_plugin_view interface calls
+
+ v3_result onWheel(float /*distance*/)
+ {
+ // TODO
+ return V3_NOT_IMPLEMENTED;
+ };
+
+ v3_result onKeyDown(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/)
+ {
+ // TODO
+ return V3_NOT_IMPLEMENTED;
+ };
+
+ v3_result onKeyUp(int16_t /*key_char*/, int16_t /*key_code*/, int16_t /*modifiers*/)
+ {
+ // TODO
+ return V3_NOT_IMPLEMENTED;
+ };
+
+ v3_result getSize(v3_view_rect* const rect) const noexcept
+ {
+ std::memset(rect, 0, sizeof(v3_view_rect));
+
+ rect->right = fUI.getWidth();
+ rect->bottom = fUI.getHeight();
+#ifdef DISTRHO_OS_MAC
+ const double scaleFactor = fUI.getScaleFactor();
+ rect->right /= scaleFactor;
+ rect->bottom /= scaleFactor;
+#endif
+
+ return V3_OK;
+ }
+
+ v3_result setSize(v3_view_rect* const /*rect*/)
+ {
+ // TODO
+ return V3_NOT_IMPLEMENTED;
+ }
+
+ v3_result onFocus(const bool /*state*/)
+ {
+ // TODO
+ return V3_NOT_IMPLEMENTED;
+ }
+
+ v3_result setFrame(v3_plugin_frame* const frame) noexcept
+ {
+ fFrame = frame;
+ return V3_OK;
+ }
+
+ v3_result checkSizeConstraint(v3_view_rect* const /*rect*/)
+ {
+ // TODO
+ return V3_NOT_IMPLEMENTED;
+ }
+
+ // ----------------------------------------------------------------------------------------------------------------
+ // v3_plugin_view_content_scale_steinberg interface calls
+
+ v3_result setContentScaleFactor(const float factor)
+ {
+ if (d_isEqual(fScaleFactor, factor))
+ return V3_OK;
+
+ fScaleFactor = factor;
+ fUI.notifyScaleFactorChanged(factor);
+ return V3_OK;
+ }
+
+ // ----------------------------------------------------------------------------------------------------------------
+
+private:
+ // Plugin UI
+ UIExporter fUI;
+
+ // VST3 stuff
+ v3_plugin_frame* fFrame;
+ // v3_component_handler_cpp** handler = nullptr;
+
+ // Temporary data
+ float fScaleFactor;
+
+ void editParameter(const uint32_t /*index*/, 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);
+ }
+
+ static void editParameterCallback(void* ptr, uint32_t index, bool started)
+ {
+ ((UIVst3*)ptr)->editParameter(index, started);
+ }
+
+ void setParameterValue(const uint32_t /*index*/, 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);
+
+ // TODO send change to DSP side?
+ }
+
+ static void setParameterCallback(void* ptr, uint32_t rindex, float value)
+ {
+ ((UIVst3*)ptr)->setParameterValue(rindex, value);
+ }
+
+ void setSize(uint /*width*/, uint /*height*/)
+ {
+// #ifdef DISTRHO_OS_MAC
+// const double scaleFactor = fUI.getScaleFactor();
+// width /= scaleFactor;
+// height /= scaleFactor;
+// #endif
+// if (frame == nullptr)
+// return;
+//
+// v3_view_rect rect = {};
+// rect.right = width;
+// rect.bottom = height;
+// (void)rect;
+// // frame->resize_view(nullptr, uivst3, &rect);
+ }
+
+ static void setSizeCallback(void* ptr, uint width, uint height)
+ {
+ ((UIVst3*)ptr)->setSize(width, height);
+ }
+
+#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+ void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/)
+ {
+// uint8_t midiData[3];
+// midiData[0] = (velocity != 0 ? 0x90 : 0x80) | channel;
+// midiData[1] = note;
+// midiData[2] = velocity;
+// fNotesRingBuffer.writeCustomData(midiData, 3);
+// fNotesRingBuffer.commitWrite();
+ }
+
+ static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
+ {
+ ((UIVst3*)ptr)->sendNote(channel, note, velocity);
+ }
+#endif
+
+#if DISTRHO_PLUGIN_WANT_STATE
+ void setState(const char* const /*key*/, const char* const /*value*/)
+ {
+ // fUiHelper->setStateFromUI(key, value);
+ }
+
+ static void setStateCallback(void* ptr, const char* key, const char* value)
+ {
+ ((UIVst3*)ptr)->setState(key, value);
+ }
+#endif
+
+ #undef handlePtr
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// 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;
+ // cached values
+ float scaleFactor;
+
+ dpf_plugin_view_scale(ScopedPointer<dpf_plugin_view_scale>* s, ScopedPointer<UIVst3>& v)
+ : refcounter(1),
+ self(s),
+ uivst3(v),
+ scaleFactor(0.0f)
+ {
+ 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);
+
+ scale->scaleFactor = factor;
+
+ if (UIVst3* const uivst3 = scale->uivst3)
+ return uivst3->setContentScaleFactor(factor);
+
+ return V3_NOT_INITIALISED;
+ };
+ }
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// dpf_plugin_view
+
+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<UIVst3> uivst3;
+ // cached values
+ 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)
+ : refcounter(1),
+ self(s),
+ instancePointer(instance),
+ sampleRate(sr)
+ {
+ 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
+
+ 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);
+
+ for (const uint8_t* interface_iid : kSupportedInterfacesBase)
+ {
+ 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;
+ };
+
+ ref = []V3_API(void* self) -> uint32_t
+ {
+ d_stdout("dpf_plugin_view::ref => %p", self);
+ 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;
+ };
+
+ // ------------------------------------------------------------------------------------------------------------
+ // v3_plugin_view
+
+ 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);
+
+ for (size_t i=0; i<ARRAY_SIZE(kSupportedPlatforms); ++i)
+ {
+ if (std::strcmp(kSupportedPlatforms[i], platform_type) == 0)
+ return V3_OK;
+ }
+
+ return V3_NOT_IMPLEMENTED;
+ };
+
+ view.attached = []V3_API(void* self, void* parent, const char* platform_type) -> v3_result
+ {
+ 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_INITIALISED);
+ DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 == nullptr, V3_INVALID_ARG);
+
+ for (size_t i=0; i<ARRAY_SIZE(kSupportedPlatforms); ++i)
+ {
+ 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);
+ view->uivst3->setFrame(view->frame);
+ // view->uivst3->setHandler(view->handler);
+ return V3_OK;
+ }
+ }
+
+ return V3_NOT_IMPLEMENTED;
+ };
+
+ view.removed = []V3_API(void* self) -> v3_result
+ {
+ 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_INITIALISED);
+ DISTRHO_SAFE_ASSERT_RETURN(view->uivst3 != nullptr, V3_INVALID_ARG);
+ view->uivst3 = nullptr;
+ return V3_OK;
+ };
+
+ view.on_wheel = []V3_API(void* self, float distance) -> v3_result
+ {
+ 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);
+
+ UIVst3* const uivst3 = view->uivst3;
+ DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
+
+ return uivst3->onWheel(distance);
+ };
+
+ 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);
+
+ UIVst3* const uivst3 = view->uivst3;
+ DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
+
+ return uivst3->onKeyDown(key_char, key_code, modifiers);
+ };
+
+ 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);
+
+ UIVst3* const uivst3 = view->uivst3;
+ DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
+
+ return uivst3->onKeyUp(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);
+
+ // special case: allow UI to not be attached yet, as a way to get size before window creation
+
+ if (UIVst3* const uivst3 = view->uivst3)
+ return uivst3->getSize(rect);
+
+ const float scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0f;
+ const UIVst3 uivst3(0, scaleFactor, view->sampleRate, view->instancePointer);
+ return uivst3.getSize(rect);
+ };
+
+ view.set_size = []V3_API(void* self, v3_view_rect* rect) -> v3_result
+ {
+ d_stdout("dpf_plugin_view::set_size => %p %p", self, rect);
+ dpf_plugin_view* const view = *(dpf_plugin_view**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
+
+ UIVst3* const uivst3 = view->uivst3;
+ DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
+
+ return uivst3->setSize(rect);
+ };
+
+ 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);
+
+ UIVst3* const uivst3 = view->uivst3;
+ DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
+
+ return uivst3->onFocus(state);
+ };
+
+ view.set_frame = []V3_API(void* self, v3_plugin_frame* frame) -> v3_result
+ {
+ d_stdout("dpf_plugin_view::set_frame => %p %o", self, frame);
+ dpf_plugin_view* const view = *(dpf_plugin_view**)self;
+ DISTRHO_SAFE_ASSERT_RETURN(view != nullptr, V3_NOT_INITIALISED);
+
+ view->frame = frame;
+
+ if (UIVst3* const uivst3 = view->uivst3)
+ return uivst3->setFrame(frame);
+
+ return V3_NOT_INITIALISED;
+ };
+
+ view.can_resize = []V3_API(void* self) -> v3_result
+ {
+ d_stdout("dpf_plugin_view::can_resize => %p", self);
+#if DISTRHO_UI_USER_RESIZABLE
+ return V3_OK;
+#else
+ 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);
+
+ UIVst3* const uivst3 = view->uivst3;
+ DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALISED);
+
+ return uivst3->checkSizeConstraint(rect);
+ };
+ }
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// dpf_plugin_view_create (called from DSP side)
+
+v3_funknown** dpf_plugin_view_create(void* instancePointer, double sampleRate);
+
+v3_funknown** dpf_plugin_view_create(void* const instancePointer, const double sampleRate)
+{
+ ScopedPointer<dpf_plugin_view>* const viewptr = new ScopedPointer<dpf_plugin_view>;
+ *viewptr = new dpf_plugin_view(viewptr, instancePointer, sampleRate);
+ return (v3_funknown**)viewptr;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO