Browse Source

Merge: origin/develop -> improve/state-allocation

pull/479/head
sevenc-nanashi 3 months ago
parent
commit
116dd854dd
23 changed files with 437 additions and 140 deletions
  1. +3
    -4
      .github/workflows/build.yml
  2. +9
    -9
      .github/workflows/cmake.yml
  3. +9
    -9
      .github/workflows/example-plugins.yml
  4. +6
    -5
      .gitignore
  5. +1
    -1
      README.md
  6. +7
    -1
      dgl/EventHandlers.hpp
  7. +91
    -1
      dgl/src/EventHandlers.cpp
  8. +10
    -14
      dgl/src/WindowPrivateData.cpp
  9. +1
    -1
      dgl/src/WindowPrivateData.hpp
  10. +2
    -1
      dgl/src/pugl.cpp
  11. +28
    -4
      distrho/DistrhoDetails.hpp
  12. +6
    -0
      distrho/DistrhoInfo.hpp
  13. +18
    -4
      distrho/extra/String.hpp
  14. +5
    -3
      distrho/extra/WebViewImpl.cpp
  15. +148
    -68
      distrho/src/DistrhoPluginAU.cpp
  16. +58
    -11
      distrho/src/DistrhoPluginCLAP.cpp
  17. +11
    -0
      distrho/src/DistrhoPluginChecks.h
  18. +10
    -0
      distrho/src/DistrhoPluginLV2export.cpp
  19. +6
    -0
      distrho/src/DistrhoPluginVST3.cpp
  20. +3
    -0
      distrho/src/DistrhoUIAU.mm
  21. +2
    -2
      distrho/src/DistrhoUIInternal.hpp
  22. +1
    -1
      distrho/src/DistrhoUIVST3.cpp
  23. +2
    -1
      distrho/src/lv2/lv2_kxstudio_properties.h

+ 3
- 4
.github/workflows/build.yml View File

@@ -13,10 +13,9 @@ jobs:
strategy: strategy:
matrix: matrix:
os: os:
# wrong use of AU MIDIPacket
# - macos-12
# - macos-13
# - macos-14
- macos-13
- macos-14
- macos-15
# webgui failure # webgui failure
# - ubuntu-20.04 # - ubuntu-20.04
- ubuntu-22.04 - ubuntu-22.04


+ 9
- 9
.github/workflows/cmake.yml View File

@@ -42,11 +42,11 @@ jobs:
suffix: _24_04 suffix: _24_04
target: ${{ matrix.target }} target: ${{ matrix.target }}


macos-12:
macos-13:
strategy: strategy:
matrix: matrix:
target: [macos-intel, macos-universal, macos-10.15] target: [macos-intel, macos-universal, macos-10.15]
runs-on: macos-12
runs-on: macos-13
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -54,14 +54,14 @@ jobs:
- uses: distrho/dpf-cmake-action@v1 - uses: distrho/dpf-cmake-action@v1
with: with:
dpf_path: . dpf_path: .
suffix: _12
suffix: _13
target: ${{ matrix.target }} target: ${{ matrix.target }}


macos-13:
macos-14:
strategy: strategy:
matrix: matrix:
target: [macos-intel, macos-universal, macos-10.15] target: [macos-intel, macos-universal, macos-10.15]
runs-on: macos-13
runs-on: macos-14
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -69,14 +69,14 @@ jobs:
- uses: distrho/dpf-cmake-action@v1 - uses: distrho/dpf-cmake-action@v1
with: with:
dpf_path: . dpf_path: .
suffix: _13
suffix: _14
target: ${{ matrix.target }} target: ${{ matrix.target }}


macos-14:
macos-15:
strategy: strategy:
matrix: matrix:
target: [macos-intel, macos-universal, macos-10.15] target: [macos-intel, macos-universal, macos-10.15]
runs-on: macos-14
runs-on: macos-15
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -84,7 +84,7 @@ jobs:
- uses: distrho/dpf-cmake-action@v1 - uses: distrho/dpf-cmake-action@v1
with: with:
dpf_path: . dpf_path: .
suffix: _14
suffix: _15
target: ${{ matrix.target }} target: ${{ matrix.target }}


cmake_win32: cmake_win32:


+ 9
- 9
.github/workflows/example-plugins.yml View File

@@ -39,11 +39,11 @@ jobs:
suffix: _24_04 suffix: _24_04
target: ${{ matrix.target }} target: ${{ matrix.target }}


macos-12:
macos-13:
strategy: strategy:
matrix: matrix:
target: [macos-intel, macos-universal, macos-10.15] target: [macos-intel, macos-universal, macos-10.15]
runs-on: macos-12
runs-on: macos-13
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -51,14 +51,14 @@ jobs:
- uses: distrho/dpf-makefile-action@v1 - uses: distrho/dpf-makefile-action@v1
with: with:
dpf_path: . dpf_path: .
suffix: _12
suffix: _13
target: ${{ matrix.target }} target: ${{ matrix.target }}


