@@ -13,10 +13,9 @@ jobs: | |||
strategy: | |||
matrix: | |||
os: | |||
# wrong use of AU MIDIPacket | |||
# - macos-12 | |||
# - macos-13 | |||
# - macos-14 | |||
- macos-13 | |||
- macos-14 | |||
- macos-15 | |||
# webgui failure | |||
# - ubuntu-20.04 | |||
- ubuntu-22.04 | |||
@@ -42,11 +42,11 @@ jobs: | |||
suffix: _24_04 | |||
target: ${{ matrix.target }} | |||
macos-12: | |||
macos-13: | |||
strategy: | |||
matrix: | |||
target: [macos-intel, macos-universal, macos-10.15] | |||
runs-on: macos-12 | |||
runs-on: macos-13 | |||
steps: | |||
- uses: actions/checkout@v4 | |||
with: | |||
@@ -54,14 +54,14 @@ jobs: | |||
- uses: distrho/dpf-cmake-action@v1 | |||
with: | |||
dpf_path: . | |||
suffix: _12 | |||
suffix: _13 | |||
target: ${{ matrix.target }} | |||
macos-13: | |||
macos-14: | |||
strategy: | |||
matrix: | |||
target: [macos-intel, macos-universal, macos-10.15] | |||
runs-on: macos-13 | |||
runs-on: macos-14 | |||
steps: | |||
- uses: actions/checkout@v4 | |||
with: | |||
@@ -69,14 +69,14 @@ jobs: | |||
- uses: distrho/dpf-cmake-action@v1 | |||
with: | |||
dpf_path: . | |||
suffix: _13 | |||
suffix: _14 | |||
target: ${{ matrix.target }} | |||
macos-14: | |||
macos-15: | |||
strategy: | |||
matrix: | |||
target: [macos-intel, macos-universal, macos-10.15] | |||
runs-on: macos-14 | |||
runs-on: macos-15 | |||
steps: | |||
- uses: actions/checkout@v4 | |||
with: | |||
@@ -84,7 +84,7 @@ jobs: | |||
- uses: distrho/dpf-cmake-action@v1 | |||
with: | |||
dpf_path: . | |||
suffix: _14 | |||
suffix: _15 | |||
target: ${{ matrix.target }} | |||
cmake_win32: | |||
@@ -39,11 +39,11 @@ jobs: | |||
suffix: _24_04 | |||
target: ${{ matrix.target }} | |||
macos-12: | |||
macos-13: | |||
strategy: | |||
matrix: | |||
target: [macos-intel, macos-universal, macos-10.15] | |||
runs-on: macos-12 | |||
runs-on: macos-13 | |||
steps: | |||
- uses: actions/checkout@v4 | |||
with: | |||
@@ -51,14 +51,14 @@ jobs: | |||
- uses: distrho/dpf-makefile-action@v1 | |||
with: | |||
dpf_path: . | |||
suffix: _12 | |||
suffix: _13 | |||
target: ${{ matrix.target }} | |||
macos-13: | |||
macos-14: | |||
strategy: | |||
matrix: | |||
target: [macos-intel, macos-universal, macos-10.15] | |||
runs-on: macos-13 | |||
runs-on: macos-14 | |||
steps: | |||
- uses: actions/checkout@v4 | |||
with: | |||
@@ -66,14 +66,14 @@ jobs: | |||
- uses: distrho/dpf-makefile-action@v1 | |||
with: | |||
dpf_path: . | |||
suffix: _13 | |||
suffix: _14 | |||
target: ${{ matrix.target }} | |||
macos-14: | |||
macos-15: | |||
strategy: | |||
matrix: | |||
target: [macos-intel, macos-universal, macos-10.15] | |||
runs-on: macos-14 | |||
runs-on: macos-15 | |||
steps: | |||
- uses: actions/checkout@v4 | |||
with: | |||
@@ -81,5 +81,5 @@ jobs: | |||
- uses: distrho/dpf-makefile-action@v1 | |||
with: | |||
dpf_path: . | |||
suffix: _14 | |||
suffix: _15 | |||
target: ${{ matrix.target }} |
@@ -15,8 +15,9 @@ CMakeFiles | |||
CMakeSettings.json | |||
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 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: | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -63,6 +63,9 @@ public: | |||
bool isCheckable() const noexcept; | |||
void setCheckable(bool checkable) noexcept; | |||
bool isEnabled() const noexcept; | |||
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; | |||
Point<double> getLastClickPosition() const noexcept; | |||
Point<double> getLastMotionPosition() const noexcept; | |||
@@ -121,6 +124,9 @@ public: | |||
KnobEventHandler& operator=(const KnobEventHandler& other); | |||
virtual ~KnobEventHandler(); | |||
bool isEnabled() const noexcept; | |||
void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; | |||
// if setStep(1) has been called before, this returns true | |||
bool isInteger() const noexcept; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -31,6 +31,8 @@ struct ButtonEventHandler::PrivateData { | |||
int state; | |||
bool checkable; | |||
bool checked; | |||
bool enabled; | |||
bool enabledInput; | |||
Point<double> lastClickPos; | |||
Point<double> lastMotionPos; | |||
@@ -44,11 +46,16 @@ struct ButtonEventHandler::PrivateData { | |||
state(kButtonStateDefault), | |||
checkable(false), | |||
checked(false), | |||
enabled(true), | |||
enabledInput(true), | |||
lastClickPos(0, 0), | |||
lastMotionPos(0, 0) {} | |||
bool mouseEvent(const Widget::MouseEvent& ev) | |||
{ | |||
if (! enabledInput) | |||
return false; | |||
lastClickPos = ev.pos; | |||
// button was released, handle it now | |||
@@ -98,6 +105,9 @@ struct ButtonEventHandler::PrivateData { | |||
bool motionEvent(const Widget::MotionEvent& ev) | |||
{ | |||
if (! enabledInput) | |||
return false; | |||
// keep pressed | |||
if (button != -1) | |||
{ | |||
@@ -171,6 +181,27 @@ struct ButtonEventHandler::PrivateData { | |||
} | |||
} | |||
void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept | |||
{ | |||
if (appliesToEventInput) | |||
enabledInput = enabled2; | |||
if (enabled == enabled2) | |||
return; | |||
// reset temp vars if disabling | |||
if (! enabled2) | |||
{ | |||
button = -1; | |||
state = kButtonStateDefault; | |||
lastClickPos = Point<double>(); | |||
lastMotionPos = Point<double>(); | |||
} | |||
enabled = enabled2; | |||
widget->repaint(); | |||
} | |||
DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | |||
}; | |||
@@ -217,6 +248,16 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept | |||
pData->checkable = checkable; | |||
} | |||
bool ButtonEventHandler::isEnabled() const noexcept | |||
{ | |||
return pData->enabled; | |||
} | |||
void ButtonEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept | |||
{ | |||
pData->setEnabled(enabled, appliesToEventInput); | |||
} | |||
Point<double> ButtonEventHandler::getLastClickPosition() const noexcept | |||
{ | |||
return pData->lastClickPos; | |||
@@ -281,6 +322,8 @@ struct KnobEventHandler::PrivateData { | |||
float value; | |||
float valueDef; | |||
float valueTmp; | |||
bool enabled; | |||
bool enabledInput; | |||
bool usingDefault; | |||
bool usingLog; | |||
Orientation orientation; | |||
@@ -301,6 +344,8 @@ struct KnobEventHandler::PrivateData { | |||
value(0.5f), | |||
valueDef(value), | |||
valueTmp(value), | |||
enabled(true), | |||
enabledInput(true), | |||
usingDefault(false), | |||
usingLog(false), | |||
orientation(Vertical), | |||
@@ -320,6 +365,8 @@ struct KnobEventHandler::PrivateData { | |||
value(other->value), | |||
valueDef(other->valueDef), | |||
valueTmp(value), | |||
enabled(other->enabled), | |||
enabledInput(other->enabledInput), | |||
usingDefault(other->usingDefault), | |||
usingLog(other->usingLog), | |||
orientation(other->orientation), | |||
@@ -338,6 +385,8 @@ struct KnobEventHandler::PrivateData { | |||
value = other->value; | |||
valueDef = other->valueDef; | |||
valueTmp = value; | |||
enabled = other->enabled; | |||
enabledInput = other->enabledInput; | |||
usingDefault = other->usingDefault; | |||
usingLog = other->usingLog; | |||
orientation = other->orientation; | |||
@@ -363,6 +412,9 @@ struct KnobEventHandler::PrivateData { | |||
bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor) | |||
{ | |||
if (! enabledInput) | |||
return false; | |||
if (ev.button != 1) | |||
return false; | |||
@@ -416,6 +468,9 @@ struct KnobEventHandler::PrivateData { | |||
bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor) | |||
{ | |||
if (! enabledInput) | |||
return false; | |||
if ((state & kKnobStateDragging) == 0x0) | |||
return false; | |||
@@ -501,6 +556,9 @@ struct KnobEventHandler::PrivateData { | |||
bool scrollEvent(const Widget::ScrollEvent& ev) | |||
{ | |||
if (! enabledInput) | |||
return false; | |||
if (! widget->contains(ev.pos)) | |||
return false; | |||
@@ -541,6 +599,28 @@ struct KnobEventHandler::PrivateData { | |||
return ((usingLog ? invlogscale(value) : value) - minimum) / diff; | |||
} | |||
void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept | |||
{ | |||
if (appliesToEventInput) | |||
enabledInput = enabled2; | |||
if (enabled == enabled2) | |||
return; | |||
// reset temp vars if disabling | |||
if (! enabled2) | |||
{ | |||
state = kKnobStateDefault; | |||
lastX = 0.0; | |||
lastY = 0.0; | |||
lastClickTime = 0; | |||
valueTmp = value; | |||
} | |||
enabled = enabled2; | |||
widget->repaint(); | |||
} | |||
void setRange(const float min, const float max) noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(max > min,); | |||
@@ -598,6 +678,16 @@ KnobEventHandler::~KnobEventHandler() | |||
delete pData; | |||
} | |||
bool KnobEventHandler::isEnabled() const noexcept | |||
{ | |||
return pData->enabled; | |||
} | |||
void KnobEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept | |||
{ | |||
pData->setEnabled(enabled, appliesToEventInput); | |||
} | |||
bool KnobEventHandler::isInteger() const noexcept | |||
{ | |||
return d_isEqual(pData->step, 1.f); | |||
@@ -579,11 +579,11 @@ void Window::PrivateData::runAsModal(const bool blockWait) | |||
// ----------------------------------------------------------------------- | |||
// pugl events | |||
void Window::PrivateData::onPuglConfigure(const double width, const double height) | |||
void Window::PrivateData::onPuglConfigure(const uint width, const uint height) | |||
{ | |||
DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,); | |||
DGL_DBGp("PUGL: onReshape : %f %f\n", width, height); | |||
DGL_DBGp("PUGL: onReshape : %d %d\n", width, height); | |||
if (autoScaling) | |||
{ | |||
@@ -1188,25 +1188,21 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver | |||
if (verbose) { | |||
switch (event->type) { | |||
case PUGL_CREATE: | |||
return fprintf(stderr, "%sCreate\n", prefix); | |||
case PUGL_DESTROY: | |||
return fprintf(stderr, "%sDestroy\n", prefix); | |||
case PUGL_MAP: | |||
return fprintf(stderr, "%sMap\n", prefix); | |||
case PUGL_UNMAP: | |||
return fprintf(stderr, "%sUnmap\n", prefix); | |||
case PUGL_UPDATE: | |||
return 0; // fprintf(stderr, "%sUpdate\n", prefix); | |||
case PUGL_REALIZE: | |||
return PRINT("%sRealize\n", prefix); | |||
case PUGL_UNREALIZE: | |||
return PRINT("%sUnrealize\n", prefix); | |||
case PUGL_CONFIGURE: | |||
return PRINT("%sConfigure " PFMT " " PFMT "\n", | |||
return PRINT("%sConfigure %d %d %d %d\n", | |||
prefix, | |||
event->configure.x, | |||
event->configure.y, | |||
event->configure.width, | |||
event->configure.height); | |||
case PUGL_UPDATE: | |||
return 0; // fprintf(stderr, "%sUpdate\n", prefix); | |||
case PUGL_EXPOSE: | |||
return PRINT("%sExpose " PFMT " " PFMT "\n", | |||
return PRINT("%sExpose %d %d %d %d\n", | |||
prefix, | |||
event->expose.x, | |||
event->expose.y, | |||
@@ -181,7 +181,7 @@ struct Window::PrivateData : IdleCallback { | |||
void runAsModal(bool blockWait); | |||
// pugl events | |||
void onPuglConfigure(double width, double height); | |||
void onPuglConfigure(uint width, uint height); | |||
void onPuglExpose(); | |||
void onPuglClose(); | |||
void onPuglFocus(bool focus, CrossingMode mode); | |||
@@ -363,7 +363,8 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height) | |||
#ifdef DGL_USING_X11 | |||
// workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118 | |||
if (view->impl->win && !view->parent && !view->transientParent) | |||
// NOTE troublesome if used under wayland | |||
if (view->impl->win && !view->parent && !view->transientParent && std::getenv("WAYLAND_DISPLAY") == nullptr) | |||
{ | |||
view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0; | |||
} | |||
@@ -202,7 +202,7 @@ static constexpr const uint32_t kStateIsOnlyForUI = 0x20; | |||
/** | |||
Parameter designation.@n | |||
Allows a parameter to be specially designated for a task, like bypass. | |||
Allows a parameter to be specially designated for a task, like bypass and reset. | |||
Each designation is unique, there must be only one parameter that uses it.@n | |||
The use of designated parameters is completely optional. | |||
@@ -214,13 +214,20 @@ enum ParameterDesignation { | |||
/** | |||
Null or unset designation. | |||
*/ | |||
kParameterDesignationNull = 0, | |||
kParameterDesignationNull, | |||
/** | |||
Bypass designation.@n | |||
When on (> 0.5f), it means the plugin must run in a bypassed state. | |||
*/ | |||
kParameterDesignationBypass = 1 | |||
kParameterDesignationBypass, | |||
/** | |||
Reset designation.@n | |||
When on (> 0.5f), it means the plugin should reset its internal processing state | |||
(like filters, oscillators, envelopes, lfos, etc) and kill all voices. | |||
*/ | |||
kParameterDesignationReset, | |||
}; | |||
/** | |||
@@ -234,7 +241,12 @@ namespace ParameterDesignationSymbols { | |||
static constexpr const char bypass[] = "dpf_bypass"; | |||
/** | |||
Bypass designation symbol, inverted for LV2 so it becomes "enabled". | |||
Reset designation symbol. | |||
*/ | |||
static constexpr const char reset[] = "dpf_reset"; | |||
/** | |||
LV2 bypass designation symbol, inverted for LV2 so it becomes "enabled". | |||
*/ | |||
static constexpr const char bypass_lv2[] = "lv2_enabled"; | |||
}; | |||
@@ -728,6 +740,18 @@ struct Parameter { | |||
ranges.min = 0.0f; | |||
ranges.max = 1.0f; | |||
break; | |||
case kParameterDesignationReset: | |||
hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger|kParameterIsTrigger; | |||
name = "Reset"; | |||
shortName = "Reset"; | |||
symbol = ParameterDesignationSymbols::reset; | |||
unit = ""; | |||
midiCC = 0; | |||
groupId = kPortGroupNone; | |||
ranges.def = 0.0f; | |||
ranges.min = 0.0f; | |||
ranges.max = 1.0f; | |||
break; | |||
} | |||
} | |||
@@ -553,6 +553,12 @@ START_NAMESPACE_DISTRHO | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
/** | |||
Whether the plugin wants MPE for MIDI input and/or output. | |||
@note Only AU and CLAP formats implement this at the moment | |||
*/ | |||
#define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0 | |||
/** | |||
Whether the plugin wants MIDI input.@n | |||
This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. | |||
@@ -22,6 +22,10 @@ | |||
#include <algorithm> | |||
#if __cplusplus >= 201703L | |||
# include <string_view> | |||
#endif | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
@@ -49,10 +53,7 @@ public: | |||
fBufferLen(0), | |||
fBufferAlloc(false) | |||
{ | |||
char ch[2]; | |||
ch[0] = c; | |||
ch[1] = '\0'; | |||
const char ch[2] = { c, '\0' }; | |||
_dup(ch); | |||
} | |||
@@ -87,6 +88,19 @@ public: | |||
_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. | |||
*/ | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -106,7 +106,7 @@ | |||
@implementation WEB_VIEW_DELEGATE_CLASS_NAME { | |||
@public | |||
WebViewMessageCallback callback; | |||
DISTRHO_NAMESPACE::WebViewMessageCallback callback; | |||
void* callbackPtr; | |||
bool loaded; | |||
} | |||
@@ -1039,7 +1039,9 @@ static bool gtk3(Display* const display, | |||
{ | |||
void* lib; | |||
if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | |||
(lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr) | |||
(lib = dlopen("libwebkit2gtk-4.1.so.0", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | |||
(lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | |||
(lib = dlopen("libwebkit2gtk-4.1.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr) | |||
{ | |||
d_stdout("WebView gtk3 platform not available: %s", dlerror()); | |||
return false; | |||
@@ -202,7 +202,8 @@ static constexpr const uint32_t kType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_AU_TYP | |||
static constexpr const uint32_t kSubType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)); | |||
static constexpr const uint32_t kManufacturer = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID)); | |||
static constexpr const uint32_t kWantedAudioFormat = kAudioFormatFlagsNativeFloatPacked | |||
static constexpr const uint32_t kWantedAudioFormat = 0 | |||
| kAudioFormatFlagsNativeFloatPacked | |||
| kAudioFormatFlagIsNonInterleaved; | |||
@@ -263,7 +264,7 @@ bool isNumChannelsComboValid(const uint16_t numInputs, const uint16_t numOutputs | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
struct PropertyListener { | |||
AudioUnitPropertyID prop; | |||
AudioUnitPropertyID prop; | |||
AudioUnitPropertyListenerProc proc; | |||
void* userData; | |||
}; | |||
@@ -276,12 +277,28 @@ struct RenderListener { | |||
typedef std::vector<PropertyListener> PropertyListeners; | |||
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), | |||
fParameterCount(fPlugin.getParameterCount()), | |||
fLastParameterValues(nullptr), | |||
fBypassParameterIndex(UINT32_MAX) | |||
fBypassParameterIndex(UINT32_MAX), | |||
fResetParameterIndex(UINT32_MAX) | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
, fMidiEventCount(0) | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
, fMidiOutputDataOffset(0) | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
, fCurrentProgram(-1) | |||
, fLastFactoryProgram(0) | |||
@@ -345,7 +366,7 @@ public: | |||
, fStateCount(fPlugin.getStateCount()) | |||
#endif | |||
{ | |||
if (fParameterCount != 0) | |||
if (fParameterCount != 0) | |||
{ | |||
fLastParameterValues = new float[fParameterCount]; | |||
std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount); | |||
@@ -354,8 +375,17 @@ public: | |||
{ | |||
fLastParameterValues[i] = fPlugin.getParameterValue(i); | |||
if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) | |||
switch (fPlugin.getParameterDesignation(i)) | |||
{ | |||
case kParameterDesignationNull: | |||
break; | |||
case kParameterDesignationBypass: | |||
fBypassParameterIndex = i; | |||
break; | |||
case kParameterDesignationReset: | |||
fResetParameterIndex = i; | |||
break; | |||
} | |||
} | |||
} | |||
@@ -370,8 +400,10 @@ public: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
if ((fMidiOutputPackets = static_cast<MIDIPacketList*>(std::malloc(kMIDIPacketListSize))) != nullptr) | |||
std::memset(fMidiOutputPackets, 0, kMIDIPacketListSize); | |||
std::memset(&fMidiOutput, 0, sizeof(fMidiOutput)); | |||
std::memset(&fMidiOutputPackets, 0, sizeof(fMidiOutputPackets)); | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
@@ -428,6 +460,10 @@ public: | |||
reallocAudioBufferList(false); | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
std::free(fMidiOutputPackets); | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
for (uint32_t i=0; i<fProgramCount; ++i) | |||
CFRelease(fFactoryPresetsData[i].presetName); | |||
@@ -451,7 +487,8 @@ public: | |||
fMidiEventCount = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
fMidiOutputPackets.numPackets = 0; | |||
fMidiOutputDataOffset = 0; | |||
fMidiOutputPackets->numPackets = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
fTimePosition.clear(); | |||
@@ -635,7 +672,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
outDataSize = sizeof(HostCallbackInfo); | |||
outWritable = false; | |||
outWritable = true; | |||
return noErr; | |||
#else | |||
return kAudioUnitErr_InvalidProperty; | |||
@@ -659,6 +696,17 @@ public: | |||
outWritable = true; | |||
return noErr; | |||
case kAudioUnitProperty_SupportsMPE: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
#if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
outDataSize = sizeof(UInt32); | |||
outWritable = false; | |||
return noErr; | |||
#else | |||
return kAudioUnitErr_InvalidProperty; | |||
#endif | |||
case kAudioUnitProperty_CocoaUI: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
@@ -708,7 +756,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
outDataSize = sizeof(uint16_t); | |||
outWritable = false; | |||
outWritable = true; | |||
return noErr; | |||
case 'DPFe': | |||
@@ -739,7 +787,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
outDataSize = sizeof(uint32_t); | |||
outWritable = false; | |||
outWritable = true; | |||
return noErr; | |||
#endif | |||
@@ -748,7 +796,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
outDataSize = sizeof(CFArrayRef); | |||
outWritable = false; | |||
outWritable = true; | |||
return noErr; | |||
case 'DPFs': | |||
@@ -764,7 +812,7 @@ public: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
outDataSize = sizeof(void*); | |||
outWritable = false; | |||
outWritable = true; | |||
return noErr; | |||
#endif | |||
@@ -885,13 +933,13 @@ public: | |||
case kAudioUnitProperty_FastDispatch: | |||
switch (inElement) | |||
{ | |||
case kAudioUnitGetParameterSelect: | |||
case kAudioUnitGetParameterSelect: | |||
*static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter; | |||
return noErr; | |||
case kAudioUnitSetParameterSelect: | |||
case kAudioUnitSetParameterSelect: | |||
*static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter; | |||
return noErr; | |||
case kAudioUnitRenderSelect: | |||
case kAudioUnitRenderSelect: | |||
*static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender; | |||
return noErr; | |||
} | |||
@@ -1028,6 +1076,12 @@ public: | |||
} | |||
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 | |||
case kAudioUnitProperty_CocoaUI: | |||
{ | |||
@@ -1414,7 +1468,7 @@ public: | |||
const float value = bypass ? 1.f : 0.f; | |||
fLastParameterValues[fBypassParameterIndex] = value; | |||
fPlugin.setParameterValue(fBypassParameterIndex, value); | |||
notifyPropertyListeners(inProp, inScope, inElement); | |||
notifyPropertyListeners(inProp, inScope, inElement); | |||
} | |||
} | |||
return noErr; | |||
@@ -1436,12 +1490,12 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
{ | |||
const UInt32 usableDataSize = std::min(inDataSize, static_cast<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) | |||
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); | |||
std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); | |||
if (changed) | |||
notifyPropertyListeners(inProp, inScope, inElement); | |||
@@ -1568,7 +1622,7 @@ public: | |||
AUEventListenerNotify(NULL, NULL, &event); | |||
if (fBypassParameterIndex == inElement) | |||
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); | |||
notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); | |||
} | |||
return noErr; | |||
@@ -1777,7 +1831,12 @@ public: | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope); | |||
DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement); | |||
if (fPlugin.isActive()) | |||
if (fResetParameterIndex != UINT32_MAX) | |||
{ | |||
fPlugin.setParameterValue(fResetParameterIndex, 1.f); | |||
fPlugin.setParameterValue(fResetParameterIndex, 0.f); | |||
} | |||
else if (fPlugin.isActive()) | |||
{ | |||
fPlugin.deactivate(); | |||
fPlugin.activate(); | |||
@@ -1787,7 +1846,8 @@ public: | |||
fMidiEventCount = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
fMidiOutputPackets.numPackets = 0; | |||
fMidiOutputDataOffset = 0; | |||
fMidiOutputPackets->numPackets = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
fTimePosition.clear(); | |||
@@ -2015,7 +2075,7 @@ public: | |||
midiEvent.data[1] = inData1; | |||
midiEvent.data[2] = inData2; | |||
switch (inStatus) | |||
switch (inStatus & 0xF0) | |||
{ | |||
case 0x80: | |||
case 0x90: | |||
@@ -2057,6 +2117,8 @@ public: | |||
break; | |||
default: | |||
// invalid | |||
d_debug("auMIDIEvent received invalid event %u %u %u %u @ %u", | |||
inStatus, inData1, inData2, inOffsetSampleFrame, fMidiEventCount); | |||
return kAudioUnitErr_InvalidPropertyValue; | |||
} | |||
@@ -2133,6 +2195,7 @@ private: | |||
const uint32_t fParameterCount; | |||
float* fLastParameterValues; | |||
uint32_t fBypassParameterIndex; | |||
uint32_t fResetParameterIndex; | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
uint32_t fMidiEventCount; | |||
@@ -2141,8 +2204,9 @@ private: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
uint32_t fMidiOutputDataOffset; | |||
MIDIPacketList* fMidiOutputPackets; | |||
AUMIDIOutputCallbackStruct fMidiOutput; | |||
d_MIDIPacketList fMidiOutputPackets; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
@@ -2172,7 +2236,7 @@ private: | |||
const PropertyListener& pl(*it); | |||
if (pl.prop == prop) | |||
pl.proc(pl.userData, fComponent, prop, scope, elem); | |||
pl.proc(pl.userData, fComponent, prop, scope, elem); | |||
} | |||
} | |||
@@ -2217,7 +2281,8 @@ private: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
fMidiOutputPackets.numPackets = 0; | |||
fMidiOutputDataOffset = 0; | |||
fMidiOutputPackets->numPackets = 0; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
@@ -2294,12 +2359,11 @@ private: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
if (fMidiOutputPackets.numPackets != 0 && fMidiOutput.midiOutputCallback != nullptr) | |||
if (fMidiOutputPackets != nullptr && | |||
fMidiOutputPackets->numPackets != 0 && | |||
fMidiOutput.midiOutputCallback != nullptr) | |||
{ | |||
fMidiOutput.midiOutputCallback(fMidiOutput.userData, | |||
inTimeStamp, | |||
0, | |||
reinterpret_cast<const ::MIDIPacketList*>(&fMidiOutputPackets)); | |||
fMidiOutput.midiOutputCallback(fMidiOutput.userData, inTimeStamp, 0, fMidiOutputPackets); | |||
} | |||
#else | |||
// unused | |||
@@ -2716,17 +2780,21 @@ private: | |||
bool writeMidi(const MidiEvent& midiEvent) | |||
{ | |||
DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fMidiOutput.midiOutputCallback != nullptr, false); | |||
DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("Out of memory", fMidiOutputPackets != nullptr, false); | |||
if (midiEvent.size > sizeof(MIDIPacket::data)) | |||
return true; | |||
if (fMidiOutputPackets.numPackets == kMaxMidiEvents) | |||
if (fMidiOutputDataOffset + kMIDIPacketNonDataSize + midiEvent.size >= kMIDIPacketListMaxDataSize) | |||
return false; | |||
const uint8_t* const midiData = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data; | |||
MIDIPacket& packet(fMidiOutputPackets.packets[fMidiOutputPackets.numPackets++]); | |||
packet.timeStamp = midiEvent.frame; | |||
packet.length = midiEvent.size; | |||
std::memcpy(packet.data, midiData, midiEvent.size); | |||
MIDIPacket* const packet = reinterpret_cast<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; | |||
} | |||
@@ -2793,7 +2861,7 @@ private: | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
struct AudioComponentPlugInInstance { | |||
AudioComponentPlugInInterface acpi; | |||
AudioComponentPlugInInterface acpi; | |||
PluginAU* plugin; | |||
AudioComponentPlugInInstance() noexcept | |||
@@ -2802,9 +2870,9 @@ struct AudioComponentPlugInInstance { | |||
{ | |||
std::memset(&acpi, 0, sizeof(acpi)); | |||
acpi.Open = Open; | |||
acpi.Close = Close; | |||
acpi.Lookup = Lookup; | |||
acpi.reserved = nullptr; | |||
acpi.Close = Close; | |||
acpi.Lookup = Lookup; | |||
acpi.reserved = nullptr; | |||
} | |||
~AudioComponentPlugInInstance() | |||
@@ -2812,14 +2880,18 @@ struct AudioComponentPlugInInstance { | |||
delete plugin; | |||
} | |||
static OSStatus Open(void* const self, const AudioUnit component) | |||
static OSStatus Open(void* const self, const AudioUnit component) | |||
{ | |||
d_debug("AudioComponentPlugInInstance::Open(%p)", self); | |||
static_cast<AudioComponentPlugInInstance*>(self)->plugin = new PluginAU(component); | |||
return noErr; | |||
} | |||
static OSStatus Close(void* const self) | |||
static OSStatus Close(void* const self) | |||
{ | |||
d_debug("AudioComponentPlugInInstance::Close(%p)", self); | |||
delete static_cast<AudioComponentPlugInInstance*>(self); | |||
return noErr; | |||
} | |||
@@ -2908,15 +2980,15 @@ struct AudioComponentPlugInInstance { | |||
d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)", | |||
self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | |||
UInt32 dataSize = 0; | |||
Boolean writable = false; | |||
UInt32 dataSize = 0; | |||
Boolean writable = false; | |||
const OSStatus res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, dataSize, writable); | |||
if (outDataSize != nullptr) | |||
*outDataSize = dataSize; | |||
if (outDataSize != nullptr) | |||
*outDataSize = dataSize; | |||
if (outWritable != nullptr) | |||
*outWritable = writable; | |||
if (outWritable != nullptr) | |||
*outWritable = writable; | |||
return res; | |||
} | |||
@@ -2928,8 +3000,16 @@ struct AudioComponentPlugInInstance { | |||
void* const outData, | |||
UInt32* const ioDataSize) | |||
{ | |||
d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)", | |||
self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | |||
#ifdef DEBUG | |||
switch (inProp) { | |||
case kAudioUnitProperty_PresentPreset: | |||
break; | |||
default: | |||
d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)", | |||
self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | |||
break; | |||
} | |||
#endif | |||
DISTRHO_SAFE_ASSERT_RETURN(ioDataSize != nullptr, kAudio_ParamError); | |||
Boolean writable; | |||
@@ -2952,24 +3032,24 @@ struct AudioComponentPlugInInstance { | |||
if (res != noErr) | |||
return res; | |||
void* outBuffer; | |||
void* outBuffer; | |||
uint8_t* tmpBuffer; | |||
if (inDataSize < outDataSize) | |||
{ | |||
tmpBuffer = new uint8_t[outDataSize]; | |||
outBuffer = tmpBuffer; | |||
} | |||
{ | |||
tmpBuffer = new uint8_t[outDataSize]; | |||
outBuffer = tmpBuffer; | |||
} | |||
else | |||
{ | |||
tmpBuffer = nullptr; | |||
outBuffer = outData; | |||
} | |||
tmpBuffer = nullptr; | |||
outBuffer = outData; | |||
} | |||
res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer); | |||
if (res != noErr) | |||
if (res != noErr) | |||
{ | |||
*ioDataSize = 0; | |||
*ioDataSize = 0; | |||
return res; | |||
} | |||
@@ -751,6 +751,7 @@ public: | |||
updateStateValueCallback), | |||
fHost(host), | |||
fOutputEvents(nullptr), | |||
fResetParameterIndex(UINT32_MAX), | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | |||
fUsingCV(false), | |||
#endif | |||
@@ -763,7 +764,19 @@ public: | |||
#endif | |||
fHostExtensions(host) | |||
{ | |||
fCachedParameters.setup(fPlugin.getParameterCount()); | |||
if (const uint32_t paramCount = fPlugin.getParameterCount()) | |||
{ | |||
fCachedParameters.setup(paramCount); | |||
for (uint32_t i=0; i<paramCount; ++i) | |||
{ | |||
if (fPlugin.getParameterDesignation(i) == kParameterDesignationReset) | |||
{ | |||
fResetParameterIndex = i; | |||
break; | |||
} | |||
} | |||
} | |||
#if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true); | |||
@@ -821,6 +834,22 @@ public: | |||
#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) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
@@ -1114,14 +1143,19 @@ public: | |||
{ | |||
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | |||
if (fPlugin.getParameterDesignation(index) == kParameterDesignationBypass) | |||
switch (fPlugin.getParameterDesignation(index)) | |||
{ | |||
case kParameterDesignationBypass: | |||
info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_BYPASS|CLAP_PARAM_IS_AUTOMATABLE; | |||
std::strcpy(info->name, "Bypass"); | |||
std::strcpy(info->module, "dpf_bypass"); | |||
} | |||
else | |||
{ | |||
break; | |||
case kParameterDesignationReset: | |||
info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_READONLY; | |||
std::strcpy(info->name, "Reset"); | |||
std::strcpy(info->module, "dpf_reset"); | |||
break; | |||
default: | |||
const uint32_t hints = fPlugin.getParameterHints(index); | |||
const uint32_t groupId = fPlugin.getParameterGroupId(index); | |||
@@ -1151,6 +1185,7 @@ public: | |||
} | |||
d_strncpy(info->module + wrtn, fPlugin.getParameterSymbol(index), CLAP_PATH_SIZE - wrtn); | |||
break; | |||
} | |||
info->id = index; | |||
@@ -1786,6 +1821,7 @@ private: | |||
const clap_host_t* const fHost; | |||
const clap_output_events_t* fOutputEvents; | |||
uint32_t fResetParameterIndex; | |||
#if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
#endif | |||
@@ -2284,23 +2320,33 @@ static bool CLAP_ABI clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, | |||
{ | |||
if (is_input) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
info->id = 0; | |||
#if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
info->supported_dialects = CLAP_NOTE_DIALECT_MIDI | CLAP_NOTE_DIALECT_MIDI_MPE; | |||
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI_MPE; | |||
#else | |||
info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; | |||
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; | |||
#endif | |||
std::strcpy(info->name, "Event/MIDI Input"); | |||
return true; | |||
#endif | |||
#endif | |||
} | |||
else | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
info->id = 0; | |||
#if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
info->supported_dialects = CLAP_NOTE_DIALECT_MIDI | CLAP_NOTE_DIALECT_MIDI_MPE; | |||
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI_MPE; | |||
#else | |||
info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; | |||
info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; | |||
#endif | |||
std::strcpy(info->name, "Event/MIDI Output"); | |||
return true; | |||
#endif | |||
#endif | |||
} | |||
return false; | |||
@@ -2440,9 +2486,10 @@ static void CLAP_ABI clap_plugin_stop_processing(const clap_plugin_t*) | |||
// nothing to do | |||
} | |||
static void CLAP_ABI clap_plugin_reset(const clap_plugin_t*) | |||
static void CLAP_ABI clap_plugin_reset(const clap_plugin_t* const plugin) | |||
{ | |||
// nothing to do | |||
PluginCLAP* const instance = static_cast<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) | |||
@@ -65,6 +65,10 @@ | |||
# define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
# define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0 | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
# define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | |||
#endif | |||
@@ -178,6 +182,13 @@ | |||
# error Synths need audio output to work! | |||
#endif | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Test if MIDI as MPE enabled where it doesn't make sense | |||
#if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE && ! (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) | |||
# error MIDI as MPE needs MIDI input or output to work! | |||
#endif | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Enable MIDI input if synth, test if midi-input disabled when synth | |||
@@ -758,6 +758,16 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; | |||
pluginString += " lv2:designation lv2:enabled ;\n"; | |||
break; | |||
case kParameterDesignationReset: | |||
designated = true; | |||
pluginString += " lv2:name \"Reset\" ;\n"; | |||
pluginString += " lv2:symbol \"" + String(ParameterDesignationSymbols::reset) + "\" ;\n"; | |||
pluginString += " lv2:default 0 ;\n"; | |||
pluginString += " lv2:minimum 0 ;\n"; | |||
pluginString += " lv2:maximum 1 ;\n"; | |||
pluginString += " lv2:portProperty lv2:toggled , lv2:integer , <" LV2_PORT_PROPS__trigger "> ;\n"; | |||
pluginString += " lv2:designation <" LV2_KXSTUDIO_PROPERTIES__Reset "> ;\n"; | |||
break; | |||
} | |||
} | |||
@@ -1763,6 +1763,12 @@ public: | |||
case kParameterDesignationBypass: | |||
flags |= V3_PARAM_IS_BYPASS; | |||
break; | |||
case kParameterDesignationReset: | |||
info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN; | |||
info->step_count = 1; | |||
strncpy_utf16(info->title, "Reset", 128); | |||
strncpy_utf16(info->short_title, "Reset", 128); | |||
return V3_OK; | |||
} | |||
if (hints & kParameterIsOutput) | |||
@@ -387,6 +387,9 @@ END_NAMESPACE_DISTRHO | |||
#define COCOA_VIEW_CLASS_NAME \ | |||
MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID) | |||
using DISTRHO_NAMESPACE::DPF_UI_AU; | |||
using DISTRHO_NAMESPACE::d_nextSampleRate; | |||
@interface COCOA_VIEW_CLASS_NAME : NSView | |||
{ | |||
@public | |||
@@ -267,12 +267,12 @@ public: | |||
uiData->app.repaintIfNeeeded(); | |||
} | |||
void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs) | |||
void addIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb, const uint timerFrequencyInMs) | |||
{ | |||
uiData->window->addIdleCallback(cb, timerFrequencyInMs); | |||
} | |||
void removeIdleCallbackForNativeIdle(IdleCallback* const cb) | |||
void removeIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb) | |||
{ | |||
uiData->window->removeIdleCallback(cb); | |||
} | |||
@@ -129,7 +129,7 @@ static uint translateVST3Modifiers(const int64_t modifiers) noexcept | |||
* Helper class for getting a native idle timer. | |||
*/ | |||
#if !DPF_VST3_USING_HOST_RUN_LOOP | |||
class NativeIdleCallback : public IdleCallback | |||
class NativeIdleCallback : public DGL_NAMESPACE::IdleCallback | |||
{ | |||
public: | |||
NativeIdleCallback(UIExporter& ui) | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
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 | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -27,6 +27,7 @@ | |||
#define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" | |||
#define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable" | |||
#define LV2_KXSTUDIO_PROPERTIES__Reset LV2_KXSTUDIO_PROPERTIES_PREFIX "Reset" | |||
#define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" | |||
#define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" | |||