diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e57a111..6f92d617 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,10 +13,9 @@ jobs: strategy: matrix: os: - # wrong use of AU MIDIPacket - # - macos-12 - # - macos-13 - # - macos-14 + - macos-13 + - macos-14 + - macos-15 # webgui failure # - ubuntu-20.04 - ubuntu-22.04 diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 4202a693..5bdbbced 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -42,11 +42,11 @@ jobs: suffix: _24_04 target: ${{ matrix.target }} - macos-12: + macos-13: strategy: matrix: target: [macos-intel, macos-universal, macos-10.15] - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v4 with: @@ -54,14 +54,14 @@ jobs: - uses: distrho/dpf-cmake-action@v1 with: dpf_path: . - suffix: _12 + suffix: _13 target: ${{ matrix.target }} - macos-13: + macos-14: strategy: matrix: target: [macos-intel, macos-universal, macos-10.15] - runs-on: macos-13 + runs-on: macos-14 steps: - uses: actions/checkout@v4 with: @@ -69,14 +69,14 @@ jobs: - uses: distrho/dpf-cmake-action@v1 with: dpf_path: . - suffix: _13 + suffix: _14 target: ${{ matrix.target }} - macos-14: + macos-15: strategy: matrix: target: [macos-intel, macos-universal, macos-10.15] - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 with: @@ -84,7 +84,7 @@ jobs: - uses: distrho/dpf-cmake-action@v1 with: dpf_path: . - suffix: _14 + suffix: _15 target: ${{ matrix.target }} cmake_win32: diff --git a/.github/workflows/example-plugins.yml b/.github/workflows/example-plugins.yml index 8ac77fcc..86bd43e0 100644 --- a/.github/workflows/example-plugins.yml +++ b/.github/workflows/example-plugins.yml @@ -39,11 +39,11 @@ jobs: suffix: _24_04 target: ${{ matrix.target }} - macos-12: + macos-13: strategy: matrix: target: [macos-intel, macos-universal, macos-10.15] - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v4 with: @@ -51,14 +51,14 @@ jobs: - uses: distrho/dpf-makefile-action@v1 with: dpf_path: . - suffix: _12 + suffix: _13 target: ${{ matrix.target }} - macos-13: + macos-14: strategy: matrix: target: [macos-intel, macos-universal, macos-10.15] - runs-on: macos-13 + runs-on: macos-14 steps: - uses: actions/checkout@v4 with: @@ -66,14 +66,14 @@ jobs: - uses: distrho/dpf-makefile-action@v1 with: dpf_path: . - suffix: _13 + suffix: _14 target: ${{ matrix.target }} - macos-14: + macos-15: strategy: matrix: target: [macos-intel, macos-universal, macos-10.15] - runs-on: macos-14 + runs-on: macos-15 steps: - uses: actions/checkout@v4 with: @@ -81,5 +81,5 @@ jobs: - uses: distrho/dpf-makefile-action@v1 with: dpf_path: . - suffix: _14 + suffix: _15 target: ${{ matrix.target }} diff --git a/README.md b/README.md index 18b71158..e3a2bcba 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/is Online documentation is available at [https://distrho.github.io/DPF/](https://distrho.github.io/DPF/). -Online help and discussion about DPF happens in the [kx.studio chat, DPF room](https://chat.kx.studio/channel/dpf). +Online help and discussion about DPF happens in the [DPF github discussions](https://github.com/DISTRHO/DPF/discussions). ## List of plugins made with DPF: diff --git a/cmake/DPF-plugin.cmake b/cmake/DPF-plugin.cmake index 38976d3a..d22dea7e 100644 --- a/cmake/DPF-plugin.cmake +++ b/cmake/DPF-plugin.cmake @@ -493,10 +493,8 @@ function(dpf__determine_vst3_package_architecture OUTPUT_VARIABLE) else() set(vst3_package_arch "i386") endif() - elseif(vst3_system_arch MATCHES "^(armv[3-8][a-z]*|ppc(64)?(le)?)$") + elseif(vst3_system_arch MATCHES "^(armv[3-9][a-z]*|aarch64|loongarch64|ppc(64)?(le)?)$") set(vst3_package_arch "${vst3_system_arch}") - elseif(vst3_system_arch MATCHES "^(aarch64)$") - set(vst3_package_arch "aarch64") else() message(FATAL_ERROR "We don't know this architecture for VST3: ${vst3_system_arch}.") endif() diff --git a/dgl/EventHandlers.hpp b/dgl/EventHandlers.hpp index 443fa8d2..450ff4e2 100644 --- a/dgl/EventHandlers.hpp +++ b/dgl/EventHandlers.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2024 Filipe Coelho + * Copyright (C) 2012-2025 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 @@ -63,6 +63,9 @@ public: bool isCheckable() const noexcept; void setCheckable(bool checkable) noexcept; + bool isEnabled() const noexcept; + void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; + Point getLastClickPosition() const noexcept; Point getLastMotionPosition() const noexcept; @@ -121,6 +124,9 @@ public: KnobEventHandler& operator=(const KnobEventHandler& other); virtual ~KnobEventHandler(); + bool isEnabled() const noexcept; + void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; + // if setStep(1) has been called before, this returns true bool isInteger() const noexcept; diff --git a/dgl/src/EventHandlers.cpp b/dgl/src/EventHandlers.cpp index a2721d2c..d3b6cd3e 100644 --- a/dgl/src/EventHandlers.cpp +++ b/dgl/src/EventHandlers.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2024 Filipe Coelho + * Copyright (C) 2012-2025 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 @@ -31,6 +31,8 @@ struct ButtonEventHandler::PrivateData { int state; bool checkable; bool checked; + bool enabled; + bool enabledInput; Point lastClickPos; Point lastMotionPos; @@ -44,11 +46,16 @@ struct ButtonEventHandler::PrivateData { state(kButtonStateDefault), checkable(false), checked(false), + enabled(true), + enabledInput(true), lastClickPos(0, 0), lastMotionPos(0, 0) {} bool mouseEvent(const Widget::MouseEvent& ev) { + if (! enabledInput) + return false; + lastClickPos = ev.pos; // button was released, handle it now @@ -98,6 +105,9 @@ struct ButtonEventHandler::PrivateData { bool motionEvent(const Widget::MotionEvent& ev) { + if (! enabledInput) + return false; + // keep pressed if (button != -1) { @@ -171,6 +181,27 @@ struct ButtonEventHandler::PrivateData { } } + void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept + { + if (appliesToEventInput) + enabledInput = enabled2; + + if (enabled == enabled2) + return; + + // reset temp vars if disabling + if (! enabled2) + { + button = -1; + state = kButtonStateDefault; + lastClickPos = Point(); + lastMotionPos = Point(); + } + + enabled = enabled2; + widget->repaint(); + } + DISTRHO_DECLARE_NON_COPYABLE(PrivateData) }; @@ -217,6 +248,16 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept pData->checkable = checkable; } +bool ButtonEventHandler::isEnabled() const noexcept +{ + return pData->enabled; +} + +void ButtonEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept +{ + pData->setEnabled(enabled, appliesToEventInput); +} + Point ButtonEventHandler::getLastClickPosition() const noexcept { return pData->lastClickPos; @@ -281,6 +322,8 @@ struct KnobEventHandler::PrivateData { float value; float valueDef; float valueTmp; + bool enabled; + bool enabledInput; bool usingDefault; bool usingLog; Orientation orientation; @@ -301,6 +344,8 @@ struct KnobEventHandler::PrivateData { value(0.5f), valueDef(value), valueTmp(value), + enabled(true), + enabledInput(true), usingDefault(false), usingLog(false), orientation(Vertical), @@ -320,6 +365,8 @@ struct KnobEventHandler::PrivateData { value(other->value), valueDef(other->valueDef), valueTmp(value), + enabled(other->enabled), + enabledInput(other->enabledInput), usingDefault(other->usingDefault), usingLog(other->usingLog), orientation(other->orientation), @@ -338,6 +385,8 @@ struct KnobEventHandler::PrivateData { value = other->value; valueDef = other->valueDef; valueTmp = value; + enabled = other->enabled; + enabledInput = other->enabledInput; usingDefault = other->usingDefault; usingLog = other->usingLog; orientation = other->orientation; @@ -363,6 +412,9 @@ struct KnobEventHandler::PrivateData { bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor) { + if (! enabledInput) + return false; + if (ev.button != 1) return false; @@ -416,6 +468,9 @@ struct KnobEventHandler::PrivateData { bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor) { + if (! enabledInput) + return false; + if ((state & kKnobStateDragging) == 0x0) return false; @@ -501,6 +556,9 @@ struct KnobEventHandler::PrivateData { bool scrollEvent(const Widget::ScrollEvent& ev) { + if (! enabledInput) + return false; + if (! widget->contains(ev.pos)) return false; @@ -541,6 +599,28 @@ struct KnobEventHandler::PrivateData { return ((usingLog ? invlogscale(value) : value) - minimum) / diff; } + void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept + { + if (appliesToEventInput) + enabledInput = enabled2; + + if (enabled == enabled2) + return; + + // reset temp vars if disabling + if (! enabled2) + { + state = kKnobStateDefault; + lastX = 0.0; + lastY = 0.0; + lastClickTime = 0; + valueTmp = value; + } + + enabled = enabled2; + widget->repaint(); + } + void setRange(const float min, const float max) noexcept { DISTRHO_SAFE_ASSERT_RETURN(max > min,); @@ -598,6 +678,16 @@ KnobEventHandler::~KnobEventHandler() delete pData; } +bool KnobEventHandler::isEnabled() const noexcept +{ + return pData->enabled; +} + +void KnobEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept +{ + pData->setEnabled(enabled, appliesToEventInput); +} + bool KnobEventHandler::isInteger() const noexcept { return d_isEqual(pData->step, 1.f); diff --git a/dgl/src/WindowPrivateData.cpp b/dgl/src/WindowPrivateData.cpp index a2afec6b..3644bc49 100644 --- a/dgl/src/WindowPrivateData.cpp +++ b/dgl/src/WindowPrivateData.cpp @@ -579,11 +579,11 @@ void Window::PrivateData::runAsModal(const bool blockWait) // ----------------------------------------------------------------------- // pugl events -void Window::PrivateData::onPuglConfigure(const double width, const double height) +void Window::PrivateData::onPuglConfigure(const uint width, const uint height) { DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,); - DGL_DBGp("PUGL: onReshape : %f %f\n", width, height); + DGL_DBGp("PUGL: onReshape : %d %d\n", width, height); if (autoScaling) { @@ -1188,25 +1188,21 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver if (verbose) { switch (event->type) { - case PUGL_CREATE: - return fprintf(stderr, "%sCreate\n", prefix); - case PUGL_DESTROY: - return fprintf(stderr, "%sDestroy\n", prefix); - case PUGL_MAP: - return fprintf(stderr, "%sMap\n", prefix); - case PUGL_UNMAP: - return fprintf(stderr, "%sUnmap\n", prefix); - case PUGL_UPDATE: - return 0; // fprintf(stderr, "%sUpdate\n", prefix); + case PUGL_REALIZE: + return PRINT("%sRealize\n", prefix); + case PUGL_UNREALIZE: + return PRINT("%sUnrealize\n", prefix); case PUGL_CONFIGURE: - return PRINT("%sConfigure " PFMT " " PFMT "\n", + return PRINT("%sConfigure %d %d %d %d\n", prefix, event->configure.x, event->configure.y, event->configure.width, event->configure.height); + case PUGL_UPDATE: + return 0; // fprintf(stderr, "%sUpdate\n", prefix); case PUGL_EXPOSE: - return PRINT("%sExpose " PFMT " " PFMT "\n", + return PRINT("%sExpose %d %d %d %d\n", prefix, event->expose.x, event->expose.y, diff --git a/dgl/src/WindowPrivateData.hpp b/dgl/src/WindowPrivateData.hpp index 0983a6dc..ed7b971f 100644 --- a/dgl/src/WindowPrivateData.hpp +++ b/dgl/src/WindowPrivateData.hpp @@ -181,7 +181,7 @@ struct Window::PrivateData : IdleCallback { void runAsModal(bool blockWait); // pugl events - void onPuglConfigure(double width, double height); + void onPuglConfigure(uint width, uint height); void onPuglExpose(); void onPuglClose(); void onPuglFocus(bool focus, CrossingMode mode); diff --git a/dgl/src/pugl.cpp b/dgl/src/pugl.cpp index 4acb5334..557f046d 100644 --- a/dgl/src/pugl.cpp +++ b/dgl/src/pugl.cpp @@ -363,7 +363,8 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height) #ifdef DGL_USING_X11 // workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118 - if (view->impl->win && !view->parent && !view->transientParent) + // NOTE troublesome if used under wayland + if (view->impl->win && !view->parent && !view->transientParent && std::getenv("WAYLAND_DISPLAY") == nullptr) { view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0; } diff --git a/distrho/DistrhoDetails.hpp b/distrho/DistrhoDetails.hpp index f72608f7..34affacb 100644 --- a/distrho/DistrhoDetails.hpp +++ b/distrho/DistrhoDetails.hpp @@ -202,7 +202,7 @@ static constexpr const uint32_t kStateIsOnlyForUI = 0x20; /** Parameter designation.@n - Allows a parameter to be specially designated for a task, like bypass. + Allows a parameter to be specially designated for a task, like bypass and reset. Each designation is unique, there must be only one parameter that uses it.@n The use of designated parameters is completely optional. @@ -214,13 +214,20 @@ enum ParameterDesignation { /** Null or unset designation. */ - kParameterDesignationNull = 0, + kParameterDesignationNull, /** Bypass designation.@n When on (> 0.5f), it means the plugin must run in a bypassed state. */ - kParameterDesignationBypass = 1 + kParameterDesignationBypass, + + /** + Reset designation.@n + When on (> 0.5f), it means the plugin should reset its internal processing state + (like filters, oscillators, envelopes, lfos, etc) and kill all voices. + */ + kParameterDesignationReset, }; /** @@ -234,7 +241,12 @@ namespace ParameterDesignationSymbols { static constexpr const char bypass[] = "dpf_bypass"; /** - Bypass designation symbol, inverted for LV2 so it becomes "enabled". + Reset designation symbol. + */ + static constexpr const char reset[] = "dpf_reset"; + + /** + LV2 bypass designation symbol, inverted for LV2 so it becomes "enabled". */ static constexpr const char bypass_lv2[] = "lv2_enabled"; }; @@ -728,6 +740,18 @@ struct Parameter { ranges.min = 0.0f; ranges.max = 1.0f; break; + case kParameterDesignationReset: + hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger|kParameterIsTrigger; + name = "Reset"; + shortName = "Reset"; + symbol = ParameterDesignationSymbols::reset; + unit = ""; + midiCC = 0; + groupId = kPortGroupNone; + ranges.def = 0.0f; + ranges.min = 0.0f; + ranges.max = 1.0f; + break; } } diff --git a/distrho/DistrhoInfo.hpp b/distrho/DistrhoInfo.hpp index 7df2003d..5016f319 100644 --- a/distrho/DistrhoInfo.hpp +++ b/distrho/DistrhoInfo.hpp @@ -553,6 +553,12 @@ START_NAMESPACE_DISTRHO */ #define DISTRHO_PLUGIN_WANT_LATENCY 1 +/** + Whether the plugin wants MPE for MIDI input and/or output. + @note Only AU and CLAP formats implement this at the moment +*/ +#define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0 + /** Whether the plugin wants MIDI input.@n This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. diff --git a/distrho/extra/ValueSmoother.hpp b/distrho/extra/ValueSmoother.hpp index 6b78a086..75f3169e 100644 --- a/distrho/extra/ValueSmoother.hpp +++ b/distrho/extra/ValueSmoother.hpp @@ -180,20 +180,20 @@ public: inline float peek() const noexcept { const float dy = target - mem; - return mem + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy); + return mem + std::copysign(std::fmin(std::abs(dy), step), dy); } inline float next() noexcept { const float y0 = mem; const float dy = target - y0; - return (mem = y0 + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy)); + return (mem = y0 + std::copysign(std::fmin(std::abs(dy), step), dy)); } private: void updateStep() noexcept { - step = (target - mem) / (tau * sampleRate); + step = std::abs(target - mem) / (tau * sampleRate); } }; diff --git a/distrho/extra/WebViewImpl.cpp b/distrho/extra/WebViewImpl.cpp index cea63578..3bdb3fa5 100644 --- a/distrho/extra/WebViewImpl.cpp +++ b/distrho/extra/WebViewImpl.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2024 Filipe Coelho + * Copyright (C) 2012-2025 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 @@ -106,7 +106,7 @@ @implementation WEB_VIEW_DELEGATE_CLASS_NAME { @public - WebViewMessageCallback callback; + DISTRHO_NAMESPACE::WebViewMessageCallback callback; void* callbackPtr; bool loaded; } @@ -1039,7 +1039,9 @@ static bool gtk3(Display* const display, { void* lib; if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr && - (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr) + (lib = dlopen("libwebkit2gtk-4.1.so.0", RTLD_NOW|RTLD_GLOBAL)) == nullptr && + (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr && + (lib = dlopen("libwebkit2gtk-4.1.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr) { d_stdout("WebView gtk3 platform not available: %s", dlerror()); return false; diff --git a/distrho/src/DistrhoPluginAU.cpp b/distrho/src/DistrhoPluginAU.cpp index 4262ca2e..b97bdb0d 100644 --- a/distrho/src/DistrhoPluginAU.cpp +++ b/distrho/src/DistrhoPluginAU.cpp @@ -202,7 +202,8 @@ static constexpr const uint32_t kType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_AU_TYP static constexpr const uint32_t kSubType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)); static constexpr const uint32_t kManufacturer = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID)); -static constexpr const uint32_t kWantedAudioFormat = kAudioFormatFlagsNativeFloatPacked +static constexpr const uint32_t kWantedAudioFormat = 0 + | kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; @@ -263,7 +264,7 @@ bool isNumChannelsComboValid(const uint16_t numInputs, const uint16_t numOutputs // -------------------------------------------------------------------------------------------------------------------- struct PropertyListener { - AudioUnitPropertyID prop; + AudioUnitPropertyID prop; AudioUnitPropertyListenerProc proc; void* userData; }; @@ -276,12 +277,28 @@ struct RenderListener { typedef std::vector PropertyListeners; typedef std::vector RenderListeners; -// -------------------------------------------------------------------------------------------------------------------- - -typedef struct { - UInt32 numPackets; - MIDIPacket packets[kMaxMidiEvents]; -} d_MIDIPacketList; +#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT +// useful definitions +static constexpr const uint32_t kMIDIPacketNonDataSize = sizeof(MIDIPacket) + #if __cplusplus >= 201103L + - sizeof(MIDIPacket::data); + #else + - sizeof(static_cast(0)->data); + #endif +static constexpr const uint32_t kMIDIPacketListNonDataSize = sizeof(MIDIPacketList) + #if __cplusplus >= 201103L + - sizeof(MIDIPacketList::packet); + #else + - sizeof(static_cast(0)->packet); + #endif + +// size of data used for midi events +static constexpr const uint32_t kMIDIPacketListMaxDataSize = kMIDIPacketNonDataSize * kMaxMidiEvents + + sizeof(Byte) * MidiEvent::kDataSize * kMaxMidiEvents; + +// size of midi list + data +static constexpr const uint32_t kMIDIPacketListSize = kMIDIPacketListNonDataSize + kMIDIPacketListMaxDataSize; +#endif // -------------------------------------------------------------------------------------------------------------------- @@ -331,10 +348,14 @@ public: fUsingRenderListeners(false), fParameterCount(fPlugin.getParameterCount()), fLastParameterValues(nullptr), - fBypassParameterIndex(UINT32_MAX) + fBypassParameterIndex(UINT32_MAX), + fResetParameterIndex(UINT32_MAX) #if DISTRHO_PLUGIN_WANT_MIDI_INPUT , fMidiEventCount(0) #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + , fMidiOutputDataOffset(0) + #endif #if DISTRHO_PLUGIN_WANT_PROGRAMS , fCurrentProgram(-1) , fLastFactoryProgram(0) @@ -345,7 +366,7 @@ public: , fStateCount(fPlugin.getStateCount()) #endif { - if (fParameterCount != 0) + if (fParameterCount != 0) { fLastParameterValues = new float[fParameterCount]; std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount); @@ -354,8 +375,17 @@ public: { fLastParameterValues[i] = fPlugin.getParameterValue(i); - if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) + switch (fPlugin.getParameterDesignation(i)) + { + case kParameterDesignationNull: + break; + case kParameterDesignationBypass: fBypassParameterIndex = i; + break; + case kParameterDesignationReset: + fResetParameterIndex = i; + break; + } } } @@ -370,8 +400,10 @@ public: #endif #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + if ((fMidiOutputPackets = static_cast(std::malloc(kMIDIPacketListSize))) != nullptr) + std::memset(fMidiOutputPackets, 0, kMIDIPacketListSize); + std::memset(&fMidiOutput, 0, sizeof(fMidiOutput)); - std::memset(&fMidiOutputPackets, 0, sizeof(fMidiOutputPackets)); #endif #if DISTRHO_PLUGIN_WANT_PROGRAMS @@ -428,6 +460,10 @@ public: reallocAudioBufferList(false); #endif + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + std::free(fMidiOutputPackets); + #endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS for (uint32_t i=0; inumPackets = 0; #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS fTimePosition.clear(); @@ -635,7 +672,7 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); #if DISTRHO_PLUGIN_WANT_TIMEPOS outDataSize = sizeof(HostCallbackInfo); - outWritable = false; + outWritable = true; return noErr; #else return kAudioUnitErr_InvalidProperty; @@ -659,6 +696,17 @@ public: outWritable = true; return noErr; + case kAudioUnitProperty_SupportsMPE: + DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); + DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); + #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE + outDataSize = sizeof(UInt32); + outWritable = false; + return noErr; + #else + return kAudioUnitErr_InvalidProperty; + #endif + case kAudioUnitProperty_CocoaUI: DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); @@ -708,7 +756,7 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); outDataSize = sizeof(uint16_t); - outWritable = false; + outWritable = true; return noErr; case 'DPFe': @@ -739,7 +787,7 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); outDataSize = sizeof(uint32_t); - outWritable = false; + outWritable = true; return noErr; #endif @@ -748,7 +796,7 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); outDataSize = sizeof(CFArrayRef); - outWritable = false; + outWritable = true; return noErr; case 'DPFs': @@ -764,7 +812,7 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); outDataSize = sizeof(void*); - outWritable = false; + outWritable = true; return noErr; #endif @@ -885,13 +933,13 @@ public: case kAudioUnitProperty_FastDispatch: switch (inElement) { - case kAudioUnitGetParameterSelect: + case kAudioUnitGetParameterSelect: *static_cast(outData) = FastDispatchGetParameter; return noErr; - case kAudioUnitSetParameterSelect: + case kAudioUnitSetParameterSelect: *static_cast(outData) = FastDispatchSetParameter; return noErr; - case kAudioUnitRenderSelect: + case kAudioUnitRenderSelect: *static_cast(outData) = FastDispatchRender; return noErr; } @@ -1028,6 +1076,12 @@ public: } return noErr; + #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE + case kAudioUnitProperty_SupportsMPE: + *static_cast(outData) = 1; + return noErr; + #endif + #if DISTRHO_PLUGIN_HAS_UI case kAudioUnitProperty_CocoaUI: { @@ -1414,7 +1468,7 @@ public: const float value = bypass ? 1.f : 0.f; fLastParameterValues[fBypassParameterIndex] = value; fPlugin.setParameterValue(fBypassParameterIndex, value); - notifyPropertyListeners(inProp, inScope, inElement); + notifyPropertyListeners(inProp, inScope, inElement); } } return noErr; @@ -1436,12 +1490,12 @@ public: #if DISTRHO_PLUGIN_WANT_TIMEPOS { const UInt32 usableDataSize = std::min(inDataSize, static_cast(sizeof(HostCallbackInfo))); - const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0; + const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0; - std::memcpy(&fHostCallbackInfo, inData, usableDataSize); + std::memcpy(&fHostCallbackInfo, inData, usableDataSize); if (sizeof(HostCallbackInfo) > usableDataSize) - std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); + std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); if (changed) notifyPropertyListeners(inProp, inScope, inElement); @@ -1568,7 +1622,7 @@ public: AUEventListenerNotify(NULL, NULL, &event); if (fBypassParameterIndex == inElement) - notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); + notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); } return noErr; @@ -1777,7 +1831,12 @@ public: DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement); - if (fPlugin.isActive()) + if (fResetParameterIndex != UINT32_MAX) + { + fPlugin.setParameterValue(fResetParameterIndex, 1.f); + fPlugin.setParameterValue(fResetParameterIndex, 0.f); + } + else if (fPlugin.isActive()) { fPlugin.deactivate(); fPlugin.activate(); @@ -1787,7 +1846,8 @@ public: fMidiEventCount = 0; #endif #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - fMidiOutputPackets.numPackets = 0; + fMidiOutputDataOffset = 0; + fMidiOutputPackets->numPackets = 0; #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS fTimePosition.clear(); @@ -2015,7 +2075,7 @@ public: midiEvent.data[1] = inData1; midiEvent.data[2] = inData2; - switch (inStatus) + switch (inStatus & 0xF0) { case 0x80: case 0x90: @@ -2057,6 +2117,8 @@ public: break; default: // invalid + d_debug("auMIDIEvent received invalid event %u %u %u %u @ %u", + inStatus, inData1, inData2, inOffsetSampleFrame, fMidiEventCount); return kAudioUnitErr_InvalidPropertyValue; } @@ -2133,6 +2195,7 @@ private: const uint32_t fParameterCount; float* fLastParameterValues; uint32_t fBypassParameterIndex; + uint32_t fResetParameterIndex; #if DISTRHO_PLUGIN_WANT_MIDI_INPUT uint32_t fMidiEventCount; @@ -2141,8 +2204,9 @@ private: #endif #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + uint32_t fMidiOutputDataOffset; + MIDIPacketList* fMidiOutputPackets; AUMIDIOutputCallbackStruct fMidiOutput; - d_MIDIPacketList fMidiOutputPackets; #endif #if DISTRHO_PLUGIN_WANT_PROGRAMS @@ -2172,7 +2236,7 @@ private: const PropertyListener& pl(*it); if (pl.prop == prop) - pl.proc(pl.userData, fComponent, prop, scope, elem); + pl.proc(pl.userData, fComponent, prop, scope, elem); } } @@ -2217,7 +2281,8 @@ private: #endif #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - fMidiOutputPackets.numPackets = 0; + fMidiOutputDataOffset = 0; + fMidiOutputPackets->numPackets = 0; #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS @@ -2294,12 +2359,11 @@ private: #endif #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT - if (fMidiOutputPackets.numPackets != 0 && fMidiOutput.midiOutputCallback != nullptr) + if (fMidiOutputPackets != nullptr && + fMidiOutputPackets->numPackets != 0 && + fMidiOutput.midiOutputCallback != nullptr) { - fMidiOutput.midiOutputCallback(fMidiOutput.userData, - inTimeStamp, - 0, - reinterpret_cast(&fMidiOutputPackets)); + fMidiOutput.midiOutputCallback(fMidiOutput.userData, inTimeStamp, 0, fMidiOutputPackets); } #else // unused @@ -2716,17 +2780,21 @@ private: bool writeMidi(const MidiEvent& midiEvent) { DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fMidiOutput.midiOutputCallback != nullptr, false); + DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("Out of memory", fMidiOutputPackets != nullptr, false); - if (midiEvent.size > sizeof(MIDIPacket::data)) - return true; - if (fMidiOutputPackets.numPackets == kMaxMidiEvents) + if (fMidiOutputDataOffset + kMIDIPacketNonDataSize + midiEvent.size >= kMIDIPacketListMaxDataSize) return false; const uint8_t* const midiData = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data; - MIDIPacket& packet(fMidiOutputPackets.packets[fMidiOutputPackets.numPackets++]); - packet.timeStamp = midiEvent.frame; - packet.length = midiEvent.size; - std::memcpy(packet.data, midiData, midiEvent.size); + MIDIPacket* const packet = reinterpret_cast( + reinterpret_cast(fMidiOutputPackets->packet) + fMidiOutputDataOffset); + + packet->timeStamp = midiEvent.frame; + packet->length = midiEvent.size; + std::memcpy(packet->data, midiData, midiEvent.size); + + ++fMidiOutputPackets->numPackets; + fMidiOutputDataOffset += kMIDIPacketNonDataSize + midiEvent.size; return true; } @@ -2793,7 +2861,7 @@ private: // -------------------------------------------------------------------------------------------------------------------- struct AudioComponentPlugInInstance { - AudioComponentPlugInInterface acpi; + AudioComponentPlugInInterface acpi; PluginAU* plugin; AudioComponentPlugInInstance() noexcept @@ -2802,9 +2870,9 @@ struct AudioComponentPlugInInstance { { std::memset(&acpi, 0, sizeof(acpi)); acpi.Open = Open; - acpi.Close = Close; - acpi.Lookup = Lookup; - acpi.reserved = nullptr; + acpi.Close = Close; + acpi.Lookup = Lookup; + acpi.reserved = nullptr; } ~AudioComponentPlugInInstance() @@ -2812,14 +2880,18 @@ struct AudioComponentPlugInInstance { delete plugin; } - static OSStatus Open(void* const self, const AudioUnit component) + static OSStatus Open(void* const self, const AudioUnit component) { + d_debug("AudioComponentPlugInInstance::Open(%p)", self); + static_cast(self)->plugin = new PluginAU(component); return noErr; } - static OSStatus Close(void* const self) + static OSStatus Close(void* const self) { + d_debug("AudioComponentPlugInInstance::Close(%p)", self); + delete static_cast(self); return noErr; } @@ -2908,15 +2980,15 @@ struct AudioComponentPlugInInstance { d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)", self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); - UInt32 dataSize = 0; - Boolean writable = false; + UInt32 dataSize = 0; + Boolean writable = false; const OSStatus res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, dataSize, writable); - if (outDataSize != nullptr) - *outDataSize = dataSize; + if (outDataSize != nullptr) + *outDataSize = dataSize; - if (outWritable != nullptr) - *outWritable = writable; + if (outWritable != nullptr) + *outWritable = writable; return res; } @@ -2928,8 +3000,16 @@ struct AudioComponentPlugInInstance { void* const outData, UInt32* const ioDataSize) { - d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)", - self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); + #ifdef DEBUG + switch (inProp) { + case kAudioUnitProperty_PresentPreset: + break; + default: + d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)", + self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); + break; + } + #endif DISTRHO_SAFE_ASSERT_RETURN(ioDataSize != nullptr, kAudio_ParamError); Boolean writable; @@ -2952,24 +3032,24 @@ struct AudioComponentPlugInInstance { if (res != noErr) return res; - void* outBuffer; + void* outBuffer; uint8_t* tmpBuffer; if (inDataSize < outDataSize) - { - tmpBuffer = new uint8_t[outDataSize]; - outBuffer = tmpBuffer; - } + { + tmpBuffer = new uint8_t[outDataSize]; + outBuffer = tmpBuffer; + } else { - tmpBuffer = nullptr; - outBuffer = outData; - } + tmpBuffer = nullptr; + outBuffer = outData; + } res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer); - if (res != noErr) + if (res != noErr) { - *ioDataSize = 0; + *ioDataSize = 0; return res; } diff --git a/distrho/src/DistrhoPluginCLAP.cpp b/distrho/src/DistrhoPluginCLAP.cpp index 498957ec..68fb9e4c 100644 --- a/distrho/src/DistrhoPluginCLAP.cpp +++ b/distrho/src/DistrhoPluginCLAP.cpp @@ -751,6 +751,7 @@ public: updateStateValueCallback), fHost(host), fOutputEvents(nullptr), + fResetParameterIndex(UINT32_MAX), #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 fUsingCV(false), #endif @@ -763,7 +764,19 @@ public: #endif fHostExtensions(host) { - fCachedParameters.setup(fPlugin.getParameterCount()); + if (const uint32_t paramCount = fPlugin.getParameterCount()) + { + fCachedParameters.setup(paramCount); + + for (uint32_t i=0; irequest_restart(fHost); + } + } + bool process(const clap_process_t* const process) { #if DISTRHO_PLUGIN_WANT_MIDI_INPUT @@ -1114,14 +1143,19 @@ public: { const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); - if (fPlugin.getParameterDesignation(index) == kParameterDesignationBypass) + switch (fPlugin.getParameterDesignation(index)) { + case kParameterDesignationBypass: info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_BYPASS|CLAP_PARAM_IS_AUTOMATABLE; std::strcpy(info->name, "Bypass"); std::strcpy(info->module, "dpf_bypass"); - } - else - { + break; + case kParameterDesignationReset: + info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_READONLY; + std::strcpy(info->name, "Reset"); + std::strcpy(info->module, "dpf_reset"); + break; + default: const uint32_t hints = fPlugin.getParameterHints(index); const uint32_t groupId = fPlugin.getParameterGroupId(index); @@ -1151,6 +1185,7 @@ public: } d_strncpy(info->module + wrtn, fPlugin.getParameterSymbol(index), CLAP_PATH_SIZE - wrtn); + break; } info->id = index; @@ -1786,6 +1821,7 @@ private: const clap_host_t* const fHost; const clap_output_events_t* fOutputEvents; + uint32_t fResetParameterIndex; #if DISTRHO_PLUGIN_NUM_INPUTS != 0 const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; #endif @@ -2284,23 +2320,33 @@ static bool CLAP_ABI clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, { if (is_input) { - #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT info->id = 0; + #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE + info->supported_dialects = CLAP_NOTE_DIALECT_MIDI | CLAP_NOTE_DIALECT_MIDI_MPE; + info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI_MPE; + #else info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; + #endif std::strcpy(info->name, "Event/MIDI Input"); return true; - #endif + #endif } else { - #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT + #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT info->id = 0; + #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE + info->supported_dialects = CLAP_NOTE_DIALECT_MIDI | CLAP_NOTE_DIALECT_MIDI_MPE; + info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI_MPE; + #else info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; + #endif std::strcpy(info->name, "Event/MIDI Output"); return true; - #endif + #endif } return false; @@ -2440,9 +2486,10 @@ static void CLAP_ABI clap_plugin_stop_processing(const clap_plugin_t*) // nothing to do } -static void CLAP_ABI clap_plugin_reset(const clap_plugin_t*) +static void CLAP_ABI clap_plugin_reset(const clap_plugin_t* const plugin) { - // nothing to do + PluginCLAP* const instance = static_cast(plugin->plugin_data); + instance->reset(); } static clap_process_status CLAP_ABI clap_plugin_process(const clap_plugin_t* const plugin, const clap_process_t* const process) diff --git a/distrho/src/DistrhoPluginChecks.h b/distrho/src/DistrhoPluginChecks.h index fb05181b..a5349002 100644 --- a/distrho/src/DistrhoPluginChecks.h +++ b/distrho/src/DistrhoPluginChecks.h @@ -65,6 +65,10 @@ # define DISTRHO_PLUGIN_WANT_LATENCY 0 #endif +#ifndef DISTRHO_PLUGIN_WANT_MIDI_AS_MPE +# define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0 +#endif + #ifndef DISTRHO_PLUGIN_WANT_MIDI_OUTPUT # define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 #endif @@ -178,6 +182,13 @@ # error Synths need audio output to work! #endif +// -------------------------------------------------------------------------------------------------------------------- +// Test if MIDI as MPE enabled where it doesn't make sense + +#if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE && ! (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) +# error MIDI as MPE needs MIDI input or output to work! +#endif + // -------------------------------------------------------------------------------------------------------------------- // Enable MIDI input if synth, test if midi-input disabled when synth diff --git a/distrho/src/DistrhoPluginLV2export.cpp b/distrho/src/DistrhoPluginLV2export.cpp index ba3cb196..3b0d22cb 100644 --- a/distrho/src/DistrhoPluginLV2export.cpp +++ b/distrho/src/DistrhoPluginLV2export.cpp @@ -758,6 +758,16 @@ void lv2_generate_ttl(const char* const basename) pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; pluginString += " lv2:designation lv2:enabled ;\n"; break; + case kParameterDesignationReset: + designated = true; + pluginString += " lv2:name \"Reset\" ;\n"; + pluginString += " lv2:symbol \"" + String(ParameterDesignationSymbols::reset) + "\" ;\n"; + pluginString += " lv2:default 0 ;\n"; + pluginString += " lv2:minimum 0 ;\n"; + pluginString += " lv2:maximum 1 ;\n"; + pluginString += " lv2:portProperty lv2:toggled , lv2:integer , <" LV2_PORT_PROPS__trigger "> ;\n"; + pluginString += " lv2:designation <" LV2_KXSTUDIO_PROPERTIES__Reset "> ;\n"; + break; } } diff --git a/distrho/src/DistrhoPluginVST3.cpp b/distrho/src/DistrhoPluginVST3.cpp index cb743923..7295c892 100644 --- a/distrho/src/DistrhoPluginVST3.cpp +++ b/distrho/src/DistrhoPluginVST3.cpp @@ -1747,6 +1747,12 @@ public: case kParameterDesignationBypass: flags |= V3_PARAM_IS_BYPASS; break; + case kParameterDesignationReset: + info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN; + info->step_count = 1; + strncpy_utf16(info->title, "Reset", 128); + strncpy_utf16(info->short_title, "Reset", 128); + return V3_OK; } if (hints & kParameterIsOutput) diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index f0c8d259..0241b59c 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.cpp @@ -26,7 +26,9 @@ # include #endif -#if defined(DISTRHO_OS_WINDOWS) +#if defined(DISTRHO_OS_WASM) +# include +#elif defined(DISTRHO_OS_WINDOWS) # include # include #elif defined(HAVE_X11) @@ -94,7 +96,9 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle) if (const char* const scale = getenv("DPF_SCALE_FACTOR")) return std::max(1.0, std::atof(scale)); - #if defined(DISTRHO_OS_WINDOWS) + #if defined(DISTRHO_OS_WASM) + return emscripten_get_device_pixel_ratio(); + #elif defined(DISTRHO_OS_WINDOWS) if (const HMODULE Shcore = LoadLibraryA("Shcore.dll")) { typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*); diff --git a/distrho/src/DistrhoUIAU.mm b/distrho/src/DistrhoUIAU.mm index c0987f51..1b3f77e5 100644 --- a/distrho/src/DistrhoUIAU.mm +++ b/distrho/src/DistrhoUIAU.mm @@ -387,6 +387,9 @@ END_NAMESPACE_DISTRHO #define COCOA_VIEW_CLASS_NAME \ MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID) +using DISTRHO_NAMESPACE::DPF_UI_AU; +using DISTRHO_NAMESPACE::d_nextSampleRate; + @interface COCOA_VIEW_CLASS_NAME : NSView { @public diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp index e9ae05c5..ea3f56a2 100644 --- a/distrho/src/DistrhoUIInternal.hpp +++ b/distrho/src/DistrhoUIInternal.hpp @@ -267,12 +267,12 @@ public: uiData->app.repaintIfNeeeded(); } - void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs) + void addIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb, const uint timerFrequencyInMs) { uiData->window->addIdleCallback(cb, timerFrequencyInMs); } - void removeIdleCallbackForNativeIdle(IdleCallback* const cb) + void removeIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb) { uiData->window->removeIdleCallback(cb); } diff --git a/distrho/src/DistrhoUIVST3.cpp b/distrho/src/DistrhoUIVST3.cpp index 0ecf675f..a326c4b3 100644 --- a/distrho/src/DistrhoUIVST3.cpp +++ b/distrho/src/DistrhoUIVST3.cpp @@ -129,7 +129,7 @@ static uint translateVST3Modifiers(const int64_t modifiers) noexcept * Helper class for getting a native idle timer. */ #if !DPF_VST3_USING_HOST_RUN_LOOP -class NativeIdleCallback : public IdleCallback +class NativeIdleCallback : public DGL_NAMESPACE::IdleCallback { public: NativeIdleCallback(UIExporter& ui) diff --git a/distrho/src/lv2/lv2_kxstudio_properties.h b/distrho/src/lv2/lv2_kxstudio_properties.h index 22922650..68dbe66f 100644 --- a/distrho/src/lv2/lv2_kxstudio_properties.h +++ b/distrho/src/lv2/lv2_kxstudio_properties.h @@ -1,6 +1,6 @@ /* LV2 KXStudio Properties Extension - Copyright 2014-2021 Filipe Coelho + Copyright 2014-2024 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 @@ -27,6 +27,7 @@ #define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" #define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable" +#define LV2_KXSTUDIO_PROPERTIES__Reset LV2_KXSTUDIO_PROPERTIES_PREFIX "Reset" #define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" #define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" diff --git a/distrho/src/xaymar-vst2/vst.h b/distrho/src/xaymar-vst2/vst.h index 9d32eee6..d193df9e 100644 --- a/distrho/src/xaymar-vst2/vst.h +++ b/distrho/src/xaymar-vst2/vst.h @@ -1,9 +1,22 @@ -// This was created from released VST2.x plugins, and is technically under the 2-clause BSD license. -// Depending on which country you are in, Steinberg can do fuck all about this. Notable countries for -// this are most members of the United States of America, the entirety of Europe, Japan, and Russia. -// Consult a lawyer if you don't know if clean room reverse engineering is allowed in your country. +/* + * Copyright 2020 Michael Fabian 'Xaymar' Dirks + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ -// See README.md for all information. +/* + * This was created from released VST2.x plugins, and is technically under the 2-clause BSD license. Depending on which country you are in, Steinberg can do fuck all about this. Notable countries for this are most members of the United States of America, the entirety of Europe, Japan, and Russia. + * + * Consult a lawyer if you don't know if clean room reverse engineering is allowed in your country. + * + * See README.md for all information. + */ // Known additional information: // - Function call standard seems to be stdcall. @@ -94,7 +107,7 @@ enum VST_CATEGORY { enum VST_EFFECT_OPCODE { /* Create/Initialize the effect (if it has not been created already). - * + * * @return Always 0. */ VST_EFFECT_OPCODE_00 = 0x00, @@ -104,7 +117,7 @@ enum VST_EFFECT_OPCODE { /* Destroy the effect (if there is any) and free its memory. * * This should destroy the actual object created by VST_ENTRYPOINT. - * + * * @return Always 0. */ VST_EFFECT_OPCODE_01 = 0x01, @@ -135,7 +148,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_05 = 0x05, /* Get the value? label for the parameter. - * + * * @param p_int1 Parameter index. * @param p_ptr 'char[8]' * @return 0 on success, 1 on failure. @@ -144,7 +157,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_PARAM_GETLABEL = 0x06, /* Get the string value for the parameter. - * + * * @param p_int1 Parameter index. * @param p_ptr 'char[8]' * @return 0 on success, 1 on failure. @@ -153,7 +166,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_PARAM_GETVALUE = 0x07, /* Get the name for the parameter. - * + * * @param p_int1 Parameter index. * @param p_ptr 'char[8]' * @return 0 on success, 1 on failure. @@ -168,7 +181,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_09 = 0x09, /* Set the new sample rate for the plugin to use. - * + * * @param p_float New sample rate as a float (double on 64-bit because register upgrades). */ VST_EFFECT_OPCODE_0A = 0x0A, @@ -186,7 +199,7 @@ enum VST_EFFECT_OPCODE { /* Effect processing should be suspended/paused. * * Unclear if this is should result in a flush of buffers. - * + * * @param p_int2 0 if the effect should suspend processing, 1 if it should resume. */ VST_EFFECT_OPCODE_0C = 0x0C, @@ -202,7 +215,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_WINDOW_GETRECT = 0x0D, /* Create the window for the plugin. - * + * * @param p_ptr HWND of the parent window. * @return 0 on failure, or HWND on success. */ @@ -210,7 +223,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_WINDOW_CREATE = 0x0E, /* Destroy the plugins window. - * + * * @return Always 0. */ VST_EFFECT_OPCODE_0F = 0x0F, @@ -383,7 +396,7 @@ enum VST_EFFECT_OPCODE { */ VST_EFFECT_OPCODE_29 = 0x29, - /* Set the speaker arrangement + /* Set the speaker arrangement * * @param p_int2 (vst_speaker_arrangement*) Pointer to a pointer to the speaker arrangement for the input. * @param p_ptr (vst_speaker_arrangement*) Pointer to a pointer to the speaker arrangement for the output. @@ -446,13 +459,13 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_VENDOR_VERSION = 0x31, /* User defined OP Code, for custom interaction. - * + * */ VST_EFFECT_OPCODE_32 = 0x32, VST_EFFECT_OPCODE_CUSTOM = 0x32, /* Test for support of a specific named feature. - * + * * @param p_ptr Pointer to a zero-terminated buffer containing the feature name. * @return Non-zero if the feature is supported, otherwise 0. */ @@ -460,7 +473,7 @@ enum VST_EFFECT_OPCODE { VST_EFFECT_OPCODE_SUPPORTS = 0x33, /* Number of samples that are at the tail at the end of playback. - * + * * @return 0 or 1 for no tail, > 1 for number of samples to tail. */ VST_EFFECT_OPCODE_34 = 0x34, @@ -586,14 +599,14 @@ enum VST_EFFECT_OPCODE { /* Begin processing of audio. * - * - * + * + * */ VST_EFFECT_OPCODE_PROCESS_BEGIN = 0x47, /* End processing of audio. * - * + * * */ VST_EFFECT_OPCODE_PROCESS_END = 0x48, @@ -705,7 +718,7 @@ enum VST_HOST_OPCODE { VST_HOST_OPCODE_2B = 0x2B, /* Parameter lost focus. - * + * * @param int1 Parameter index. */ VST_HOST_OPCODE_2C = 0x2C, @@ -808,7 +821,7 @@ struct vst_effect { // 64-bit adds 4-byte padding here to align pointers. /* Control the VST through an opcode and up to four parameters. - * + * * @param this Pointer to the effect itself. * @param opcode The opcode to run, see VST_EFFECT_OPCODES. * @param p_int1 Parameter, see VST_EFFECT_OPCODES. @@ -817,22 +830,22 @@ struct vst_effect { * @param p_float Parameter, see VST_EFFECT_OPCODES. */ intptr_t(VST_FUNCTION_INTERFACE* control)(vst_effect* pthis, VST_EFFECT_OPCODE opcode, int32_t p_int1, - intptr_t p_int2, void* p_ptr, float p_float); + intptr_t p_int2, void* p_ptr, float p_float); /* Process the given number of samples in inputs and outputs. * * Different to process_float how? Never seen any difference. - * + * * @param pthis Pointer to the effect itself. * @param inputs Pointer to an array of 'const float[samples]' with size numInputs. * @param outputs Pointer to an array of 'float[samples]' with size numOutputs. * @param samples Number of samples per channel in inputs. */ void(VST_FUNCTION_INTERFACE* process)(vst_effect* pthis, const float* const* inputs, float** outputs, - int32_t samples); + int32_t samples); /* Updates the value for the parameter at the given index, or does nothing if out of bounds. - * + * * @param pthis Pointer to the effect itself. * @param index Parameter index. * @param value New value for the parameter. @@ -840,7 +853,7 @@ struct vst_effect { void(VST_FUNCTION_INTERFACE* set_parameter)(vst_effect* pthis, uint32_t index, float value); /* Returns the value stored for the parameter at index, or 0 if out of bounds. - * + * * @param pthis Pointer to the effect itself. * @param index Parameter index. * @return float Value of the parameter. @@ -853,7 +866,7 @@ struct vst_effect { int32_t num_outputs; // Number of outputs. /* Bitflags - * + * * Bit Description * 1 Effect has "Editor" * 2 Unknown (Found in: ReaDelay) @@ -872,7 +885,7 @@ struct vst_effect { /* Initial delay before processing of samples can actually begin in Samples. * - * Should be updated before or during handling the 0x47 control call. + * Should be updated before or during handling the 0x47 control call. */ int32_t delay; @@ -884,16 +897,16 @@ struct vst_effect { /* Id of the plugin. * - * Due to this not being enough for uniqueness, it should not be used alone + * Due to this not being enough for uniqueness, it should not be used alone * for indexing. Ideally you want to index like this: * [unique_id][module_name][version][flags] - * If any of the checks after unique_id fail, you default to the first + * If any of the checks after unique_id fail, you default to the first * possible choice. */ int32_t unique_id; /* Plugin version - * + * * Unrelated to the minimum VST Version, but often the same. */ int32_t version; @@ -908,19 +921,19 @@ struct vst_effect { * @param samples Number of samples per channel in inputs. */ void(VST_FUNCTION_INTERFACE* process_float)(vst_effect* pthis, const float* const* inputs, float** outputs, - int32_t samples); + int32_t samples); /* Process the given number of double samples in inputs and outputs. * * Used only by 2.4 hosts and plugins, possibly restricted to said version. - * + * * @param pthis Pointer to the effect itself. * @param inputs Pointer to an array of 'const double[samples]' with size numInputs. * @param outputs Pointer to an array of 'double[samples]' with size numOutputs. * @param samples Number of samples per channel in inputs. */ void(VST_FUNCTION_INTERFACE* process_double)(vst_effect* pthis, const double* const* inputs, double** outputs, - int32_t samples); + int32_t samples); // Everything after this is unknown and was present in reacomp-standalone.dll. uint8_t _unknown[56]; // 56-bytes of something. Could also just be 52-bytes. @@ -969,13 +982,13 @@ struct vst_speaker_arrangement { }; /* Callback used by the plugin to interface with the host. - * + * * @param opcode See VST_HOST_OPCODE * @param p_str Zero terminated string or null on call. * @return ? */ typedef intptr_t (*vst_host_callback)(vst_effect* plugin, VST_HOST_OPCODE opcode, int32_t p_int1, int64_t p_int2, - void* p_str, float p_float); + void* p_str, float p_float); /* Entry point for VST2.x plugins. *