macos-13:
macos-14:
strategy: strategy:
matrix: matrix:
target: [macos-intel, macos-universal, macos-10.15] target: [macos-intel, macos-universal, macos-10.15]
runs-on: macos-13
runs-on: macos-14
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -66,14 +66,14 @@ jobs:
- uses: distrho/dpf-makefile-action@v1 - uses: distrho/dpf-makefile-action@v1
with: with:
dpf_path: . dpf_path: .
suffix: _13
suffix: _14
target: ${{ matrix.target }} target: ${{ matrix.target }}


macos-14:
macos-15:
strategy: strategy:
matrix: matrix:
target: [macos-intel, macos-universal, macos-10.15] target: [macos-intel, macos-universal, macos-10.15]
runs-on: macos-14
runs-on: macos-15
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@@ -81,5 +81,5 @@ jobs:
- uses: distrho/dpf-makefile-action@v1 - uses: distrho/dpf-makefile-action@v1
with: with:
dpf_path: . dpf_path: .
suffix: _14
suffix: _15
target: ${{ matrix.target }} target: ${{ matrix.target }}

+ 6
- 5
.gitignore View File

@@ -15,8 +15,9 @@ CMakeFiles
CMakeSettings.json CMakeSettings.json
cmake_install.cmake cmake_install.cmake


bin/
build/
docs/
utils/lv2_ttl_generator
utils/lv2_ttl_generator.dSYM/
/bin/
/build/
/docs/
/khronos/
/utils/lv2_ttl_generator
/utils/lv2_ttl_generator.dSYM/

+ 1
- 1
README.md View File

@@ -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 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: ## List of plugins made with DPF:


+ 7
- 1
dgl/EventHandlers.hpp View File

@@ -1,6 +1,6 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -63,6 +63,9 @@ public:
bool isCheckable() const noexcept; bool isCheckable() const noexcept;
void setCheckable(bool checkable) noexcept; void setCheckable(bool checkable) noexcept;


bool isEnabled() const noexcept;
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept;

Point<double> getLastClickPosition() const noexcept; Point<double> getLastClickPosition() const noexcept;
Point<double> getLastMotionPosition() const noexcept; Point<double> getLastMotionPosition() const noexcept;


@@ -121,6 +124,9 @@ public:
KnobEventHandler& operator=(const KnobEventHandler& other); KnobEventHandler& operator=(const KnobEventHandler& other);
virtual ~KnobEventHandler(); virtual ~KnobEventHandler();


bool isEnabled() const noexcept;
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept;

// if setStep(1) has been called before, this returns true // if setStep(1) has been called before, this returns true
bool isInteger() const noexcept; bool isInteger() const noexcept;




+ 91
- 1
dgl/src/EventHandlers.cpp View File

