diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp index a48b20c5..017eb234 100644 --- a/distrho/src/DistrhoPluginInternal.hpp +++ b/distrho/src/DistrhoPluginInternal.hpp @@ -19,6 +19,10 @@ #include "../DistrhoPlugin.hpp" +#ifdef DISTRHO_PLUGIN_TARGET_VST3 +# include "DistrhoPluginVST3.hpp" +#endif + #include START_NAMESPACE_DISTRHO @@ -81,28 +85,6 @@ static void fillInPredefinedPortGroupData(const uint32_t groupId, PortGroup& por } } -// #ifdef DISTRHO_PLUGIN_TARGET_VST3 -enum Vst3InternalParameters { - kVst3InternalParameterActive = 0, - kVst3InternalParameterBufferSize, - kVst3InternalParameterSampleRate, -# if DISTRHO_PLUGIN_WANT_LATENCY - kVst3InternalParameterLatency, -# endif -# if DISTRHO_PLUGIN_WANT_PROGRAMS - kVst3InternalParameterProgram, -# endif - kVst3InternalParameterBaseCount, -# if DISTRHO_PLUGIN_WANT_MIDI_INPUT - kVst3InternalParameterMidiCC_start = kVst3InternalParameterBaseCount, - kVst3InternalParameterMidiCC_end = kVst3InternalParameterMidiCC_start + 130*16, - kVst3InternalParameterCount = kVst3InternalParameterMidiCC_end -# else - kVst3InternalParameterCount = kVst3InternalParameterBaseCount -# endif -}; -// #endif - // ----------------------------------------------------------------------- // Plugin private data diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp index 7464e1a6..924429d0 100644 --- a/distrho/src/DistrhoPluginVST3.cpp +++ b/distrho/src/DistrhoPluginVST3.cpp @@ -18,20 +18,6 @@ #include "../DistrhoPluginUtils.hpp" #include "../extra/ScopedPointer.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 - -#if DISTRHO_PLUGIN_HAS_UI == 1 && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS == 0 -# define DPF_VST3_USES_SEPARATE_CONTROLLER -#endif - #define DPF_VST3_MAX_BUFFER_SIZE 32768 #define DPF_VST3_MAX_SAMPLE_RATE 384000 #define DPF_VST3_MAX_LATENCY DPF_VST3_MAX_SAMPLE_RATE * 10 @@ -46,21 +32,6 @@ #include "travesty/factory.h" #include "travesty/host.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); } - operator int() volatile noexcept { return __atomic_load_n(&value, __ATOMIC_RELAXED); } - }; -} -#endif - #include #include #include @@ -71,8 +42,6 @@ namespace std { * - have parameter outputs host-provided UI working in at least 1 host * - parameter groups via unit ids * - test parameter changes from DSP (aka requestParameterValueChange) - * - how to hide parameter outputs? - * - how to hide program parameter? * - test receiving midi CC * - implement getParameterNormalized/setParameterNormalized for MIDI CC params ? * - fully implemented parameter stuff and verify @@ -241,190 +210,6 @@ const char* tuid2str(const v3_tuid iid) return buf; } -// -------------------------------------------------------------------------------------------------------------------- - -static bool strcmp_utf16(const int16_t* const str16, const char* const str8) -{ - size_t i = 0; - for (; str8[i] != '\0'; ++i) - { - const uint8_t char8 = static_cast(str8[i]); - - // skip non-ascii chars, unsupported - if (char8 >= 0x80) - return false; - - if (str16[i] != char8) - return false; - } - - return str16[i] == str8[i]; -} - -// -------------------------------------------------------------------------------------------------------------------- - -static size_t strlen_utf16(const int16_t* const str) -{ - size_t i = 0; - - while (str[i] != 0) - ++i; - - return i; -} - -// -------------------------------------------------------------------------------------------------------------------- - -static void strncpy(char* const dst, const char* const src, const size_t length) -{ - DISTRHO_SAFE_ASSERT_RETURN(length > 0,); - - if (const size_t len = std::min(std::strlen(src), length-1U)) - { - std::memcpy(dst, src, len); - dst[len] = '\0'; - } - else - { - dst[0] = '\0'; - } -} - -void strncpy_utf8(char* const dst, const int16_t* const src, const size_t length) -{ - DISTRHO_SAFE_ASSERT_RETURN(length > 0,); - - if (const size_t len = std::min(strlen_utf16(src), length-1U)) - { - for (size_t i=0; i= 0x80) - continue; - - dst[i] = src[i]; - } - dst[len] = 0; - } - else - { - dst[0] = 0; - } -} - -void strncpy_utf16(int16_t* const dst, const char* const src, const size_t length) -{ - DISTRHO_SAFE_ASSERT_RETURN(length > 0,); - - if (const size_t len = std::min(std::strlen(src), length-1U)) - { - for (size_t i=0; i= 0x80) - continue; - - dst[i] = src[i]; - } - dst[len] = 0; - } - else - { - dst[0] = 0; - } -} - -// -------------------------------------------------------------------------------------------------------------------- - -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 char* const format, const size_t size) -{ - DISTRHO_SAFE_ASSERT_RETURN(size > 0,); - - char* const tmpbuf = (char*)std::malloc(size); - DISTRHO_SAFE_ASSERT_RETURN(tmpbuf != nullptr,); - - std::snprintf(tmpbuf, size-1, format, value); - tmpbuf[size-1] = '\0'; - - strncpy_utf16(dst, tmpbuf, size); - std::free(tmpbuf); -} - -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 inline -void snprintf_i32_utf16(int16_t* const dst, const int value, const size_t size) -{ - return snprintf_utf16_t(dst, value, "%d", size); -} - -// -------------------------------------------------------------------------------------------------------------------- -// handy way to create a utf16 string from a utf8 one on the current function scope, used for message strings - -struct ScopedUTF16String { - int16_t* str; - ScopedUTF16String(const char* const s) noexcept; - ~ScopedUTF16String() noexcept; - operator const int16_t*() const noexcept; -}; - -// -------------------------------------------------------------------------------------------------------------------- - -ScopedUTF16String::ScopedUTF16String(const char* const s) noexcept - : str(nullptr) -{ - const size_t len = std::strlen(s); - str = static_cast(std::malloc(sizeof(int16_t) * (len + 1))); - DISTRHO_SAFE_ASSERT_RETURN(str != nullptr,); - strncpy_utf16(str, s, len + 1); -} - -ScopedUTF16String::~ScopedUTF16String() noexcept -{ - std::free(str); -} - -ScopedUTF16String::operator const int16_t*() const noexcept -{ - return str; -} - -// -------------------------------------------------------------------------------------------------------------------- -// handy way to create a utf8 string from a utf16 one on the current function scope - -struct ScopedUTF8String { - char str[128]; - - ScopedUTF8String(const int16_t* const s) noexcept - { - strncpy_utf8(str, s, 128); - } - - operator const char*() const noexcept - { - return str; - } -}; - // -------------------------------------------------------------------------------------------------------------------- // dpf_plugin_view_create (implemented on UI side) @@ -469,7 +254,7 @@ public: : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback), fComponentHandler(nullptr), #if DISTRHO_PLUGIN_HAS_UI -# ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +# if DPF_VST3_USES_SEPARATE_CONTROLLER fConnectionFromCompToCtrl(nullptr), # endif fConnectionFromCtrlToView(nullptr), @@ -563,9 +348,10 @@ public: { fCachedParameterValues = new float[extraParameterCount]; - fCachedParameterValues[kVst3InternalParameterActive] = 0.0f; + #if DPF_VST3_USES_SEPARATE_CONTROLLER fCachedParameterValues[kVst3InternalParameterBufferSize] = fPlugin.getBufferSize(); fCachedParameterValues[kVst3InternalParameterSampleRate] = fPlugin.getSampleRate(); + #endif #if DISTRHO_PLUGIN_WANT_LATENCY fCachedParameterValues[kVst3InternalParameterLatency] = fLastKnownLatency; #endif @@ -1243,11 +1029,13 @@ public: fPlugin.setSampleRate(setup->sample_rate, true); fPlugin.setBufferSize(setup->max_block_size, true); + #if DPF_VST3_USES_SEPARATE_CONTROLLER fCachedParameterValues[kVst3InternalParameterBufferSize] = setup->max_block_size; fParameterValuesChangedDuringProcessing[kVst3InternalParameterBufferSize] = true; fCachedParameterValues[kVst3InternalParameterSampleRate] = setup->sample_rate; fParameterValuesChangedDuringProcessing[kVst3InternalParameterSampleRate] = true; + #endif #if DISTRHO_PLUGIN_HAS_UI fParameterValueChangesForUI[kVst3InternalParameterSampleRate] = true; #endif @@ -1272,8 +1060,6 @@ public: fPlugin.deactivateIfNeeded(); } - fCachedParameterValues[kVst3InternalParameterActive] = processing ? 1.0f : 0.0f; - fParameterValuesChangedDuringProcessing[kVst3InternalParameterActive] = true; return V3_OK; } @@ -1608,12 +1394,7 @@ public: switch (rindex) { - case kVst3InternalParameterActive: - info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN; - info->step_count = 1; - strncpy_utf16(info->title, "Active", 128); - strncpy_utf16(info->short_title, "Active", 128); - return V3_OK; + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN; info->step_count = DPF_VST3_MAX_BUFFER_SIZE - 1; @@ -1627,6 +1408,7 @@ public: strncpy_utf16(info->short_title, "Sample Rate", 128); strncpy_utf16(info->units, "frames", 128); return V3_OK; + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN; @@ -1714,15 +1496,14 @@ public: switch (rindex) { - case kVst3InternalParameterActive: - strncpy_utf16(output, normalized > 0.5 ? "On" : "Off", 128); - return V3_OK; + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: snprintf_i32_utf16(output, static_cast(normalized * DPF_VST3_MAX_BUFFER_SIZE + 0.5), 128); return V3_OK; case kVst3InternalParameterSampleRate: snprintf_f32_utf16(output, std::round(normalized * DPF_VST3_MAX_SAMPLE_RATE), 128); return V3_OK; + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: snprintf_f32_utf16(output, std::round(normalized * DPF_VST3_MAX_LATENCY), 128); @@ -1783,15 +1564,14 @@ public: { switch (rindex) { - case kVst3InternalParameterActive: - *output = strcmp_utf16(input, "On") ? 1.0 : 0.0; - return V3_OK; + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: *output = static_cast(std::atoi(ScopedUTF8String(input))) / DPF_VST3_MAX_BUFFER_SIZE; return V3_OK; case kVst3InternalParameterSampleRate: *output = std::atof(ScopedUTF8String(input)) / DPF_VST3_MAX_SAMPLE_RATE; return V3_OK; + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: *output = std::atof(ScopedUTF8String(input)) / DPF_VST3_MAX_LATENCY; @@ -1852,12 +1632,12 @@ public: switch (rindex) { - case kVst3InternalParameterActive: - return normalized > 0.5 ? 1.0 : 0.0; + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: return std::round(normalized * DPF_VST3_MAX_BUFFER_SIZE); case kVst3InternalParameterSampleRate: return normalized * DPF_VST3_MAX_SAMPLE_RATE; + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: return normalized * DPF_VST3_MAX_LATENCY; @@ -1897,12 +1677,12 @@ public: { switch (rindex) { - case kVst3InternalParameterActive: - return plain; + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_BUFFER_SIZE)); case kVst3InternalParameterSampleRate: return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_SAMPLE_RATE)); + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_LATENCY)); @@ -1933,11 +1713,13 @@ public: return 0.0; #endif + #if DPF_VST3_USES_SEPARATE_CONTROLLER || DISTRHO_PLUGIN_WANT_LATENCY || DISTRHO_PLUGIN_WANT_PROGRAMS switch (rindex) { - case kVst3InternalParameterActive: + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: case kVst3InternalParameterSampleRate: + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: #endif @@ -1946,6 +1728,7 @@ public: #endif return plainParameterToNormalized(rindex, fCachedParameterValues[rindex]); } + #endif const uint32_t index = static_cast(rindex - kVst3InternalParameterCount); DISTRHO_SAFE_ASSERT_UINT2_RETURN(index < fParameterCount, index, fParameterCount, 0.0); @@ -1971,23 +1754,14 @@ public: switch (rindex) { - case kVst3InternalParameterActive: - if (fCachedParameterValues[rindex] > 0.5f) - { - if (! fPlugin.isActive()) - fPlugin.activate(); - } - else - { - fPlugin.deactivateIfNeeded(); - } - break; + #if DPF_VST3_USES_SEPARATE_CONTROLLER case kVst3InternalParameterBufferSize: fPlugin.setBufferSize(fCachedParameterValues[rindex], true); break; case kVst3InternalParameterSampleRate: fPlugin.setSampleRate(fCachedParameterValues[rindex], true); break; + #endif #if DISTRHO_PLUGIN_WANT_LATENCY case kVst3InternalParameterLatency: flags = V3_RESTART_LATENCY_CHANGED; @@ -2019,10 +1793,12 @@ public: return V3_OK; } + #if DPF_VST3_USES_SEPARATE_CONTROLLER const uint32_t index = static_cast(rindex - kVst3InternalParameterCount); DISTRHO_SAFE_ASSERT_UINT2_RETURN(index < fParameterCount, index, fParameterCount, V3_INVALID_ARG); setNormalizedPluginParameterValue(index, normalized); + #endif return V3_OK; } @@ -2036,7 +1812,7 @@ public: // ---------------------------------------------------------------------------------------------------------------- // v3_connection_point interface calls - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER void comp2ctrl_connect(v3_connection_point** const other) { fConnectionFromCompToCtrl = other; @@ -2230,7 +2006,7 @@ public: #if DISTRHO_PLUGIN_WANT_MIDI_INPUT if (std::strcmp(msgid, "midi") == 0) { - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER DISTRHO_SAFE_ASSERT_RETURN(fConnectionFromCompToCtrl != nullptr, V3_INTERNAL_ERR); return v3_cpp_obj(fConnectionFromCompToCtrl)->notify(fConnectionFromCompToCtrl, message); #else @@ -2242,7 +2018,7 @@ public: #if DISTRHO_PLUGIN_WANT_STATE if (std::strcmp(msgid, "state-set") == 0) { - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER DISTRHO_SAFE_ASSERT_RETURN(fConnectionFromCompToCtrl != nullptr, V3_INTERNAL_ERR); return v3_cpp_obj(fConnectionFromCompToCtrl)->notify(fConnectionFromCompToCtrl, message); #else @@ -2352,7 +2128,7 @@ private: // VST3 stuff v3_component_handler** fComponentHandler; #if DISTRHO_PLUGIN_HAS_UI - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER v3_connection_point** fConnectionFromCompToCtrl; #endif v3_connection_point** fConnectionFromCtrlToView; @@ -2401,7 +2177,8 @@ private: v3_param_id paramId; float curValue; - for (v3_param_id i=kVst3InternalParameterActive; i<=kVst3InternalParameterSampleRate; ++i) + #if DPF_VST3_USES_SEPARATE_CONTROLLER + for (v3_param_id i=kVst3InternalParameterBufferSize; i<=kVst3InternalParameterSampleRate; ++i) { if (! fParameterValuesChangedDuringProcessing[i]) continue; @@ -2410,6 +2187,7 @@ private: fParameterValuesChangedDuringProcessing[i] = false; addParameterDataToHostOutputEvents(outparamsptr, i, curValue); } + #endif for (uint32_t i=0; i connectionCtrl2View; #endif -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER ScopedPointer connectionComp2Ctrl; ScopedPointer vst3; #else @@ -2961,12 +2739,12 @@ struct dpf_edit_controller : v3_edit_controller_cpp { // cached values v3_component_handler** handler; v3_host_application** const hostApplicationFromFactory; -#ifndef DPF_VST3_USES_SEPARATE_CONTROLLER +#if !DPF_VST3_USES_SEPARATE_CONTROLLER v3_host_application** const hostApplicationFromComponent; #endif v3_host_application** hostApplicationFromInitialize; -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER dpf_edit_controller(v3_host_application** const hostApp) : refcounter(1), vst3(nullptr), @@ -2978,7 +2756,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { #endif handler(nullptr), hostApplicationFromFactory(hostApp), -#ifndef DPF_VST3_USES_SEPARATE_CONTROLLER +#if !DPF_VST3_USES_SEPARATE_CONTROLLER hostApplicationFromComponent(hostComp), #endif hostApplicationFromInitialize(nullptr) @@ -2988,7 +2766,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { // make sure host application is valid through out this controller lifetime if (hostApplicationFromFactory != nullptr) v3_cpp_obj_ref(hostApplicationFromFactory); -#ifndef DPF_VST3_USES_SEPARATE_CONTROLLER +#if !DPF_VST3_USES_SEPARATE_CONTROLLER if (hostApplicationFromComponent != nullptr) v3_cpp_obj_ref(hostApplicationFromComponent); #endif @@ -3024,12 +2802,12 @@ struct dpf_edit_controller : v3_edit_controller_cpp { #if DISTRHO_PLUGIN_HAS_UI connectionCtrl2View = nullptr; #endif -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER connectionComp2Ctrl = nullptr; vst3 = nullptr; #endif -#ifndef DPF_VST3_USES_SEPARATE_CONTROLLER +#if !DPF_VST3_USES_SEPARATE_CONTROLLER if (hostApplicationFromComponent != nullptr) v3_cpp_obj_unref(hostApplicationFromComponent); #endif @@ -3065,7 +2843,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { } #endif -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER if (v3_tuid_match(iid, v3_connection_point_iid)) { d_stdout("query_interface_edit_controller => %p %s %p | OK convert %p", @@ -3105,7 +2883,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { return refcount; } -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER /** * Some hosts will have unclean instances of a few of the controller child classes at this point. * We check for those here, going through the whole possible chain to see if it is safe to delete. @@ -3144,7 +2922,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { dpf_edit_controller* const controller = *static_cast(self); // check if already initialized -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER DISTRHO_SAFE_ASSERT_RETURN(controller->vst3 == nullptr, V3_INVALID_ARG); #else DISTRHO_SAFE_ASSERT_RETURN(! controller->initialized, V3_INVALID_ARG); @@ -3160,7 +2938,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { // save it for later so we can unref it controller->hostApplicationFromInitialize = hostApplication; -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER // provide the factory application to the plugin if this new one is missing if (hostApplication == nullptr) hostApplication = controller->hostApplicationFromFactory; @@ -3195,7 +2973,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { d_stdout("dpf_edit_controller::terminate => %p", self); dpf_edit_controller* const controller = *static_cast(self); -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER // check if already terminated DISTRHO_SAFE_ASSERT_RETURN(controller->vst3 != nullptr, V3_INVALID_ARG); @@ -3226,7 +3004,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { { d_stdout("dpf_edit_controller::set_component_state => %p %p", self, stream); -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER dpf_edit_controller* const controller = *static_cast(self); PluginVst3* const vst3 = controller->vst3; @@ -3246,7 +3024,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { { d_stdout("dpf_edit_controller::set_state => %p %p", self, stream); -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER dpf_edit_controller* const controller = *static_cast(self); DISTRHO_SAFE_ASSERT_RETURN(controller->vst3 != nullptr, V3_NOT_INITIALIZED); #endif @@ -3262,7 +3040,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { { d_stdout("dpf_edit_controller::get_state => %p %p", self, stream); -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER dpf_edit_controller* const controller = *static_cast(self); DISTRHO_SAFE_ASSERT_RETURN(controller->vst3 != nullptr, V3_NOT_INITIALIZED); #endif @@ -3396,7 +3174,7 @@ struct dpf_edit_controller : v3_edit_controller_cpp { // we require a host application for message creation v3_host_application** const host = controller->hostApplicationFromInitialize != nullptr ? controller->hostApplicationFromInitialize -#ifndef DPF_VST3_USES_SEPARATE_CONTROLLER +#if !DPF_VST3_USES_SEPARATE_CONTROLLER : controller->hostApplicationFromComponent != nullptr ? controller->hostApplicationFromComponent #endif @@ -3646,7 +3424,7 @@ struct dpf_audio_processor : v3_audio_processor_cpp { struct dpf_component : v3_component_cpp { std::atomic_int refcounter; ScopedPointer processor; -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER ScopedPointer connectionComp2Ctrl; #else ScopedPointer controller; @@ -3691,7 +3469,7 @@ struct dpf_component : v3_component_cpp { { d_stdout("~dpf_component()"); processor = nullptr; -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER connectionComp2Ctrl = nullptr; #else controller = nullptr; @@ -3743,7 +3521,7 @@ struct dpf_component : v3_component_cpp { return V3_OK; } -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER if (v3_tuid_match(iid, v3_connection_point_iid)) { d_stdout("query_interface_component => %p %s %p | OK convert %p", @@ -3815,7 +3593,7 @@ struct dpf_component : v3_component_cpp { } } -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER if (dpf_comp2ctrl_connection_point* const point = component->connectionComp2Ctrl) { if (const int refcount = point->refcounter) @@ -3880,7 +3658,7 @@ struct dpf_component : v3_component_cpp { // create the actual plugin component->vst3 = new PluginVst3(hostApplication); - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER // set connection point if needed if (dpf_comp2ctrl_connection_point* const point = component->connectionComp2Ctrl) { @@ -4133,7 +3911,7 @@ struct dpf_factory : v3_plugin_factory_cpp { if (hostContext != nullptr) v3_cpp_obj_unref(hostContext); - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER if (gControllerGarbage.size() != 0) { d_stdout("DPF notice: cleaning up previously undeleted controllers now"); @@ -4271,7 +4049,7 @@ struct dpf_factory : v3_plugin_factory_cpp { return V3_OK; } - #ifdef DPF_VST3_USES_SEPARATE_CONTROLLER + #if DPF_VST3_USES_SEPARATE_CONTROLLER // create edit controller if (v3_tuid_match(class_id, *(const v3_tuid*)&dpf_tuid_controller) && v3_tuid_match(iid, v3_edit_controller_iid)) { @@ -4299,8 +4077,7 @@ struct dpf_factory : v3_plugin_factory_cpp { DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_INVALID_ARG); info->cardinality = 0x7FFFFFFF; - // TODO FIXME -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER || !DISTRHO_PLUGIN_HAS_UI info->class_flags = V3_DISTRIBUTABLE; #endif std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); @@ -4323,8 +4100,7 @@ struct dpf_factory : v3_plugin_factory_cpp { DISTRHO_SAFE_ASSERT_RETURN(idx == 0, V3_INVALID_ARG); info->cardinality = 0x7FFFFFFF; - // TODO FIXME -#ifdef DPF_VST3_USES_SEPARATE_CONTROLLER +#if DPF_VST3_USES_SEPARATE_CONTROLLER || !DISTRHO_PLUGIN_HAS_UI info->class_flags = V3_DISTRIBUTABLE; #endif std::memcpy(info->class_id, dpf_tuid_class, sizeof(v3_tuid)); diff --git a/distrho/src/DistrhoPluginVST3.hpp b/distrho/src/DistrhoPluginVST3.hpp new file mode 100644 index 00000000..ca0b6735 --- /dev/null +++ b/distrho/src/DistrhoPluginVST3.hpp @@ -0,0 +1,275 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2021 Filipe Coelho + * + * 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. + */ + +#ifndef DISTRHO_PLUGIN_VST3_HPP_INCLUDED +#define DISTRHO_PLUGIN_VST3_HPP_INCLUDED + +#include "DistrhoPluginChecks.h" +#include "../DistrhoUtils.hpp" + +#include +#include + +#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 + +#if DISTRHO_PLUGIN_HAS_UI == 1 && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS == 0 +# define DPF_VST3_USES_SEPARATE_CONTROLLER 1 +#else +# define DPF_VST3_USES_SEPARATE_CONTROLLER 0 +#endif + +// -------------------------------------------------------------------------------------------------------------------- + +#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 + +// -------------------------------------------------------------------------------------------------------------------- + +START_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- + +enum Vst3InternalParameters { +#if DPF_VST3_USES_SEPARATE_CONTROLLER + kVst3InternalParameterBufferSize, + kVst3InternalParameterSampleRate, +#endif +#if DISTRHO_PLUGIN_WANT_LATENCY + kVst3InternalParameterLatency, +#endif +#if DISTRHO_PLUGIN_WANT_PROGRAMS + kVst3InternalParameterProgram, +#endif + kVst3InternalParameterBaseCount, +#if DISTRHO_PLUGIN_WANT_MIDI_INPUT + kVst3InternalParameterMidiCC_start = kVst3InternalParameterBaseCount, + kVst3InternalParameterMidiCC_end = kVst3InternalParameterMidiCC_start + 130*16, + kVst3InternalParameterCount = kVst3InternalParameterMidiCC_end +#else + kVst3InternalParameterCount = kVst3InternalParameterBaseCount +#endif +}; + +// -------------------------------------------------------------------------------------------------------------------- + +static inline +bool strcmp_utf16(const int16_t* const str16, const char* const str8) +{ + size_t i = 0; + for (; str8[i] != '\0'; ++i) + { + const uint8_t char8 = static_cast(str8[i]); + + // skip non-ascii chars, unsupported + if (char8 >= 0x80) + return false; + + if (str16[i] != char8) + return false; + } + + return str16[i] == str8[i]; +} + +// -------------------------------------------------------------------------------------------------------------------- + +static inline +size_t strlen_utf16(const int16_t* const str) +{ + size_t i = 0; + + while (str[i] != 0) + ++i; + + return i; +} + +// -------------------------------------------------------------------------------------------------------------------- + +static inline +void strncpy(char* const dst, const char* const src, const size_t length) +{ + DISTRHO_SAFE_ASSERT_RETURN(length > 0,); + + if (const size_t len = std::min(std::strlen(src), length-1U)) + { + std::memcpy(dst, src, len); + dst[len] = '\0'; + } + else + { + dst[0] = '\0'; + } +} + +static inline +void strncpy_utf8(char* const dst, const int16_t* const src, const size_t length) +{ + DISTRHO_SAFE_ASSERT_RETURN(length > 0,); + + if (const size_t len = std::min(strlen_utf16(src), length-1U)) + { + for (size_t i=0; i= 0x80) + continue; + + dst[i] = src[i]; + } + dst[len] = 0; + } + else + { + dst[0] = 0; + } +} + +static inline +void strncpy_utf16(int16_t* const dst, const char* const src, const size_t length) +{ + DISTRHO_SAFE_ASSERT_RETURN(length > 0,); + + if (const size_t len = std::min(std::strlen(src), length-1U)) + { + for (size_t i=0; i= 0x80) + continue; + + dst[i] = src[i]; + } + dst[len] = 0; + } + else + { + dst[0] = 0; + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +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 char* const format, const size_t size) +{ + DISTRHO_SAFE_ASSERT_RETURN(size > 0,); + + char* const tmpbuf = (char*)std::malloc(size); + DISTRHO_SAFE_ASSERT_RETURN(tmpbuf != nullptr,); + + std::snprintf(tmpbuf, size-1, format, value); + tmpbuf[size-1] = '\0'; + + strncpy_utf16(dst, tmpbuf, size); + std::free(tmpbuf); +} + +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 inline +void snprintf_i32_utf16(int16_t* const dst, const int value, const size_t size) +{ + return snprintf_utf16_t(dst, value, "%d", size); +} + +// -------------------------------------------------------------------------------------------------------------------- +// handy way to create a utf16 string from a utf8 one on the current function scope, used for message strings + +struct ScopedUTF16String { + int16_t* str; + ScopedUTF16String(const char* const s) noexcept + : str(nullptr) + { + const size_t len = std::strlen(s); + str = static_cast(std::malloc(sizeof(int16_t) * (len + 1))); + DISTRHO_SAFE_ASSERT_RETURN(str != nullptr,); + strncpy_utf16(str, s, len + 1); + } + + ~ScopedUTF16String() noexcept + { + std::free(str); + } + + operator const int16_t*() const noexcept + { + return str; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- +// handy way to create a utf8 string from a utf16 one on the current function scope (limited to 128 chars) + +struct ScopedUTF8String { + char str[128]; + + ScopedUTF8String(const int16_t* const s) noexcept + { + strncpy_utf8(str, s, 128); + } + + operator const char*() const noexcept + { + return str; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- + +#endif // DISTRHO_PLUGIN_VST3_HPP_INCLUDED diff --git a/distrho/src/DistrhoUIPrivateData.hpp b/distrho/src/DistrhoUIPrivateData.hpp index d03ab16e..378c15d4 100644 --- a/distrho/src/DistrhoUIPrivateData.hpp +++ b/distrho/src/DistrhoUIPrivateData.hpp @@ -19,6 +19,10 @@ #include "../DistrhoUI.hpp" +#ifdef DISTRHO_PLUGIN_TARGET_VST3 +# include "DistrhoPluginVST3.hpp" +#endif + #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI # include "../extra/Sleep.hpp" #else @@ -294,28 +298,6 @@ typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8 typedef void (*setSizeFunc) (void* ptr, uint width, uint height); typedef bool (*fileRequestFunc) (void* ptr, const char* key); -#if defined(DISTRHO_PLUGIN_TARGET_VST3) && !defined(DISTRHO_PLUGIN_INTERNAL_HPP_INCLUDED) -enum Vst3InternalParameters { - kVst3InternalParameterActive = 0, - kVst3InternalParameterBufferSize, - kVst3InternalParameterSampleRate, -# if DISTRHO_PLUGIN_WANT_LATENCY - kVst3InternalParameterLatency, -# endif -# if DISTRHO_PLUGIN_WANT_PROGRAMS - kVst3InternalParameterProgram, -# endif - kVst3InternalParameterBaseCount, -# if DISTRHO_PLUGIN_WANT_MIDI_INPUT - kVst3InternalParameterMidiCC_start = kVst3InternalParameterBaseCount, - kVst3InternalParameterMidiCC_end = kVst3InternalParameterMidiCC_start + 130*16, - kVst3InternalParameterCount = kVst3InternalParameterMidiCC_end -# else - kVst3InternalParameterCount = kVst3InternalParameterBaseCount -# endif -}; -#endif - // ----------------------------------------------------------------------- // UI private data diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp index c7de0a69..53873d47 100644 --- a/distrho/src/DistrhoUIVST3.cpp +++ b/distrho/src/DistrhoUIVST3.cpp @@ -21,21 +21,6 @@ #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); } - operator int() volatile noexcept { return __atomic_load_n(&value, __ATOMIC_RELAXED); } - }; -}; -#endif - /* TODO items: * - mousewheel event * - key down/up events @@ -66,14 +51,6 @@ static constexpr const setStateFunc setStateCallback = nullptr; // Utility functions (defined on plugin side) const char* tuid2str(const v3_tuid iid); -void strncpy_utf16(int16_t* dst, const char* src, size_t length); - -struct ScopedUTF16String { - int16_t* str; - ScopedUTF16String(const char* const s) noexcept; - ~ScopedUTF16String() noexcept; - operator const int16_t*() const noexcept; -}; // -------------------------------------------------------------------------------------------------------------------- diff --git a/examples/CVPort/Makefile b/examples/CVPort/Makefile index 5833735e..c41d7cdc 100644 --- a/examples/CVPort/Makefile +++ b/examples/CVPort/Makefile @@ -23,8 +23,7 @@ include ../../Makefile.plugins.mk # -------------------------------------------------------------- # Enable all possible plugin types -TARGETS += jack -TARGETS += lv2_dsp +TARGETS = jack lv2_dsp vst3 all: $(TARGETS)