diff --git a/dpf/Makefile.base.mk b/dpf/Makefile.base.mk
index 83ef5c4..6c7d17a 100644
--- a/dpf/Makefile.base.mk
+++ b/dpf/Makefile.base.mk
@@ -213,13 +213,15 @@ DGL_SYSTEM_LIBS += -framework Cocoa
endif
ifeq ($(WINDOWS),true)
-DGL_SYSTEM_LIBS += -lgdi32
+DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32
endif
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true)
+ifeq ($(HAVE_X11),true)
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11)
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11)
endif
+endif
# ---------------------------------------------------------------------------------------------------------------------
# Set Cairo specific stuff
diff --git a/dpf/README.md b/dpf/README.md
index 5dda160..d1bdfe3 100644
--- a/dpf/README.md
+++ b/dpf/README.md
@@ -30,6 +30,11 @@ List of plugins made with DPF:
- [DragonFly-Reverb](https://github.com/michaelwillis/dragonfly-reverb)
- [Wolf-Shaper](https://github.com/pdesaulniers/wolf-shaper) and [Wolf-Spectrum](https://github.com/pdesaulniers/wolf-spectrum)
- [YK Chorus](https://github.com/SpotlightKid/ykchorus)
+ - [Ninjas2](https://github.com/rghvdberg/ninjas2)
+ - [String-machine](https://github.com/jpcima/string-machine)
+ - [Rezonateur](https://github.com/jpcima/rezonateur)
+ - [QuadraFuzz](https://github.com/jpcima/quadrafuzz)
+ - [Shiru Plugins](https://github.com/linuxmao-org/shiru-plugins)
Plugin examples are available in the `example/` folder inside this repo.
diff --git a/dpf/dgl/src/Cairo.cpp b/dpf/dgl/src/Cairo.cpp
index 2c9e42e..ac9fff5 100644
--- a/dpf/dgl/src/Cairo.cpp
+++ b/dpf/dgl/src/Cairo.cpp
@@ -14,13 +14,98 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "../Base.hpp"
+#include "../Geometry.hpp"
+#include "../Cairo.hpp"
START_NAMESPACE_DGL
// -----------------------------------------------------------------------
-// nothing here yet
+static void notImplemented(const char *name)
+{
+ d_stderr2("cairo function not implemented: %s", name);
+}
+
+// -----------------------------------------------------------------------
+// Line
+
+template
+void Line::draw()
+{
+ notImplemented("Line::draw");
+}
+
+// -----------------------------------------------------------------------
+// Circle
+
+template
+void Circle::_draw(const bool outline)
+{
+ notImplemented("Circle::draw");
+}
+
+// -----------------------------------------------------------------------
+// Triangle
+
+template
+void Triangle::_draw(const bool outline)
+{
+ notImplemented("Triangle::draw");
+}
+
+// -----------------------------------------------------------------------
+// Rectangle
+
+template
+void Rectangle::_draw(const bool outline)
+{
+ notImplemented("Rectangle::draw");
+}
+
+// -----------------------------------------------------------------------
+// Possible template data types
+
+template class Point;
+template class Point;
+template class Point;
+template class Point;
+template class Point;
+template class Point;
+
+template class Size;
+template class Size;
+template class Size;
+template class Size;
+template class Size;
+template class Size;
+
+template class Line;
+template class Line;
+template class Line;
+template class Line;
+template class Line;
+template class Line;
+
+template class Circle;
+template class Circle;
+template class Circle;
+template class Circle;
+template class Circle;
+template class Circle;
+
+template class Triangle;
+template class Triangle;
+template class Triangle;
+template class Triangle;
+template class Triangle;
+template class Triangle;
+
+template class Rectangle;
+template class Rectangle;
+template class Rectangle;
+template class Rectangle;
+template class Rectangle;
+template class Rectangle;
// -----------------------------------------------------------------------
diff --git a/dpf/dgl/src/NanoVG.cpp b/dpf/dgl/src/NanoVG.cpp
index 06fc49f..b62bc4c 100644
--- a/dpf/dgl/src/NanoVG.cpp
+++ b/dpf/dgl/src/NanoVG.cpp
@@ -81,11 +81,8 @@ static NVGcontext* nvgCreateGL_helper(int flags)
{
#if defined(DISTRHO_OS_WINDOWS)
static bool needsInit = true;
- if (needsInit)
- {
- needsInit = false;
# define DGL_EXT(PROC, func) \
- func = (PROC) wglGetProcAddress ( #func ); \
+ if (needsInit) func = (PROC) wglGetProcAddress ( #func ); \
DISTRHO_SAFE_ASSERT_RETURN(func != nullptr, nullptr);
DGL_EXT(PFNGLACTIVETEXTUREPROC, glActiveTexture)
DGL_EXT(PFNGLATTACHSHADERPROC, glAttachShader)
@@ -115,7 +112,7 @@ DGL_EXT(PFNGLUNIFORM4FVPROC, glUniform4fv)
DGL_EXT(PFNGLUSEPROGRAMPROC, glUseProgram)
DGL_EXT(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
# undef DGL_EXT
- }
+ needsInit = false;
#endif
return nvgCreateGL(flags);
}
@@ -918,6 +915,8 @@ int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWi
#ifndef DGL_NO_SHARED_RESOURCES
void NanoVG::loadSharedResources()
{
+ if (fContext == nullptr) return;
+
if (nvgFindFont(fContext, NANOVG_DEJAVU_SANS_TTF) >= 0)
return;
diff --git a/dpf/dgl/src/Window.cpp b/dpf/dgl/src/Window.cpp
index bb9db16..f715e54 100644
--- a/dpf/dgl/src/Window.cpp
+++ b/dpf/dgl/src/Window.cpp
@@ -1,6 +1,8 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2019 Filipe Coelho
+ * Copyright (C) 2019 Jean Pierre Cimalando
+ * Copyright (C) 2019 Robin Gareus
*
* 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
@@ -105,6 +107,10 @@ struct Window::PrivateData {
mView(nullptr),
mWindow(nullptr),
mParentWindow(nullptr)
+# ifndef DGL_FILE_BROWSER_DISABLED
+ , fOpenFilePanel(nullptr),
+ fFilePanelDelegate(nullptr)
+# endif
#else
xDisplay(nullptr),
xWindow(0)
@@ -137,6 +143,10 @@ struct Window::PrivateData {
mView(nullptr),
mWindow(nullptr),
mParentWindow(nullptr)
+# ifndef DGL_FILE_BROWSER_DISABLED
+ , fOpenFilePanel(nullptr),
+ fFilePanelDelegate(nullptr)
+# endif
#else
xDisplay(nullptr),
xWindow(0)
@@ -181,6 +191,10 @@ struct Window::PrivateData {
mView(nullptr),
mWindow(nullptr),
mParentWindow(nullptr)
+# ifndef DGL_FILE_BROWSER_DISABLED
+ , fOpenFilePanel(nullptr),
+ fFilePanelDelegate(nullptr)
+# endif
#else
xDisplay(nullptr),
xWindow(0)
@@ -323,6 +337,19 @@ struct Window::PrivateData {
xWindow = 0;
#endif
+#if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED)
+ if (fOpenFilePanel)
+ {
+ [fOpenFilePanel release];
+ fOpenFilePanel = nullptr;
+ }
+ if (fFilePanelDelegate)
+ {
+ [fFilePanelDelegate release];
+ fFilePanelDelegate = nullptr;
+ }
+#endif
+
DBG("Success!\n");
}
@@ -687,6 +714,9 @@ struct Window::PrivateData {
}
#else
XStoreName(xDisplay, xWindow, title);
+ Atom netWmName = XInternAtom(xDisplay, "_NET_WM_NAME", False);
+ Atom utf8String = XInternAtom(xDisplay, "UTF8_STRING", False);
+ XChangeProperty(xDisplay, xWindow, netWmName, utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title));
#endif
}
@@ -774,6 +804,15 @@ struct Window::PrivateData {
}
#endif
+#if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED)
+ if (fSelectedFile.isNotEmpty())
+ {
+ char* const buffer = fSelectedFile.getAndReleaseBuffer();
+ fView->fileSelectedFunc(fView, buffer);
+ std::free(buffer);
+ }
+#endif
+
if (fModal.enabled && fModal.parent != nullptr)
fModal.parent->idle();
}
@@ -1050,6 +1089,39 @@ struct Window::PrivateData {
return false;
}
+#if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED)
+ static void openPanelDidEnd(NSOpenPanel* panel, int returnCode, void *userData)
+ {
+ PrivateData* pData = (PrivateData*)userData;
+
+ if (returnCode == NSOKButton)
+ {
+ NSArray* urls = [panel URLs];
+ NSURL* fileUrl = nullptr;
+
+ for (NSUInteger i = 0, n = [urls count]; i < n && !fileUrl; ++i)
+ {
+ NSURL* url = (NSURL*)[urls objectAtIndex:i];
+ if ([url isFileURL])
+ fileUrl = url;
+ }
+
+ if (fileUrl)
+ {
+ PuglView* view = pData->fView;
+ if (view->fileSelectedFunc)
+ {
+ const char* fileName = [fileUrl.path UTF8String];
+ view->fileSelectedFunc(view, fileName);
+ }
+ }
+ }
+
+ [pData->fOpenFilePanel release];
+ pData->fOpenFilePanel = nullptr;
+ }
+#endif
+
// -------------------------------------------------------------------
Application& fApp;
@@ -1095,11 +1167,18 @@ struct Window::PrivateData {
#if defined(DISTRHO_OS_WINDOWS)
HWND hwnd;
HWND hwndParent;
+# ifndef DGL_FILE_BROWSER_DISABLED
+ String fSelectedFile;
+# endif
#elif defined(DISTRHO_OS_MAC)
bool fNeedsIdle;
NSView* mView;
id mWindow;
id mParentWindow;
+# ifndef DGL_FILE_BROWSER_DISABLED
+ NSOpenPanel* fOpenFilePanel;
+ id fFilePanelDelegate;
+# endif
#else
Display* xDisplay;
::Window xWindow;
@@ -1216,6 +1295,20 @@ void Window::repaint() noexcept
// }
#ifndef DGL_FILE_BROWSER_DISABLED
+
+#ifdef DISTRHO_OS_MAC
+END_NAMESPACE_DGL
+@interface FilePanelDelegate : NSObject
+{
+ void (*fCallback)(NSOpenPanel*, int, void*);
+ void* fUserData;
+}
+-(id)initWithCallback:(void(*)(NSOpenPanel*, int, void*))callback userData:(void*)userData;
+-(void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+@end
+START_NAMESPACE_DGL
+#endif
+
bool Window::openFileBrowser(const FileBrowserOptions& options)
{
# ifdef SOFD_HAVE_X11
@@ -1278,6 +1371,93 @@ bool Window::openFileBrowser(const FileBrowserOptions& options)
// show
return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0);
+# elif defined(DISTRHO_OS_WINDOWS)
+ // the old and compatible dialog API
+ OPENFILENAMEW ofn;
+ memset(&ofn, 0, sizeof(ofn));
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = pData->hwnd;
+
+ // set initial directory in UTF-16 coding
+ std::vector startDirW;
+ if (options.startDir)
+ {
+ startDirW.resize(strlen(options.startDir) + 1);
+ if (MultiByteToWideChar(CP_UTF8, 0, options.startDir, -1, startDirW.data(), startDirW.size()))
+ ofn.lpstrInitialDir = startDirW.data();
+ }
+
+ // set title in UTF-16 coding
+ std::vector titleW;
+ if (options.title)
+ {
+ titleW.resize(strlen(options.title) + 1);
+ if (MultiByteToWideChar(CP_UTF8, 0, options.title, -1, titleW.data(), titleW.size()))
+ ofn.lpstrTitle = titleW.data();
+ }
+
+ // prepare a buffer to receive the result
+ std::vector fileNameW(32768); // the Unicode maximum
+ ofn.lpstrFile = fileNameW.data();
+ ofn.nMaxFile = (DWORD)fileNameW.size();
+
+ // TODO synchronous only, can't do better with WinAPI native dialogs.
+ // threading might work, if someone is motivated to risk it.
+ if (GetOpenFileNameW(&ofn))
+ {
+ // back to UTF-8
+ std::vector fileNameA(4 * 32768);
+ if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, fileNameA.data(), (int)fileNameA.size(), nullptr, nullptr))
+ {
+ // handle it during the next idle cycle (fake async)
+ pData->fSelectedFile = fileNameA.data();
+ }
+ }
+
+ return true;
+# elif defined(DISTRHO_OS_MAC)
+ if (pData->fOpenFilePanel) // permit one dialog at most
+ {
+ [pData->fOpenFilePanel makeKeyAndOrderFront:nil];
+ return false;
+ }
+
+ NSOpenPanel* panel = [NSOpenPanel openPanel];
+ pData->fOpenFilePanel = [panel retain];
+
+ [panel setCanChooseFiles:YES];
+ [panel setCanChooseDirectories:NO];
+ [panel setAllowsMultipleSelection:NO];
+
+ if (options.startDir)
+ [panel setDirectory:[NSString stringWithUTF8String:options.startDir]];
+
+ if (options.title)
+ {
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:options.title
+ length:strlen(options.title)
+ encoding:NSUTF8StringEncoding];
+ [panel setTitle:titleString];
+ }
+
+ id delegate = pData->fFilePanelDelegate;
+ if (!delegate)
+ {
+ delegate = [[FilePanelDelegate alloc] initWithCallback:&PrivateData::openPanelDidEnd
+ userData:pData];
+ pData->fFilePanelDelegate = [delegate retain];
+ }
+
+ [panel beginSheetForDirectory:nullptr
+ file:nullptr
+ modalForWindow:nullptr
+ modalDelegate:delegate
+ didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
+ contextInfo:nullptr];
+
+ return true;
# else
// not implemented
return false;
@@ -1286,8 +1466,29 @@ bool Window::openFileBrowser(const FileBrowserOptions& options)
(void)options;
# endif
}
+
+#ifdef DISTRHO_OS_MAC
+END_NAMESPACE_DGL
+@implementation FilePanelDelegate
+-(id)initWithCallback:(void(*)(NSOpenPanel*, int, void*))callback userData:(void *)userData
+{
+ [super init];
+ self->fCallback = callback;
+ self->fUserData = userData;
+ return self;
+}
+
+-(void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ self->fCallback(sheet, returnCode, self->fUserData);
+ (void)contextInfo;
+}
+@end
+START_NAMESPACE_DGL
#endif
+#endif // !defined(DGL_FILE_BROWSER_DISABLED)
+
bool Window::isEmbed() const noexcept
{
return pData->fUsingEmbed;
diff --git a/dpf/dgl/src/pugl/pugl_x11.c b/dpf/dgl/src/pugl/pugl_x11.c
index 3146cfc..2783bbb 100644
--- a/dpf/dgl/src/pugl/pugl_x11.c
+++ b/dpf/dgl/src/pugl/pugl_x11.c
@@ -274,6 +274,9 @@ puglCreateWindow(PuglView* view, const char* title)
if (title) {
XStoreName(impl->display, impl->win, title);
+ Atom netWmName = XInternAtom(impl->display, "_NET_WM_NAME", False);
+ Atom utf8String = XInternAtom(impl->display, "UTF8_STRING", False);
+ XChangeProperty(impl->display, impl->win, netWmName, utf8String, 8, PropModeReplace, (unsigned char *)title, strlen(title));
}
if (view->transient_parent > 0) {
diff --git a/dpf/dgl/src/sofd/libsofd.c b/dpf/dgl/src/sofd/libsofd.c
index 914a6e2..06273d4 100644
--- a/dpf/dgl/src/sofd/libsofd.c
+++ b/dpf/dgl/src/sofd/libsofd.c
@@ -1257,7 +1257,8 @@ static int fib_opendir (Display *dpy, const char* path, const char *sel) {
} else {
int i;
struct dirent *de;
- strcpy (_cur_path, path);
+ if (path != _cur_path)
+ strcpy (_cur_path, path);
if (_cur_path[strlen (_cur_path) -1] != '/')
strcat (_cur_path, "/");
diff --git a/dpf/distrho/DistrhoPlugin.hpp b/dpf/distrho/DistrhoPlugin.hpp
index ebc5407..913f7dd 100644
--- a/dpf/distrho/DistrhoPlugin.hpp
+++ b/dpf/distrho/DistrhoPlugin.hpp
@@ -384,6 +384,13 @@ struct Parameter {
*/
String name;
+ /**
+ The short name of this parameter.@n
+ Used when displaying the parameter name in a very limited space.
+ @note This value is optional, the full name is used when the short one is missing.
+ */
+ String shortName;
+
/**
The symbol of this parameter.@n
A parameter symbol is a short restricted name used as a machine and human readable identifier.@n
@@ -399,6 +406,12 @@ struct Parameter {
*/
String unit;
+ /**
+ An extensive description/comment about the parameter.
+ @note This value is optional and only used for LV2.
+ */
+ String description;
+
/**
Ranges of this parameter.@n
The ranges describe the default, minimum and maximum values.
@@ -430,6 +443,7 @@ struct Parameter {
Parameter() noexcept
: hints(0x0),
name(),
+ shortName(),
symbol(),
unit(),
ranges(),
@@ -443,6 +457,7 @@ struct Parameter {
Parameter(uint32_t h, const char* n, const char* s, const char* u, float def, float min, float max) noexcept
: hints(h),
name(n),
+ shortName(),
symbol(s),
unit(u),
ranges(def, min, max),
@@ -462,11 +477,12 @@ struct Parameter {
case kParameterDesignationNull:
break;
case kParameterDesignationBypass:
- hints = kParameterIsAutomable|kParameterIsBoolean|kParameterIsInteger;
- name = "Bypass";
- symbol = "dpf_bypass";
- unit = "";
- midiCC = 0;
+ hints = kParameterIsAutomable|kParameterIsBoolean|kParameterIsInteger;
+ name = "Bypass";
+ shortName = "Bypass";
+ symbol = "dpf_bypass";
+ unit = "";
+ midiCC = 0;
ranges.def = 0.0f;
ranges.min = 0.0f;
ranges.max = 1.0f;
diff --git a/dpf/distrho/DistrhoUtils.hpp b/dpf/distrho/DistrhoUtils.hpp
index ee2cb57..4cf8ac7 100644
--- a/dpf/distrho/DistrhoUtils.hpp
+++ b/dpf/distrho/DistrhoUtils.hpp
@@ -156,6 +156,46 @@ void d_safe_assert(const char* const assertion, const char* const file, const in
d_stderr2("assertion failure: \"%s\" in file %s, line %i", assertion, file, line);
}
+/*
+ * Print a safe assertion error message, with 1 extra signed integer value.
+ */
+static inline
+void d_safe_assert_int(const char* const assertion, const char* const file,
+ const int line, const int value) noexcept
+{
+ d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value);
+}
+
+/*
+ * Print a safe assertion error message, with 1 extra unsigned integer value.
+ */
+static inline
+void d_safe_assert_uint(const char* const assertion, const char* const file,
+ const int line, const uint value) noexcept
+{
+ d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %u", assertion, file, line, value);
+}
+
+/*
+ * Print a safe assertion error message, with 2 extra signed integer values.
+ */
+static inline
+void d_safe_assert_int2(const char* const assertion, const char* const file,
+ const int line, const int v1, const int v2) noexcept
+{
+ d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2);
+}
+
+/*
+ * Print a safe assertion error message, with 2 extra unsigned integer values.
+ */
+static inline
+void d_safe_assert_uint2(const char* const assertion, const char* const file,
+ const int line, const uint v1, const uint v2) noexcept
+{
+ d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2);
+}
+
/*
* Print a safe exception error message.
*/
diff --git a/dpf/distrho/extra/String.hpp b/dpf/distrho/extra/String.hpp
index 650c5bb..5e25840 100644
--- a/dpf/distrho/extra/String.hpp
+++ b/dpf/distrho/extra/String.hpp
@@ -568,6 +568,18 @@ public:
return fBuffer;
}
+ /*
+ * Get and release the string buffer, while also clearing this string.
+ * Result must be freed.
+ */
+ char* getAndReleaseBuffer() noexcept
+ {
+ char* const ret = fBuffer;
+ fBuffer = _null();
+ fBufferLen = 0;
+ return ret;
+ }
+
// -------------------------------------------------------------------
// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
// Copyright (C) 2004-2008 René Nyffenegger
diff --git a/dpf/distrho/src/DistrhoDefines.h b/dpf/distrho/src/DistrhoDefines.h
index f16e44d..14492f6 100644
--- a/dpf/distrho/src/DistrhoDefines.h
+++ b/dpf/distrho/src/DistrhoDefines.h
@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2016 Filipe Coelho
+ * Copyright (C) 2012-2019 Filipe Coelho
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
@@ -81,6 +81,22 @@
#define DISTRHO_SAFE_ASSERT_CONTINUE(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); continue; }
#define DISTRHO_SAFE_ASSERT_RETURN(cond, ret) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); return ret; }
+#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value); break; }
+#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); continue; }
+#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast(value)); return ret; }
+
+#define DISTRHO_SAFE_ASSERT_INT2_BREAK(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); break; }
+#define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; }
+#define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; }
+
+#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value); break; }
+#define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); continue; }
+#define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast(value)); return ret; }
+
+#define DISTRHO_SAFE_ASSERT_UINT2_BREAK(cond, v1, v2) if (! (cond)) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); break; }
+#define DISTRHO_SAFE_ASSERT_UINT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); continue; }
+#define DISTRHO_SAFE_ASSERT_UINT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast(v1), static_cast(v2)); return ret; }
+
/* Define DISTRHO_SAFE_EXCEPTION */
#define DISTRHO_SAFE_EXCEPTION(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); }
#define DISTRHO_SAFE_EXCEPTION_BREAK(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); break; }
diff --git a/dpf/distrho/src/DistrhoPluginInternal.hpp b/dpf/distrho/src/DistrhoPluginInternal.hpp
index 604f4d9..b05663e 100644
--- a/dpf/distrho/src/DistrhoPluginInternal.hpp
+++ b/dpf/distrho/src/DistrhoPluginInternal.hpp
@@ -375,6 +375,13 @@ public:
return fData->parameters[index].name;
}
+ const String& getParameterShortName(const uint32_t index) const noexcept
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
+
+ return fData->parameters[index].shortName;
+ }
+
const String& getParameterSymbol(const uint32_t index) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
@@ -389,6 +396,13 @@ public:
return fData->parameters[index].unit;
}
+ const String& getParameterDescription(const uint32_t index) const noexcept
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackString);
+
+ return fData->parameters[index].description;
+ }
+
const ParameterEnumerationValues& getParameterEnumValues(const uint32_t index) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, sFallbackEnumValues);
diff --git a/dpf/distrho/src/DistrhoPluginLV2.cpp b/dpf/distrho/src/DistrhoPluginLV2.cpp
index ed97052..5410bf1 100644
--- a/dpf/distrho/src/DistrhoPluginLV2.cpp
+++ b/dpf/distrho/src/DistrhoPluginLV2.cpp
@@ -846,6 +846,11 @@ public:
return LV2_WORKER_SUCCESS;
}
+
+ LV2_Worker_Status lv2_work_response(uint32_t, const void*)
+ {
+ return LV2_WORKER_SUCCESS;
+ }
#endif
// -------------------------------------------------------------------
@@ -1243,6 +1248,11 @@ LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function, LV2
{
return instancePtr->lv2_work(data);
}
+
+LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const void* body)
+{
+ return instancePtr->lv2_work_response(size, body);
+}
#endif
// -----------------------------------------------------------------------
@@ -1272,7 +1282,7 @@ static const void* lv2_extension_data(const char* uri)
#if DISTRHO_PLUGIN_WANT_STATE
static const LV2_State_Interface state = { lv2_save, lv2_restore };
- static const LV2_Worker_Interface worker = { lv2_work, nullptr, nullptr };
+ static const LV2_Worker_Interface worker = { lv2_work, lv2_work_response, nullptr };
if (std::strcmp(uri, LV2_STATE__interface) == 0)
return &state;
diff --git a/dpf/distrho/src/DistrhoPluginLV2export.cpp b/dpf/distrho/src/DistrhoPluginLV2export.cpp
index a43ec4b..3c44b87 100644
--- a/dpf/distrho/src/DistrhoPluginLV2export.cpp
+++ b/dpf/distrho/src/DistrhoPluginLV2export.cpp
@@ -70,6 +70,140 @@
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
+// -----------------------------------------------------------------------
+static const char* const lv2ManifestPluginExtensionData[] =
+{
+ "opts:interface",
+#if DISTRHO_PLUGIN_WANT_STATE
+ LV2_STATE__interface,
+ LV2_WORKER__interface,
+#endif
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ LV2_PROGRAMS__Interface,
+#endif
+#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
+ MOD_LICENSE__interface,
+#endif
+ nullptr
+};
+
+static const char* const lv2ManifestPluginOptionalFeatures[] =
+{
+#if DISTRHO_PLUGIN_IS_RT_SAFE
+ LV2_CORE__hardRTCapable,
+#endif
+ LV2_BUF_SIZE__boundedBlockLength,
+ nullptr
+};
+
+static const char* const lv2ManifestPluginRequiredFeatures[] =
+{
+ "opts:options",
+ LV2_URID__map,
+#if DISTRHO_PLUGIN_WANT_STATE
+ LV2_WORKER__schedule,
+#endif
+#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
+ MOD_LICENSE__feature,
+#endif
+ nullptr
+};
+
+static const char* const lv2ManifestPluginSupportedOptions[] =
+{
+ LV2_BUF_SIZE__nominalBlockLength,
+ LV2_BUF_SIZE__maxBlockLength,
+ LV2_PARAMETERS__sampleRate,
+ nullptr
+};
+
+#if DISTRHO_PLUGIN_HAS_UI
+static const char* const lv2ManifestUiExtensionData[] =
+{
+ "opts:interface",
+ "ui:idleInterface",
+ "ui:showInterface",
+ "ui:resize",
+#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ LV2_PROGRAMS__UIInterface,
+#endif
+ nullptr
+};
+
+static const char* const lv2ManifestUiOptionalFeatures[] =
+{
+#if DISTRHO_PLUGIN_HAS_EMBED_UI
+# if !DISTRHO_UI_USER_RESIZABLE
+ "ui:noUserResize",
+# endif
+ "ui:resize",
+ "ui:touch",
+#endif
+ nullptr
+};
+
+static const char* const lv2ManifestUiRequiredFeatures[] =
+{
+ "opts:options",
+#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
+ LV2_DATA_ACCESS_URI,
+ LV2_INSTANCE_ACCESS_URI,
+#endif
+ LV2_URID__map,
+ nullptr
+};
+
+static const char* const lv2ManifestUiSupportedOptions[] =
+{
+ LV2_PARAMETERS__sampleRate,
+ nullptr
+};
+#endif // DISTRHO_PLUGIN_HAS_UI
+
+static void addAttribute(String& text,
+ const char* const attribute,
+ const char* const values[],
+ const uint indent,
+ const bool endInDot = false)
+{
+ if (values[0] == nullptr)
+ {
+ if (endInDot)
+ {
+ bool found;
+ const size_t index = text.rfind(';', &found);
+ if (found) text[index] = '.';
+ }
+ return;
+ }
+
+ const size_t attributeLength = std::strlen(attribute);
+
+ for (uint i = 0; values[i] != nullptr; ++i)
+ {
+ for (uint j = 0; j < indent; ++j)
+ text += " ";
+
+ if (i == 0)
+ {
+ text += attribute;
+ }
+ else
+ {
+ for (uint j = 0; j < attributeLength; ++j)
+ text += " ";
+ }
+
+ text += " ";
+
+ const bool isUrl = std::strstr(values[i], "://") != nullptr || std::strncmp(values[i], "urn:", 4) == 0;
+ if (isUrl) text += "<";
+ text += values[i];
+ if (isUrl) text += ">";
+ text += values[i + 1] ? " ,\n" : (endInDot ? " .\n\n" : " ;\n\n");
+ }
+}
+
// -----------------------------------------------------------------------
DISTRHO_PLUGIN_EXPORT
@@ -132,32 +266,10 @@ void lv2_generate_ttl(const char* const basename)
manifestString += " a ui:" DISTRHO_LV2_UI_TYPE " ;\n";
manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n";
# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
- manifestString += "\n";
- manifestString += " lv2:extensionData ui:idleInterface ,\n";
-# if DISTRHO_PLUGIN_WANT_PROGRAMS
- manifestString += " ui:showInterface ,\n";
- manifestString += " <" LV2_PROGRAMS__Interface "> ;\n";
-# else
- manifestString += " ui:showInterface ;\n";
-# endif
- manifestString += "\n";
-# if DISTRHO_PLUGIN_HAS_EMBED_UI
-# if DISTRHO_UI_USER_RESIZABLE
- manifestString += " lv2:optionalFeature ui:resize ,\n";
- manifestString += " ui:touch ;\n";
- manifestString += "\n";
-# else // DISTRHO_UI_USER_RESIZABLE
- manifestString += " lv2:optionalFeature ui:noUserResize ,\n";
- manifestString += " ui:resize ,\n";
- manifestString += " ui:touch ;\n";
- manifestString += "\n";
-# endif // DISTRHO_UI_USER_RESIZABLE
-# endif // DISTRHO_PLUGIN_HAS_EMBED_UI
- manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n";
- manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n";
- manifestString += " <" LV2_OPTIONS__options "> ,\n";
- manifestString += " <" LV2_URID__map "> ;\n";
- manifestString += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n";
+ addAttribute(manifestString, "lv2:extensionData", lv2ManifestUiExtensionData, 4);
+ addAttribute(manifestString, "lv2:optionalFeature", lv2ManifestUiOptionalFeatures, 4);
+ addAttribute(manifestString, "lv2:requiredFeature", lv2ManifestUiRequiredFeatures, 4);
+ addAttribute(manifestString, "opts:supportedOption", lv2ManifestUiSupportedOptions, 4, true);
# else // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n";
# endif // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
@@ -214,7 +326,9 @@ void lv2_generate_ttl(const char* const basename)
pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n";
pluginString += "@prefix rdf: .\n";
pluginString += "@prefix rdfs: .\n";
+#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT
pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n";
+#endif
#if DISTRHO_PLUGIN_HAS_UI
pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
#endif
@@ -232,45 +346,10 @@ void lv2_generate_ttl(const char* const basename)
#endif
pluginString += "\n";
- // extensionData
- pluginString += " lv2:extensionData <" LV2_STATE__interface "> ";
-#if DISTRHO_PLUGIN_WANT_STATE
- pluginString += ",\n <" LV2_OPTIONS__interface "> ";
- pluginString += ",\n <" LV2_WORKER__interface "> ";
-#endif
-#if DISTRHO_PLUGIN_WANT_PROGRAMS
- pluginString += ",\n <" LV2_PROGRAMS__Interface "> ";
-#endif
-#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
- pluginString += ",\n <" MOD_LICENSE__interface "> ";
-#endif
- pluginString += ";\n\n";
-
- // optionalFeatures
-#if DISTRHO_PLUGIN_IS_RT_SAFE
- pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n";
- pluginString += " <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
-#else
- pluginString += " lv2:optionalFeature <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
-#endif
- pluginString += "\n";
-
- // requiredFeatures
- pluginString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ";
- pluginString += ",\n <" LV2_URID__map "> ";
-#if DISTRHO_PLUGIN_WANT_STATE
- pluginString += ",\n <" LV2_WORKER__schedule "> ";
-#endif
-#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD
- pluginString += ",\n <" MOD_LICENSE__feature "> ";
-#endif
- pluginString += ";\n\n";
-
- // supportedOptions
- pluginString += " opts:supportedOption <" LV2_BUF_SIZE__nominalBlockLength "> ,\n";
- pluginString += " <" LV2_BUF_SIZE__maxBlockLength "> ,\n";
- pluginString += " <" LV2_PARAMETERS__sampleRate "> ;\n";
- pluginString += "\n";
+ addAttribute(pluginString, "lv2:extensionData", lv2ManifestPluginExtensionData, 4);
+ addAttribute(pluginString, "lv2:optionalFeature", lv2ManifestPluginOptionalFeatures, 4);
+ addAttribute(pluginString, "lv2:requiredFeature", lv2ManifestPluginRequiredFeatures, 4);
+ addAttribute(pluginString, "opts:supportedOption", lv2ManifestPluginSupportedOptions, 4);
// UI
#if DISTRHO_PLUGIN_HAS_UI
@@ -440,6 +519,12 @@ void lv2_generate_ttl(const char* const basename)
pluginString += " lv2:symbol \"" + symbol + "\" ;\n";
+ // short name
+ const String& shortName(plugin.getParameterShortName(i));
+
+ if (shortName.isNotEmpty())
+ pluginString += " lv2:shortName \"\"\"" + shortName + "\"\"\" ;\n";
+
// ranges
const ParameterRanges& ranges(plugin.getParameterRanges(i));
@@ -528,6 +613,12 @@ void lv2_generate_ttl(const char* const basename)
}
}
+ // comment
+ const String& comment(plugin.getParameterDescription(i));
+
+ if (comment.isNotEmpty())
+ pluginString += " rdfs:comment \"\"\"" + comment + "\"\"\" ;\n";
+
// hints
const uint32_t hints(plugin.getParameterHints(i));
@@ -560,7 +651,7 @@ void lv2_generate_ttl(const char* const basename)
const String comment(plugin.getDescription());
if (comment.isNotEmpty())
- pluginString += " rdfs:comment \"\"\"\n" + comment + "\n\"\"\" ;\n\n";
+ pluginString += " rdfs:comment \"\"\"" + comment + "\"\"\" ;\n\n";
}
#ifdef DISTRHO_PLUGIN_BRAND
@@ -629,30 +720,11 @@ void lv2_generate_ttl(const char* const basename)
uiString += "\n";
uiString += "<" DISTRHO_UI_URI ">\n";
- uiString += " lv2:extensionData ui:idleInterface ,\n";
-# if DISTRHO_PLUGIN_WANT_PROGRAMS
- uiString += " ui:showInterface ,\n";
- uiString += " <" LV2_PROGRAMS__Interface "> ;\n";
-# else
- uiString += " ui:showInterface ;\n";
-# endif
- uiString += "\n";
-# if DISTRHO_PLUGIN_HAS_EMBED_UI
-# if DISTRHO_UI_USER_RESIZABLE
- uiString += " lv2:optionalFeature ui:resize ,\n";
- uiString += " ui:touch ;\n";
- uiString += "\n";
-# else // DISTRHO_UI_USER_RESIZABLE
- uiString += " lv2:optionalFeature ui:noUserResize ,\n";
- uiString += " ui:resize ,\n";
- uiString += " ui:touch ;\n";
- uiString += "\n";
-# endif // DISTRHO_UI_USER_RESIZABLE
-# endif // DISTRHO_PLUGIN_HAS_EMBED_UI
- uiString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n";
- uiString += " <" LV2_URID__map "> ;\n";
- uiString += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n";
+ addAttribute(uiString, "lv2:extensionData", lv2ManifestUiExtensionData, 4);
+ addAttribute(uiString, "lv2:optionalFeature", lv2ManifestUiOptionalFeatures, 4);
+ addAttribute(uiString, "lv2:requiredFeature", lv2ManifestUiRequiredFeatures, 4);
+ addAttribute(uiString, "opts:supportedOption", lv2ManifestUiSupportedOptions, 4, true);
uiFile << uiString << std::endl;
uiFile.close();
diff --git a/dpf/distrho/src/DistrhoPluginVST.cpp b/dpf/distrho/src/DistrhoPluginVST.cpp
index d8e7640..c77b7af 100644
--- a/dpf/distrho/src/DistrhoPluginVST.cpp
+++ b/dpf/distrho/src/DistrhoPluginVST.cpp
@@ -1294,7 +1294,11 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t
case effGetParamName:
if (ptr != nullptr && index < static_cast(plugin.getParameterCount()))
{
- DISTRHO_NAMESPACE::strncpy((char*)ptr, plugin.getParameterName(index), 16);
+ const String& shortName(plugin.getParameterShortName(index));
+ if (shortName.isNotEmpty())
+ DISTRHO_NAMESPACE::strncpy((char*)ptr, shortName, 16);
+ else
+ DISTRHO_NAMESPACE::strncpy((char*)ptr, plugin.getParameterName(index), 16);
return 1;
}
return 0;
diff --git a/dpf/utils/generate-vst-bundles.sh b/dpf/utils/generate-vst-bundles.sh
index b4afdb8..1cf784a 100755
--- a/dpf/utils/generate-vst-bundles.sh
+++ b/dpf/utils/generate-vst-bundles.sh
@@ -9,19 +9,18 @@ else
exit
fi
-PWD=`pwd`
+DPF_DIR=$(dirname $0)/..
+PLUGINS=$(ls | grep vst.dylib)
rm -rf *.vst/
-PLUGINS=`ls | grep vst.dylib`
-
for i in $PLUGINS; do
- FILE=`echo $i | awk 'sub("-vst.dylib","")'`
- cp -r ../dpf/utils/plugin.vst/ $FILE.vst
- mv $i $FILE.vst/Contents/MacOS/$FILE
- rm -f $FILE.vst/Contents/MacOS/deleteme
- sed -i -e "s/X-PROJECTNAME-X/$FILE/" $FILE.vst/Contents/Info.plist
- rm -f $FILE.vst/Contents/Info.plist-e
+ BUNDLE=$(echo ${i} | awk 'sub("-vst.dylib","")')
+ cp -r ${DPF_DIR}/utils/plugin.vst/ ${BUNDLE}.vst
+ mv ${i} ${BUNDLE}.vst/Contents/MacOS/${BUNDLE}
+ rm -f ${BUNDLE}.vst/Contents/MacOS/deleteme
+ sed -i -e "s/X-PROJECTNAME-X/${BUNDLE}/" ${BUNDLE}.vst/Contents/Info.plist
+ rm -f ${BUNDLE}.vst/Contents/Info.plist-e
done
cd ..
diff --git a/plugins/Kars/DistrhoPluginKars.cpp b/plugins/Kars/DistrhoPluginKars.cpp
index b3d1b43..b16ef18 100644
--- a/plugins/Kars/DistrhoPluginKars.cpp
+++ b/plugins/Kars/DistrhoPluginKars.cpp
@@ -15,6 +15,7 @@
*/
#include "DistrhoPluginKars.hpp"
+#include "DistrhoPluginUtils.hpp"
START_NAMESPACE_DISTRHO
@@ -117,136 +118,6 @@ void DistrhoPluginKars::activate()
}
}
-/**
- Handy class to help keep audio buffer in sync with incoming MIDI events.
- To use it, create a local variable (on the stack) and call nextEvent() until it returns false.
- @code
- for (AudioMidiSyncHelper amsh(outputs, frames, midiEvents, midiEventCount); amsh.nextEvent();)
- {
- float* const outL = amsh.outputs[0];
- float* const outR = amsh.outputs[1];
-
- for (uint32_t i=0; i(midiEvents);
- for (uint32_t i=0; i < midiEventCount; ++i)
- rwEvents[i].frame -= totalFramesUsed;
- }
-
- frames = remainingFrames - firstEventFrame;
- remainingFrames -= frames;
- remainingMidiEventCount -= midiEventCount;
- totalFramesUsed += frames;
- return true;
- }
-
-private:
- /** @internal */
- uint32_t remainingFrames;
- uint32_t remainingMidiEventCount;
- uint32_t totalFramesUsed;
-};
-
void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount)
{
uint8_t note, velo;
@@ -270,7 +141,7 @@ void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, con
DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
if (velo > 0)
{
- fNotes[note].on = fBlockStart + amsh.midiEvents[i].frame;
+ fNotes[note].on = fBlockStart;
fNotes[note].off = kNoteNull;
fNotes[note].velocity = velo;
break;
@@ -279,7 +150,7 @@ void DistrhoPluginKars::run(const float**, float** outputs, uint32_t frames, con
case 0x80:
note = data[1];
DISTRHO_SAFE_ASSERT_BREAK(note < 128); // kMaxNotes
- fNotes[note].off = fBlockStart + amsh.midiEvents[i].frame;
+ fNotes[note].off = fBlockStart;
break;
}
}