@@ -1,6 +1,6 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -31,6 +31,8 @@ struct ButtonEventHandler::PrivateData {
int state; int state;
bool checkable; bool checkable;
bool checked; bool checked;
bool enabled;
bool enabledInput;


Point<double> lastClickPos; Point<double> lastClickPos;
Point<double> lastMotionPos; Point<double> lastMotionPos;
@@ -44,11 +46,16 @@ struct ButtonEventHandler::PrivateData {
state(kButtonStateDefault), state(kButtonStateDefault),
checkable(false), checkable(false),
checked(false), checked(false),
enabled(true),
enabledInput(true),
lastClickPos(0, 0), lastClickPos(0, 0),
lastMotionPos(0, 0) {} lastMotionPos(0, 0) {}


bool mouseEvent(const Widget::MouseEvent& ev) bool mouseEvent(const Widget::MouseEvent& ev)
{ {
if (! enabledInput)
return false;

lastClickPos = ev.pos; lastClickPos = ev.pos;


// button was released, handle it now // button was released, handle it now
@@ -98,6 +105,9 @@ struct ButtonEventHandler::PrivateData {


bool motionEvent(const Widget::MotionEvent& ev) bool motionEvent(const Widget::MotionEvent& ev)
{ {
if (! enabledInput)
return false;

// keep pressed // keep pressed
if (button != -1) 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<double>();
lastMotionPos = Point<double>();
}

enabled = enabled2;
widget->repaint();
}

DISTRHO_DECLARE_NON_COPYABLE(PrivateData) DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
}; };


@@ -217,6 +248,16 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept
pData->checkable = checkable; 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<double> ButtonEventHandler::getLastClickPosition() const noexcept Point<double> ButtonEventHandler::getLastClickPosition() const noexcept
{ {
return pData->lastClickPos; return pData->lastClickPos;
@@ -281,6 +322,8 @@ struct KnobEventHandler::PrivateData {
float value; float value;
float valueDef; float valueDef;
float valueTmp; float valueTmp;
bool enabled;
bool enabledInput;
bool usingDefault; bool usingDefault;
bool usingLog; bool usingLog;
Orientation orientation; Orientation orientation;
@@ -301,6 +344,8 @@ struct KnobEventHandler::PrivateData {
value(0.5f), value(0.5f),
valueDef(value), valueDef(value),
valueTmp(value), valueTmp(value),
enabled(true),
enabledInput(true),
usingDefault(false), usingDefault(false),
usingLog(false), usingLog(false),
orientation(Vertical), orientation(Vertical),
@@ -320,6 +365,8 @@ struct KnobEventHandler::PrivateData {
value(other->value), value(other->value),
valueDef(other->valueDef), valueDef(other->valueDef),
valueTmp(value), valueTmp(value),
enabled(other->enabled),
enabledInput(other->enabledInput),
usingDefault(other->usingDefault), usingDefault(other->usingDefault),
usingLog(other->usingLog), usingLog(other->usingLog),
orientation(other->orientation), orientation(other->orientation),
@@ -338,6 +385,8 @@ struct KnobEventHandler::PrivateData {
value = other->value; value = other->value;
valueDef = other->valueDef; valueDef = other->valueDef;
valueTmp = value; valueTmp = value;
enabled = other->enabled;
enabledInput = other->enabledInput;
usingDefault = other->usingDefault; usingDefault = other->usingDefault;
usingLog = other->usingLog; usingLog = other->usingLog;
orientation = other->orientation; orientation = other->orientation;
@@ -363,6 +412,9 @@ struct KnobEventHandler::PrivateData {


bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor) bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor)
{ {
if (! enabledInput)
return false;

if (ev.button != 1) if (ev.button != 1)
return false; return false;


@@ -416,6 +468,9 @@ struct KnobEventHandler::PrivateData {


bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor) bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor)
{ {
if (! enabledInput)
return false;

if ((state & kKnobStateDragging) == 0x0) if ((state & kKnobStateDragging) == 0x0)
return false; return false;


@@ -501,6 +556,9 @@ struct KnobEventHandler::PrivateData {


bool scrollEvent(const Widget::ScrollEvent& ev) bool scrollEvent(const Widget::ScrollEvent& ev)
{ {
if (! enabledInput)
return false;

if (! widget->contains(ev.pos)) if (! widget->contains(ev.pos))
return false; return false;


@@ -541,6 +599,28 @@ struct KnobEventHandler::PrivateData {
return ((usingLog ? invlogscale(value) : value) - minimum) / diff; 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 void setRange(const float min, const float max) noexcept
{ {
DISTRHO_SAFE_ASSERT_RETURN(max > min,); DISTRHO_SAFE_ASSERT_RETURN(max > min,);
@@ -598,6 +678,16 @@ KnobEventHandler::~KnobEventHandler()
delete pData; 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 bool KnobEventHandler::isInteger() const noexcept
{ {
return d_isEqual(pData->step, 1.f); return d_isEqual(pData->step, 1.f);


+ 10
- 14
dgl/src/WindowPrivateData.cpp View File

@@ -579,11 +579,11 @@ void Window::PrivateData::runAsModal(const bool blockWait)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// pugl events // 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,); 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) if (autoScaling)
{ {
@@ -1188,25 +1188,21 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver


if (verbose) { if (verbose) {
switch (event->type) { 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: case PUGL_CONFIGURE:
return PRINT("%sConfigure " PFMT " " PFMT "\n",
return PRINT("%sConfigure %d %d %d %d\n",
prefix, prefix,
event->configure.x, event->configure.x,
event->configure.y, event->configure.y,
event->configure.width, event->configure.width,
event->configure.height); event->configure.height);
case PUGL_UPDATE:
return 0; // fprintf(stderr, "%sUpdate\n", prefix);
case PUGL_EXPOSE: case PUGL_EXPOSE:
return PRINT("%sExpose " PFMT " " PFMT "\n",
return PRINT("%sExpose %d %d %d %d\n",
prefix, prefix,
event->expose.x, event->expose.x,
event->expose.y, event->expose.y,


+ 1
- 1
dgl/src/WindowPrivateData.hpp View File

@@ -181,7 +181,7 @@ struct Window::PrivateData : IdleCallback {
void runAsModal(bool blockWait); void runAsModal(bool blockWait);


// pugl events // pugl events
void onPuglConfigure(double width, double height);
void onPuglConfigure(uint width, uint height);
void onPuglExpose(); void onPuglExpose();
void onPuglClose(); void onPuglClose();
void onPuglFocus(bool focus, CrossingMode mode); void onPuglFocus(bool focus, CrossingMode mode);


+ 2
- 1
dgl/src/pugl.cpp View File

@@ -363,7 +363,8 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)


#ifdef DGL_USING_X11 #ifdef DGL_USING_X11
// workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118 // 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; view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0;
} }


+ 28
- 4
distrho/DistrhoDetails.hpp View File

@@ -202,7 +202,7 @@ static constexpr const uint32_t kStateIsOnlyForUI = 0x20;


/** /**
Parameter designation.@n 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 Each designation is unique, there must be only one parameter that uses it.@n
The use of designated parameters is completely optional. The use of designated parameters is completely optional.
@@ -214,13 +214,20 @@ enum ParameterDesignation {
/** /**
Null or unset designation. Null or unset designation.
*/ */
kParameterDesignationNull = 0,
kParameterDesignationNull,


/** /**
Bypass designation.@n Bypass designation.@n
When on (> 0.5f), it means the plugin must run in a bypassed state. 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"; 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"; static constexpr const char bypass_lv2[] = "lv2_enabled";
}; };
@@ -728,6 +740,18 @@ struct Parameter {
ranges.min = 0.0f; ranges.min = 0.0f;
ranges.max = 1.0f; ranges.max = 1.0f;
break; 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;
} }
} }




+ 6
- 0
distrho/DistrhoInfo.hpp View File

@@ -553,6 +553,12 @@ START_NAMESPACE_DISTRHO
*/ */
#define DISTRHO_PLUGIN_WANT_LATENCY 1 #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 Whether the plugin wants MIDI input.@n
This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true.


+ 18
- 4
distrho/extra/String.hpp View File

@@ -22,6 +22,10 @@


#include <algorithm> #include <algorithm>


#if __cplusplus >= 201703L
# include <string_view>
#endif

START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@@ -49,10 +53,7 @@ public:
fBufferLen(0), fBufferLen(0),
fBufferAlloc(false) fBufferAlloc(false)
{ {
char ch[2];
ch[0] = c;
ch[1] = '\0';

const char ch[2] = { c, '\0' };
_dup(ch); _dup(ch);
} }


@@ -87,6 +88,19 @@ public:
_dup(strBuf); _dup(strBuf);
} }


#if __cplusplus >= 201703L
/*
* std::string_view compatible variant.
*/
explicit String(const std::string_view& strView) noexcept
: fBuffer(_null()),
fBufferLen(0),
fBufferAlloc(false)
{
_dup(strView.data(), strView.size());
}
#endif

/* /*
* Integer. * Integer.
*/ */


+ 5
- 3
distrho/extra/WebViewImpl.cpp View File

@@ -1,6 +1,6 @@
/* /*
* DISTRHO Plugin Framework (DPF) * DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -106,7 +106,7 @@


@implementation WEB_VIEW_DELEGATE_CLASS_NAME { @implementation WEB_VIEW_DELEGATE_CLASS_NAME {
@public @public
WebViewMessageCallback callback;
DISTRHO_NAMESPACE::WebViewMessageCallback callback;
void* callbackPtr; void* callbackPtr;
bool loaded; bool loaded;
} }
@@ -1039,7 +1039,9 @@ static bool gtk3(Display* const display,
{ {
void* lib; void* lib;
if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr && 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()); d_stdout("WebView gtk3 platform not available: %s", dlerror());
return false; return false;


+ 148
- 68
distrho/src/DistrhoPluginAU.cpp View File

@@ -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 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 kManufacturer = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID));


static constexpr const uint32_t kWantedAudioFormat = kAudioFormatFlagsNativeFloatPacked
static constexpr const uint32_t kWantedAudioFormat = 0
| kAudioFormatFlagsNativeFloatPacked
| kAudioFormatFlagIsNonInterleaved; | kAudioFormatFlagIsNonInterleaved;




@@ -263,7 +264,7 @@ bool isNumChannelsComboValid(const uint16_t numInputs, const uint16_t numOutputs
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------


struct PropertyListener { struct PropertyListener {
AudioUnitPropertyID prop;
AudioUnitPropertyID prop;
AudioUnitPropertyListenerProc proc; AudioUnitPropertyListenerProc proc;
void* userData; void* userData;
}; };
@@ -276,12 +277,28 @@ struct RenderListener {
typedef std::vector<PropertyListener> PropertyListeners; typedef std::vector<PropertyListener> PropertyListeners;
typedef std::vector<RenderListener> RenderListeners; typedef std::vector<RenderListener> 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<MIDIPacket*>(0)->data);
#endif
static constexpr const uint32_t kMIDIPacketListNonDataSize = sizeof(MIDIPacketList)
#if __cplusplus >= 201103L
- sizeof(MIDIPacketList::packet);
#else
- sizeof(static_cast<MIDIPacketList*>(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), fUsingRenderListeners(false),
fParameterCount(fPlugin.getParameterCount()), fParameterCount(fPlugin.getParameterCount()),
fLastParameterValues(nullptr), fLastParameterValues(nullptr),
fBypassParameterIndex(UINT32_MAX)
fBypassParameterIndex(UINT32_MAX),
fResetParameterIndex(UINT32_MAX)
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
, fMidiEventCount(0) , fMidiEventCount(0)
#endif #endif
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
, fMidiOutputDataOffset(0)
#endif
#if DISTRHO_PLUGIN_WANT_PROGRAMS #if DISTRHO_PLUGIN_WANT_PROGRAMS
, fCurrentProgram(-1) , fCurrentProgram(-1)
, fLastFactoryProgram(0) , fLastFactoryProgram(0)
@@ -345,7 +366,7 @@ public:
, fStateCount(fPlugin.getStateCount()) , fStateCount(fPlugin.getStateCount())
#endif #endif
{ {
if (fParameterCount != 0)
if (fParameterCount != 0)
{ {
fLastParameterValues = new float[fParameterCount]; fLastParameterValues = new float[fParameterCount];
std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount); std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount);
@@ -354,8 +375,17 @@ public:
{ {
fLastParameterValues[i] = fPlugin.getParameterValue(i); fLastParameterValues[i] = fPlugin.getParameterValue(i);


if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass)
switch (fPlugin.getParameterDesignation(i))
{
case kParameterDesignationNull:
break;
case kParameterDesignationBypass:
fBypassParameterIndex = i; fBypassParameterIndex = i;
break;
case kParameterDesignationReset:
fResetParameterIndex = i;
break;
}
} }
} }


@@ -370,8 +400,10 @@ public:
#endif #endif


#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
if ((fMidiOutputPackets = static_cast<MIDIPacketList*>(std::malloc(kMIDIPacketListSize))) != nullptr)
std::memset(fMidiOutputPackets, 0, kMIDIPacketListSize);

std::memset(&fMidiOutput, 0, sizeof(fMidiOutput)); std::memset(&fMidiOutput, 0, sizeof(fMidiOutput));
std::memset(&fMidiOutputPackets, 0, sizeof(fMidiOutputPackets));
#endif #endif


#if DISTRHO_PLUGIN_WANT_PROGRAMS #if DISTRHO_PLUGIN_WANT_PROGRAMS
@@ -428,6 +460,10 @@ public:
reallocAudioBufferList(false); reallocAudioBufferList(false);
#endif #endif


#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
std::free(fMidiOutputPackets);
#endif

#if DISTRHO_PLUGIN_WANT_PROGRAMS #if DISTRHO_PLUGIN_WANT_PROGRAMS
for (uint32_t i=0; i<fProgramCount; ++i) for (uint32_t i=0; i<fProgramCount; ++i)
CFRelease(fFactoryPresetsData[i].presetName); CFRelease(fFactoryPresetsData[i].presetName);
@@ -451,7 +487,8 @@ public:
fMidiEventCount = 0; fMidiEventCount = 0;
#endif #endif
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
fMidiOutputPackets.numPackets = 0;
fMidiOutputDataOffset = 0;
fMidiOutputPackets->numPackets = 0;
#endif #endif
#if DISTRHO_PLUGIN_WANT_TIMEPOS #if DISTRHO_PLUGIN_WANT_TIMEPOS
fTimePosition.clear(); fTimePosition.clear();
@@ -635,7 +672,7 @@ public:
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
#if DISTRHO_PLUGIN_WANT_TIMEPOS #if DISTRHO_PLUGIN_WANT_TIMEPOS
outDataSize = sizeof(HostCallbackInfo); outDataSize = sizeof(HostCallbackInfo);
outWritable = false;
outWritable = true;
return noErr; return noErr;
#else #else
return kAudioUnitErr_InvalidProperty; return kAudioUnitErr_InvalidProperty;
@@ -659,6 +696,17 @@ public:
outWritable = true; outWritable = true;
return noErr; 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: case kAudioUnitProperty_CocoaUI:
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); 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(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
outDataSize = sizeof(uint16_t); outDataSize = sizeof(uint16_t);
outWritable = false;
outWritable = true;
return noErr; return noErr;


case 'DPFe': case 'DPFe':
@@ -739,7 +787,7 @@ public:
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
outDataSize = sizeof(uint32_t); outDataSize = sizeof(uint32_t);
outWritable = false;
outWritable = true;
return noErr; return noErr;
#endif #endif


@@ -748,7 +796,7 @@ public:
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
outDataSize = sizeof(CFArrayRef); outDataSize = sizeof(CFArrayRef);
outWritable = false;
outWritable = true;
return noErr; return noErr;


case 'DPFs': case 'DPFs':
@@ -764,7 +812,7 @@ public:
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
outDataSize = sizeof(void*); outDataSize = sizeof(void*);
outWritable = false;
outWritable = true;
return noErr; return noErr;
#endif #endif


@@ -885,13 +933,13 @@ public:
case kAudioUnitProperty_FastDispatch: case kAudioUnitProperty_FastDispatch:
switch (inElement) switch (inElement)
{ {
case kAudioUnitGetParameterSelect:
case kAudioUnitGetParameterSelect:
*static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter; *static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter;
return noErr; return noErr;
case kAudioUnitSetParameterSelect:
case kAudioUnitSetParameterSelect:
*static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter; *static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter;
return noErr; return noErr;
case kAudioUnitRenderSelect:
case kAudioUnitRenderSelect:
*static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender; *static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender;
return noErr; return noErr;
} }
@@ -1028,6 +1076,12 @@ public:
} }
return noErr; return noErr;


#if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE
case kAudioUnitProperty_SupportsMPE:
*static_cast<UInt32*>(outData) = 1;
return noErr;
#endif

#if DISTRHO_PLUGIN_HAS_UI #if DISTRHO_PLUGIN_HAS_UI
case kAudioUnitProperty_CocoaUI: case kAudioUnitProperty_CocoaUI:
{ {
@@ -1414,7 +1468,7 @@ public:
const float value = bypass ? 1.f : 0.f; const float value = bypass ? 1.f : 0.f;
fLastParameterValues[fBypassParameterIndex] = value; fLastParameterValues[fBypassParameterIndex] = value;
fPlugin.setParameterValue(fBypassParameterIndex, value); fPlugin.setParameterValue(fBypassParameterIndex, value);
notifyPropertyListeners(inProp, inScope, inElement);
notifyPropertyListeners(inProp, inScope, inElement);
} }
} }
return noErr; return noErr;
@@ -1436,12 +1490,12 @@ public:
#if DISTRHO_PLUGIN_WANT_TIMEPOS #if DISTRHO_PLUGIN_WANT_TIMEPOS
{ {
const UInt32 usableDataSize = std::min(inDataSize, static_cast<UInt32>(sizeof(HostCallbackInfo))); const UInt32 usableDataSize = std::min(inDataSize, static_cast<UInt32>(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) if (sizeof(HostCallbackInfo) > usableDataSize)
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize);
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize);


if (changed) if (changed)
notifyPropertyListeners(inProp, inScope, inElement); notifyPropertyListeners(inProp, inScope, inElement);
@@ -1568,7 +1622,7 @@ public:
AUEventListenerNotify(NULL, NULL, &event); AUEventListenerNotify(NULL, NULL, &event);


if (fBypassParameterIndex == inElement) if (fBypassParameterIndex == inElement)
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
} }
return noErr; 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(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope);
DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement); 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.deactivate();
fPlugin.activate(); fPlugin.activate();
@@ -1787,7 +1846,8 @@ public:
fMidiEventCount = 0; fMidiEventCount = 0;
#endif #endif
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
fMidiOutputPackets.numPackets = 0;
fMidiOutputDataOffset = 0;
fMidiOutputPackets->numPackets = 0;
#endif #endif
#if DISTRHO_PLUGIN_WANT_TIMEPOS #if DISTRHO_PLUGIN_WANT_TIMEPOS
fTimePosition.clear(); fTimePosition.clear();
@@ -2015,7 +2075,7 @@ public:
midiEvent.data[1] = inData1; midiEvent.data[1] = inData1;
midiEvent.data[2] = inData2; midiEvent.data[2] = inData2;


switch (inStatus)
switch (inStatus & 0xF0)
{ {
case 0x80: case 0x80:
case 0x90: case 0x90:
@@ -2057,6 +2117,8 @@ public:
break; break;
default: default:
// invalid // invalid
d_debug("auMIDIEvent received invalid event %u %u %u %u @ %u",
inStatus, inData1, inData2, inOffsetSampleFrame, fMidiEventCount);
return kAudioUnitErr_InvalidPropertyValue; return kAudioUnitErr_InvalidPropertyValue;
} }


@@ -2133,6 +2195,7 @@ private:
const uint32_t fParameterCount; const uint32_t fParameterCount;
float* fLastParameterValues; float* fLastParameterValues;
uint32_t fBypassParameterIndex; uint32_t fBypassParameterIndex;
uint32_t fResetParameterIndex;


#if DISTRHO_PLUGIN_WANT_MIDI_INPUT #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
uint32_t fMidiEventCount; uint32_t fMidiEventCount;
@@ -2141,8 +2204,9 @@ private:
#endif #endif


#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
uint32_t fMidiOutputDataOffset;
MIDIPacketList* fMidiOutputPackets;
AUMIDIOutputCallbackStruct fMidiOutput; AUMIDIOutputCallbackStruct fMidiOutput;
d_MIDIPacketList fMidiOutputPackets;
#endif #endif


#if DISTRHO_PLUGIN_WANT_PROGRAMS #if DISTRHO_PLUGIN_WANT_PROGRAMS
@@ -2172,7 +2236,7 @@ private:
const PropertyListener& pl(*it); const PropertyListener& pl(*it);


if (pl.prop == prop) 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 #endif


#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
fMidiOutputPackets.numPackets = 0;
fMidiOutputDataOffset = 0;
fMidiOutputPackets->numPackets = 0;
#endif #endif


#if DISTRHO_PLUGIN_WANT_TIMEPOS #if DISTRHO_PLUGIN_WANT_TIMEPOS
@@ -2294,12 +2359,11 @@ private:
#endif #endif


#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #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<const ::MIDIPacketList*>(&fMidiOutputPackets));
fMidiOutput.midiOutputCallback(fMidiOutput.userData, inTimeStamp, 0, fMidiOutputPackets);
} }
#else #else
// unused // unused
@@ -2716,17 +2780,21 @@ private:
bool writeMidi(const MidiEvent& midiEvent) bool writeMidi(const MidiEvent& midiEvent)
{ {
DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fMidiOutput.midiOutputCallback != nullptr, false); 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; return false;


const uint8_t* const midiData = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data; 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<MIDIPacket*>(
reinterpret_cast<uint8_t*>(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; return true;
} }


@@ -2793,7 +2861,7 @@ private:
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------


struct AudioComponentPlugInInstance { struct AudioComponentPlugInInstance {
AudioComponentPlugInInterface acpi;
AudioComponentPlugInInterface acpi;
PluginAU* plugin; PluginAU* plugin;


AudioComponentPlugInInstance() noexcept AudioComponentPlugInInstance() noexcept
@@ -2802,9 +2870,9 @@ struct AudioComponentPlugInInstance {
{ {
std::memset(&acpi, 0, sizeof(acpi)); std::memset(&acpi, 0, sizeof(acpi));
acpi.Open = Open; acpi.Open = Open;
acpi.Close = Close;
acpi.Lookup = Lookup;
acpi.reserved = nullptr;
acpi.Close = Close;
acpi.Lookup = Lookup;
acpi.reserved = nullptr;
} }


~AudioComponentPlugInInstance() ~AudioComponentPlugInInstance()
@@ -2812,14 +2880,18 @@ struct AudioComponentPlugInInstance {
delete plugin; 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<AudioComponentPlugInInstance*>(self)->plugin = new PluginAU(component); static_cast<AudioComponentPlugInInstance*>(self)->plugin = new PluginAU(component);
return noErr; return noErr;
} }


static OSStatus Close(void* const self)
static OSStatus Close(void* const self)
{ {
d_debug("AudioComponentPlugInInstance::Close(%p)", self);

delete static_cast<AudioComponentPlugInInstance*>(self); delete static_cast<AudioComponentPlugInInstance*>(self);
return noErr; return noErr;
} }
@@ -2908,15 +2980,15 @@ struct AudioComponentPlugInInstance {
d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)", d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)",
self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); 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); 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; return res;
} }
@@ -2928,8 +3000,16 @@ struct AudioComponentPlugInInstance {
void* const outData, void* const outData,
UInt32* const ioDataSize) 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); DISTRHO_SAFE_ASSERT_RETURN(ioDataSize != nullptr, kAudio_ParamError);


Boolean writable; Boolean writable;
@@ -2952,24 +3032,24 @@ struct AudioComponentPlugInInstance {
if (res != noErr) if (res != noErr)
return res; return res;


void* outBuffer;
void* outBuffer;
uint8_t* tmpBuffer; uint8_t* tmpBuffer;
if (inDataSize < outDataSize) if (inDataSize < outDataSize)
{
tmpBuffer = new uint8_t[outDataSize];
outBuffer = tmpBuffer;
}
{
tmpBuffer = new uint8_t[outDataSize];
outBuffer = tmpBuffer;
}
else else
{ {
tmpBuffer = nullptr;
outBuffer = outData;
}
tmpBuffer = nullptr;
outBuffer = outData;
}


res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer); res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer);


if (res != noErr)
if (res != noErr)
{ {
*ioDataSize = 0;
*ioDataSize = 0;
return res; return res;
} }




+ 58
- 11
distrho/src/DistrhoPluginCLAP.cpp View File

@@ -751,6 +751,7 @@ public:
updateStateValueCallback), updateStateValueCallback),
fHost(host), fHost(host),
fOutputEvents(nullptr), fOutputEvents(nullptr),
fResetParameterIndex(UINT32_MAX),
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0
fUsingCV(false), fUsingCV(false),
#endif #endif
@@ -763,7 +764,19 @@ public:
#endif #endif
fHostExtensions(host) fHostExtensions(host)
{ {
fCachedParameters.setup(fPlugin.getParameterCount());
if (const uint32_t paramCount = fPlugin.getParameterCount())
{
fCachedParameters.setup(paramCount);

for (uint32_t i=0; i<paramCount; ++i)
{
if (fPlugin.getParameterDesignation(i) == kParameterDesignationReset)
{
fResetParameterIndex = i;
break;
}
}
}


#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT
fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true); fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true);
@@ -821,6 +834,22 @@ public:
#endif #endif
} }


void reset()
{
if (fResetParameterIndex != UINT32_MAX)
{
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fMidiEventCount = 0;
#endif
fPlugin.setParameterValue(fResetParameterIndex, 1.f);
fPlugin.setParameterValue(fResetParameterIndex, 0.f);
}
else
{
fHost->request_restart(fHost);
}
}

bool process(const clap_process_t* const process) bool process(const clap_process_t* const process)
{ {
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
@@ -1114,14 +1143,19 @@ public:
{ {
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); 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; info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_BYPASS|CLAP_PARAM_IS_AUTOMATABLE;
std::strcpy(info->name, "Bypass"); std::strcpy(info->name, "Bypass");
std::strcpy(info->module, "dpf_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 hints = fPlugin.getParameterHints(index);
const uint32_t groupId = fPlugin.getParameterGroupId(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); d_strncpy(info->module + wrtn, fPlugin.getParameterSymbol(index), CLAP_PATH_SIZE - wrtn);
break;
} }


info->id = index; info->id = index;
@@ -1786,6 +1821,7 @@ private:
const clap_host_t* const fHost; const clap_host_t* const fHost;
const clap_output_events_t* fOutputEvents; const clap_output_events_t* fOutputEvents;


uint32_t fResetParameterIndex;
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 #if DISTRHO_PLUGIN_NUM_INPUTS != 0
const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS];
#endif #endif
@@ -2284,23 +2320,33 @@ static bool CLAP_ABI clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t,
{ {
if (is_input) if (is_input)
{ {
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
info->id = 0; 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->supported_dialects = CLAP_NOTE_DIALECT_MIDI;
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
#endif
std::strcpy(info->name, "Event/MIDI Input"); std::strcpy(info->name, "Event/MIDI Input");
return true; return true;
#endif
#endif
} }
else else
{ {
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
info->id = 0; 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->supported_dialects = CLAP_NOTE_DIALECT_MIDI;
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI;
#endif
std::strcpy(info->name, "Event/MIDI Output"); std::strcpy(info->name, "Event/MIDI Output");
return true; return true;
#endif
#endif
} }


return false; return false;
@@ -2440,9 +2486,10 @@ static void CLAP_ABI clap_plugin_stop_processing(const clap_plugin_t*)
// nothing to do // 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<PluginCLAP*>(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) static clap_process_status CLAP_ABI clap_plugin_process(const clap_plugin_t* const plugin, const clap_process_t* const process)


+ 11
- 0
distrho/src/DistrhoPluginChecks.h View File

@@ -65,6 +65,10 @@
# define DISTRHO_PLUGIN_WANT_LATENCY 0 # define DISTRHO_PLUGIN_WANT_LATENCY 0
#endif #endif


#ifndef DISTRHO_PLUGIN_WANT_MIDI_AS_MPE
# define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0
#endif

#ifndef DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #ifndef DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
# define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 # define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0
#endif #endif
@@ -178,6 +182,13 @@
# error Synths need audio output to work! # error Synths need audio output to work!
#endif #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 // Enable MIDI input if synth, test if midi-input disabled when synth




+ 10
- 0
distrho/src/DistrhoPluginLV2export.cpp View File

@@ -758,6 +758,16 @@ void lv2_generate_ttl(const char* const basename)
pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n";
pluginString += " lv2:designation lv2:enabled ;\n"; pluginString += " lv2:designation lv2:enabled ;\n";
break; 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;
} }
} }




+ 6
- 0
distrho/src/DistrhoPluginVST3.cpp View File

@@ -1763,6 +1763,12 @@ public:
case kParameterDesignationBypass: case kParameterDesignationBypass:
flags |= V3_PARAM_IS_BYPASS; flags |= V3_PARAM_IS_BYPASS;
break; 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) if (hints & kParameterIsOutput)


+ 3
- 0
distrho/src/DistrhoUIAU.mm View File

@@ -387,6 +387,9 @@ END_NAMESPACE_DISTRHO
#define COCOA_VIEW_CLASS_NAME \ #define COCOA_VIEW_CLASS_NAME \
MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID) 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 @interface COCOA_VIEW_CLASS_NAME : NSView
{ {
@public @public


+ 2
- 2
distrho/src/DistrhoUIInternal.hpp View File

@@ -267,12 +267,12 @@ public:
uiData->app.repaintIfNeeeded(); 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); uiData->window->addIdleCallback(cb, timerFrequencyInMs);
} }


void removeIdleCallbackForNativeIdle(IdleCallback* const cb)
void removeIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb)
{ {
uiData->window->removeIdleCallback(cb); uiData->window->removeIdleCallback(cb);
} }


+ 1
- 1
distrho/src/DistrhoUIVST3.cpp View File

@@ -129,7 +129,7 @@ static uint translateVST3Modifiers(const int64_t modifiers) noexcept
* Helper class for getting a native idle timer. * Helper class for getting a native idle timer.
*/ */
#if !DPF_VST3_USING_HOST_RUN_LOOP #if !DPF_VST3_USING_HOST_RUN_LOOP
class NativeIdleCallback : public IdleCallback
class NativeIdleCallback : public DGL_NAMESPACE::IdleCallback
{ {
public: public:
NativeIdleCallback(UIExporter& ui) NativeIdleCallback(UIExporter& ui)


+ 2
- 1
distrho/src/lv2/lv2_kxstudio_properties.h View File

@@ -1,6 +1,6 @@
/* /*
LV2 KXStudio Properties Extension LV2 KXStudio Properties Extension
Copyright 2014-2021 Filipe Coelho <falktx@falktx.com>
Copyright 2014-2024 Filipe Coelho <falktx@falktx.com>


Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above 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_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#"


#define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable" #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__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat"
#define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" #define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId"




Loading…
Cancel
Save