@@ -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 | ||||
@@ -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: | ||||
@@ -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 }} |
@@ -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/ |
@@ -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: | ||||
@@ -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; | ||||
@@ -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); | ||||
@@ -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, | ||||
@@ -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); | ||||
@@ -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; | ||||
} | } | ||||
@@ -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; | |||||
} | } | ||||
} | } | ||||
@@ -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. | ||||
@@ -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. | ||||
*/ | */ | ||||
@@ -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; | ||||
@@ -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; | ||||
} | } | ||||
@@ -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) | ||||
@@ -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 | ||||
@@ -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; | |||||
} | } | ||||
} | } | ||||
@@ -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) | ||||
@@ -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 | ||||
@@ -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); | ||||
} | } | ||||
@@ -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) | ||||
@@ -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" | ||||