summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2014-10-12 11:12:17 +1100
committerDamien Zammit <damien@zamaudio.com>2014-10-12 11:12:17 +1100
commitd6b40348af534f6497aa7a90609dbd706b54ad65 (patch)
tree54adea7a30ae831c877bb1dce58a196096540885
parentbef37b553942ed8de3e6caed2e5a8f5dc065543d (diff)
parent28211b04bffad076dc47c3a2525174d03c4db958 (diff)
Merge pull request #23 from falkTX/master
Update for working OSX LV2/VST UIs
-rw-r--r--.gitignore2
-rw-r--r--Makefile3
-rw-r--r--libs/dgl/Geometry.hpp1
-rw-r--r--libs/dgl/Makefile5
-rw-r--r--libs/dgl/ntk/NtkApp.hpp205
-rw-r--r--libs/dgl/src/Geometry.cpp4
-rw-r--r--libs/dgl/src/Window.cpp87
-rw-r--r--libs/dgl/src/Window.mm17
-rw-r--r--libs/dgl/src/pugl/pugl_osx.m5
-rw-r--r--libs/distrho/DistrhoUIMain.cpp25
-rw-r--r--libs/distrho/extra/d_thread.hpp291
-rw-r--r--libs/distrho/src/DistrhoPluginLV2.cpp7
-rw-r--r--libs/distrho/src/DistrhoPluginLV2export.cpp2
-rw-r--r--libs/distrho/src/DistrhoPluginVST.cpp155
-rw-r--r--libs/distrho/src/DistrhoUIInternal.hpp8
-rwxr-xr-xlibs/generate-vst-bundles.sh33
-rw-r--r--libs/lv2-ttl-generator/GNUmakefile4
-rw-r--r--libs/lv2-ttl-generator/lv2_ttl_generator.c12
-rw-r--r--libs/plugin.vst/Contents/Info.plist24
-rw-r--r--libs/plugin.vst/Contents/MacOS/deleteme1
-rw-r--r--libs/plugin.vst/Contents/PkgInfo1
-rw-r--r--libs/plugin.vst/Contents/Resources/empty.lproj0
22 files changed, 741 insertions, 151 deletions
diff --git a/.gitignore b/.gitignore
index 8b013da..677f4ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,9 +7,11 @@
*.so
.kdev_include_paths
+.DS_Store
bin/*-dssi/
bin/*.lv2/
+bin/*.vst/
libs/lv2_ttl_generator
bin/ZamAutoSat
diff --git a/Makefile b/Makefile
index 50a9f26..feb4b7b 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,9 @@ libs: FORCE
gen: plugins libs/lv2_ttl_generator
@./libs/generate-ttl.sh
+ifeq ($(MACOS),true)
+ @./libs/generate-vst-bundles.sh
+endif
libs/lv2_ttl_generator:
$(MAKE) -C libs/lv2-ttl-generator
diff --git a/libs/dgl/Geometry.hpp b/libs/dgl/Geometry.hpp
index f9dba46..117c0a9 100644
--- a/libs/dgl/Geometry.hpp
+++ b/libs/dgl/Geometry.hpp
@@ -18,7 +18,6 @@
#define DGL_GEOMETRY_HPP_INCLUDED
#include "Base.hpp"
-#include <cmath>
START_NAMESPACE_DGL
diff --git a/libs/dgl/Makefile b/libs/dgl/Makefile
index 55439de..856af9a 100644
--- a/libs/dgl/Makefile
+++ b/libs/dgl/Makefile
@@ -62,10 +62,7 @@ all: $(TARGET)
%.cpp.o: %.cpp
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@
-%.m.o: %.m
- $(CC) $< $(BUILD_C_FLAGS) -ObjC -c -o $@
-
-%.mm.o: %.mm
+%.mm.o: %.cpp
$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@
# --------------------------------------------------------------
diff --git a/libs/dgl/ntk/NtkApp.hpp b/libs/dgl/ntk/NtkApp.hpp
index 5dc7b2d..2c32d56 100644
--- a/libs/dgl/ntk/NtkApp.hpp
+++ b/libs/dgl/ntk/NtkApp.hpp
@@ -18,6 +18,8 @@
#define DGL_NTK_APP_HPP_INCLUDED
#include "../Base.hpp"
+#include "../../distrho/DistrhoUI.hpp"
+#include "../../distrho/extra/d_thread.hpp"
#ifdef override
# define override_defined
@@ -35,36 +37,65 @@
# undef override_defined
#endif
+struct ScopedDisplayLock {
+ ScopedDisplayLock()
+ {
+#ifdef DISTRHO_OS_LINUX
+ XLockDisplay(fl_display);
+#endif
+ }
+
+ ~ScopedDisplayLock()
+ {
+#ifdef DISTRHO_OS_LINUX
+ XUnlockDisplay(fl_display);
+#endif
+ }
+};
+
+// -----------------------------------------------------------------------
+
+namespace DISTRHO_NAMESPACE {
+ class UI;
+}
+
START_NAMESPACE_DGL
class NtkWindow;
+typedef DISTRHO_NAMESPACE::Mutex d_Mutex;
+typedef DISTRHO_NAMESPACE::MutexLocker d_MutexLocker;
+typedef DISTRHO_NAMESPACE::Thread d_Thread;
+typedef DISTRHO_NAMESPACE::UI d_UI;
+
// -----------------------------------------------------------------------
/**
DGL compatible App class that uses NTK instead of OpenGL.
@see App
*/
-class NtkApp
+class NtkApp : d_Thread
{
public:
/**
Constructor.
*/
NtkApp()
- : fIsRunning(true),
- fWindows()
+ : d_Thread("NtkApp"),
+ fWindows(),
+ fWindowMutex(),
+ fNextUI(),
+ fDoNextUI(false),
+ fInitialized(false)
{
- static bool initialized = false;
-
- if (! initialized)
- {
- initialized = true;
- fl_register_images();
#ifdef DISTRHO_OS_LINUX
- fl_open_display();
+ //XInitThreads();
#endif
- }
+
+ startThread();
+
+ for (; ! fInitialized;)
+ d_msleep(10);
}
/**
@@ -72,20 +103,15 @@ public:
*/
~NtkApp()
{
- DISTRHO_SAFE_ASSERT(! fIsRunning);
-
+ stopThread(-1);
fWindows.clear();
}
/**
Idle function.
- This calls the NTK event-loop once (and all idle callbacks).
+ This calls does nothing.
*/
- void idle()
- {
- Fl::check();
- Fl::flush();
- }
+ void idle() {}
/**
Run the application event-loop until all Windows are closed.
@@ -93,9 +119,8 @@ public:
*/
void exec()
{
- fIsRunning = true;
- Fl::run();
- fIsRunning = false;
+ while (isThreadRunning() && ! shouldThreadExit())
+ d_sleep(1);
}
/**
@@ -104,13 +129,7 @@ public:
*/
void quit()
{
- fIsRunning = false;
-
- for (std::list<Fl_Double_Window*>::reverse_iterator rit = fWindows.rbegin(), rite = fWindows.rend(); rit != rite; ++rit)
- {
- Fl_Double_Window* const window(*rit);
- window->hide();
- }
+ signalThreadShouldExit();
}
/**
@@ -119,23 +138,91 @@ public:
*/
bool isQuiting() const noexcept
{
- return !fIsRunning;
+ if (isThreadRunning() && ! shouldThreadExit())
+ return false;
+ return true;
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ Create UI on our separate thread.
+ Blocks until the UI is created and returns it.
+ */
+ d_UI* createUI(void* const func)
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(isThreadRunning(), nullptr);
+ DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI, nullptr);
+
+ fNextUI.create = true;
+ fNextUI.func = (NextUI::UiFunc)func;
+ fDoNextUI = true;
+
+ for (; fDoNextUI;)
+ d_msleep(10);
+
+ return fNextUI.ui;
+ }
+
+ /**
+ Delete UI on our separate thread.
+ Blocks until the UI is deleted.
+ */
+ void deleteUI(d_UI* const ui)
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(! fDoNextUI,);
+
+ fNextUI.create = false;
+ fNextUI.ui = ui;
+ fDoNextUI = true;
+
+ if (isThreadRunning())
+ {
+ for (; fDoNextUI;)
+ d_msleep(10);
+ }
+ else
+ {
+ fNextUI.run();
+ fDoNextUI = false;
+ }
}
+ // -------------------------------------------------------------------
+
private:
- bool fIsRunning;
- std::list<Fl_Double_Window*> fWindows;
+ struct NextUI {
+ typedef d_UI* (*UiFunc)();
- friend class NtkWindow;
+ bool create;
+
+ union {
+ UiFunc func;
+ d_UI* ui;
+ };
+
+ NextUI()
+ : create(false),
+ func(nullptr) {}
+
+ void run();
+ };
+
+ std::list<Fl_Double_Window*> fWindows;
+ d_Mutex fWindowMutex;
+ NextUI fNextUI;
+ volatile bool fDoNextUI;
+ volatile bool fInitialized;
/** @internal used by NtkWindow. */
void addWindow(Fl_Double_Window* const window)
{
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);
- if (fWindows.size() == 0)
- fIsRunning = true;
+ if (fWindows.size() == 0 && ! isThreadRunning())
+ startThread();
+ const d_MutexLocker sl(fWindowMutex);
fWindows.push_back(window);
}
@@ -144,15 +231,59 @@ private:
{
DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,);
+ const d_MutexLocker sl(fWindowMutex);
fWindows.remove(window);
if (fWindows.size() == 0)
- fIsRunning = false;
+ signalThreadShouldExit();
+ }
+
+ /** @internal */
+ void run() override
+ {
+ static bool initialized = false;
+
+ if (! initialized)
+ {
+ initialized = true;
+ fl_register_images();
+#ifdef DISTRHO_OS_LINUX
+ fl_open_display();
+#endif
+ }
+
+ fInitialized = true;
+
+ for (; ! shouldThreadExit();)
+ {
+ if (fDoNextUI)
+ {
+ const ScopedDisplayLock csdl;
+ fNextUI.run();
+ fDoNextUI = false;
+ }
+
+ const ScopedDisplayLock csdl;
+ Fl::check();
+ Fl::flush();
+
+ d_msleep(20);
+ }
+
+ const d_MutexLocker sl(fWindowMutex);
+ const ScopedDisplayLock csdl;
+
+ for (std::list<Fl_Double_Window*>::reverse_iterator rit = fWindows.rbegin(), rite = fWindows.rend(); rit != rite; ++rit)
+ {
+ Fl_Double_Window* const window(*rit);
+ window->hide();
+ }
}
+ friend class NtkWindow;
+
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NtkApp)
};
-
// -----------------------------------------------------------------------
END_NAMESPACE_DGL
diff --git a/libs/dgl/src/Geometry.cpp b/libs/dgl/src/Geometry.cpp
index 4dc7e43..a7565fa 100644
--- a/libs/dgl/src/Geometry.cpp
+++ b/libs/dgl/src/Geometry.cpp
@@ -16,6 +16,8 @@
#include "../Geometry.hpp"
+#include <cmath>
+
START_NAMESPACE_DGL
static const float M_2PIf = 3.14159265358979323846f*2.0f;
@@ -627,7 +629,7 @@ void Circle<T>::_draw(const bool isOutline)
glBegin(isOutline ? GL_LINE_LOOP : GL_POLYGON);
- for (int i=0; i<fNumSegments; ++i)
+ for (uint i=0; i<fNumSegments; ++i)
{
glVertex2f(x + fPos.fX, y + fPos.fY);
diff --git a/libs/dgl/src/Window.cpp b/libs/dgl/src/Window.cpp
index 9d3c744..e31b75c 100644
--- a/libs/dgl/src/Window.cpp
+++ b/libs/dgl/src/Window.cpp
@@ -77,7 +77,8 @@ struct Window::PrivateData {
xWindow(0),
#elif defined(DISTRHO_OS_MAC)
fNeedsIdle(true),
- xWindow(nullptr),
+ mView(nullptr),
+ mWindow(nullptr),
#endif
leakDetector_PrivateData()
{
@@ -103,7 +104,8 @@ struct Window::PrivateData {
xWindow(0),
#elif defined(DISTRHO_OS_MAC)
fNeedsIdle(false),
- xWindow(nullptr),
+ mView(nullptr),
+ mWindow(nullptr),
#endif
leakDetector_PrivateData()
{
@@ -135,7 +137,8 @@ struct Window::PrivateData {
xWindow(0),
#elif defined(DISTRHO_OS_MAC)
fNeedsIdle(false),
- xWindow(nullptr),
+ mView(nullptr),
+ mWindow(nullptr),
#endif
leakDetector_PrivateData()
{
@@ -188,8 +191,14 @@ struct Window::PrivateData {
hwnd = impl->hwnd;
DISTRHO_SAFE_ASSERT(hwnd != 0);
#elif defined(DISTRHO_OS_MAC)
- xWindow = impl->window;
- DISTRHO_SAFE_ASSERT(xWindow != nullptr);
+ mView = impl->glview;
+ mWindow = impl->window;
+ DISTRHO_SAFE_ASSERT(mView != nullptr);
+ if (fUsingEmbed) {
+ DISTRHO_SAFE_ASSERT(mWindow == nullptr);
+ } else {
+ DISTRHO_SAFE_ASSERT(mWindow != nullptr);
+ }
#elif defined(DISTRHO_OS_LINUX)
xDisplay = impl->display;
xWindow = impl->win;
@@ -236,7 +245,8 @@ struct Window::PrivateData {
#if defined(DISTRHO_OS_WINDOWS)
hwnd = 0;
#elif defined(DISTRHO_OS_MAC)
- xWindow = nullptr;
+ mView = nullptr;
+ mWindow = nullptr;
#elif defined(DISTRHO_OS_LINUX)
xDisplay = nullptr;
xWindow = 0;
@@ -337,9 +347,12 @@ struct Window::PrivateData {
SetActiveWindow(hwnd);
SetFocus(hwnd);
#elif defined(DISTRHO_OS_MAC)
- // TODO
- //[NSApp activateIgnoringOtherApps:YES];
- //[xWindow makeKeyAndOrderFront:xWindow];
+ if (mWindow != nullptr)
+ {
+ // TODO
+ //[NSApp activateIgnoringOtherApps:YES];
+ //[mWindow makeKeyAndOrderFront:mWindow];
+ }
#elif defined(DISTRHO_OS_LINUX)
XRaiseWindow(xDisplay, xWindow);
XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime);
@@ -378,9 +391,19 @@ struct Window::PrivateData {
UpdateWindow(hwnd);
#elif defined(DISTRHO_OS_MAC)
if (yesNo)
- [xWindow setIsVisible:YES];
+ {
+ if (mWindow != nullptr)
+ [mWindow setIsVisible:YES];
+ else
+ [mView setHidden:NO];
+ }
else
- [xWindow setIsVisible:NO];
+ {
+ if (mWindow != nullptr)
+ [mWindow setIsVisible:NO];
+ else
+ [mView setHidden:YES];
+ }
#elif defined(DISTRHO_OS_LINUX)
if (yesNo)
XMapRaised(xDisplay, xWindow);
@@ -421,6 +444,12 @@ struct Window::PrivateData {
fResizable = yesNo;
+#ifdef CARLA_OS_MAC
+ // FIXME?
+ const uint flags(yesNo ? (NSViewWidthSizable|NSViewHeightSizable) : 0x0);
+ [mView setAutoresizingMask:flags];
+#endif
+
setSize(fWidth, fHeight, true);
}
@@ -459,18 +488,12 @@ struct Window::PrivateData {
if (! forced)
UpdateWindow(hwnd);
#elif defined(DISTRHO_OS_MAC)
- [xWindow setContentSize:NSMakeSize(width, height)];
-# if 0
- NSRect frame = [xWindow frame];
- frame.origin.y -= height - frame.size.height;
- frame.size.width = width;
- frame.size.height = height+20;
-
- //if (forced)
- // [xWindow setFrame:frame];
- //else
- [xWindow setFrame:frame display:YES animate:NO];
-# endif
+ [mView setFrame:NSMakeRect(0, 0, width, height)];
+
+ if (mWindow != nullptr)
+ {
+ [mWindow setContentSize:NSMakeSize(width, height)];
+ }
#elif defined(DISTRHO_OS_LINUX)
XResizeWindow(xDisplay, xWindow, width, height);
@@ -506,12 +529,15 @@ struct Window::PrivateData {
#if defined(DISTRHO_OS_WINDOWS)
SetWindowTextA(hwnd, title);
#elif defined(DISTRHO_OS_MAC)
- NSString* titleString = [[NSString alloc]
- initWithBytes:title
- length:strlen(title)
- encoding:NSUTF8StringEncoding];
+ if (mWindow != nullptr)
+ {
+ NSString* titleString = [[NSString alloc]
+ initWithBytes:title
+ length:strlen(title)
+ encoding:NSUTF8StringEncoding];
- [xWindow setTitle:titleString];
+ [mWindow setTitle:titleString];
+ }
#elif defined(DISTRHO_OS_LINUX)
XStoreName(xDisplay, xWindow, title);
#endif
@@ -815,8 +841,9 @@ struct Window::PrivateData {
Display* xDisplay;
::Window xWindow;
#elif defined(DISTRHO_OS_MAC)
- bool fNeedsIdle;
- id xWindow;
+ bool fNeedsIdle;
+ PuglOpenGLView* mView;
+ id mWindow;
#endif
// -------------------------------------------------------------------
diff --git a/libs/dgl/src/Window.mm b/libs/dgl/src/Window.mm
deleted file mode 100644
index 9d3e0b1..0000000
--- a/libs/dgl/src/Window.mm
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * DISTRHO Plugin Framework (DPF)
- * Copyright (C) 2012-2014 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
- * permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "Window.cpp"
diff --git a/libs/dgl/src/pugl/pugl_osx.m b/libs/dgl/src/pugl/pugl_osx.m
index b8a8131..96aa57a 100644
--- a/libs/dgl/src/pugl/pugl_osx.m
+++ b/libs/dgl/src/pugl/pugl_osx.m
@@ -125,6 +125,8 @@ puglDisplay(PuglView* view)
{
colorBits = numColorBits;
depthBits = numDepthBits;
+ puglview = nil;
+ trackingArea = nil;
NSOpenGLPixelFormatAttribute pixelAttribs[16] = {
NSOpenGLPFADoubleBuffer,
@@ -375,8 +377,7 @@ puglCreateWindow(PuglView* view, const char* title)
if (view->parent) {
NSView* pview = (NSView*)view->parent;
[pview addSubview:impl->glview];
- [impl->glview setHidden:NO];
- return 0;
+ return 0;
}
id window = [[PuglWindow new]retain];
diff --git a/libs/distrho/DistrhoUIMain.cpp b/libs/distrho/DistrhoUIMain.cpp
index cb1cb6e..3bc0971 100644
--- a/libs/distrho/DistrhoUIMain.cpp
+++ b/libs/distrho/DistrhoUIMain.cpp
@@ -27,3 +27,28 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST)
// nothing
#endif
+
+#ifdef DGL_NTK_APP_HPP_INCLUDED
+
+START_NAMESPACE_DGL
+
+void NtkApp::NextUI::run()
+{
+ if (create)
+ {
+ d_stdout("Creating NTK UI in separate thread...");
+ d_UI* const ui2 = (func)();
+ ui = ui2;
+ }
+ else
+ {
+ d_stdout("Destroying NTK UI in separate thread...");
+ d_UI* const ui2 = ui;
+ ui = nullptr;
+ delete ui2;
+ }
+}
+
+END_NAMESPACE_DGL
+
+#endif
diff --git a/libs/distrho/extra/d_thread.hpp b/libs/distrho/extra/d_thread.hpp
new file mode 100644
index 0000000..9a7b2a9
--- /dev/null
+++ b/libs/distrho/extra/d_thread.hpp
@@ -0,0 +1,291 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2014 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
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DISTRHO_THREAD_HPP_INCLUDED
+#define DISTRHO_THREAD_HPP_INCLUDED
+
+#include "d_mutex.hpp"
+#include "d_sleep.hpp"
+#include "d_string.hpp"
+
+#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
+// has pthread_setname_np
+#elif defined(DISTRHO_OS_LINUX)
+# include <sys/prctl.h>
+#endif
+
+START_NAMESPACE_DISTRHO
+
+// -----------------------------------------------------------------------
+// Thread class
+
+class Thread
+{
+protected:
+ /*
+ * Constructor.
+ */
+ Thread(const char* const threadName = nullptr) noexcept
+ : fLock(),
+ fName(threadName),
+#ifdef PTW32_DLLPORT
+ fHandle({nullptr, 0}),
+#else
+ fHandle(0),
+#endif
+ fShouldExit(false) {}
+
+ /*
+ * Destructor.
+ */
+ virtual ~Thread() /*noexcept*/
+ {
+ DISTRHO_SAFE_ASSERT(! isThreadRunning());
+
+ stopThread(-1);
+ }
+
+ /*
+ * Virtual function to be implemented by the subclass.
+ */
+ virtual void run() = 0;
+
+ // -------------------------------------------------------------------
+
+public:
+ /*
+ * Check if the thread is running.
+ */
+ bool isThreadRunning() const noexcept
+ {
+#ifdef PTW32_DLLPORT
+ return (fHandle.p != nullptr);
+#else
+ return (fHandle != 0);
+#endif
+ }
+
+ /*
+ * Check if the thread should exit.
+ */
+ bool shouldThreadExit() const noexcept
+ {
+ return fShouldExit;
+ }
+
+ /*
+ * Start the thread.
+ */
+ bool startThread() noexcept
+ {
+ // check if already running
+ DISTRHO_SAFE_ASSERT_RETURN(! isThreadRunning(), true);
+
+ const MutexLocker cml(fLock);
+
+ fShouldExit = false;
+
+ pthread_t handle;
+
+ if (pthread_create(&handle, nullptr, _entryPoint, this) == 0)
+ {
+#ifdef PTW32_DLLPORT
+ DISTRHO_SAFE_ASSERT_RETURN(handle.p != nullptr, false);
+#else
+ DISTRHO_SAFE_ASSERT_RETURN(handle != 0, false);
+#endif
+ pthread_detach(handle);
+ _copyFrom(handle);
+
+ // wait for thread to start
+ fLock.lock();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /*
+ * Stop the thread.
+ * In the 'timeOutMilliseconds':
+ * = 0 -> no wait
+ * > 0 -> wait timeout value
+ * < 0 -> wait forever
+ */
+ bool stopThread(const int timeOutMilliseconds) noexcept
+ {
+ const MutexLocker cml(fLock);
+
+ if (isThreadRunning())
+ {
+ signalThreadShouldExit();
+
+ if (timeOutMilliseconds != 0)
+ {
+ // Wait for the thread to stop
+ int timeOutCheck = (timeOutMilliseconds == 1 || timeOutMilliseconds == -1) ? timeOutMilliseconds : timeOutMilliseconds/2;
+
+ for (; isThreadRunning();)
+ {
+ d_msleep(2);
+
+ if (timeOutCheck < 0)
+ continue;
+
+ if (timeOutCheck > 0)
+ timeOutCheck -= 1;
+ else
+ break;
+ }
+ }
+
+ if (isThreadRunning())
+ {
+ // should never happen!
+ d_stderr2("Carla assertion failure: \"! isThreadRunning()\" in file %s, line %i", __FILE__, __LINE__);
+
+ // copy thread id so we can clear our one
+ pthread_t threadId;
+ _copyTo(threadId);
+ _init();
+
+ try {
+ pthread_cancel(threadId);
+ } DISTRHO_SAFE_EXCEPTION("pthread_cancel");
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /*
+ * Tell the thread to stop as soon as possible.
+ */
+ void signalThreadShouldExit() noexcept
+ {
+ fShouldExit = true;
+ }
+
+ // -------------------------------------------------------------------
+
+ /*
+ * Returns the name of the thread.
+ * This is the name that gets set in the constructor.
+ */
+ const d_string& getThreadName() const noexcept
+ {
+ return fName;
+ }
+
+ /*
+ * Changes the name of the caller thread.
+ */
+ static void setCurrentThreadName(const char* const name) noexcept
+ {
+ DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
+
+#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012
+ pthread_setname_np(pthread_self(), name);
+#elif defined(DISTRHO_OS_LINUX)
+ prctl(PR_SET_NAME, name, 0, 0, 0);
+#endif
+ }
+
+ // -------------------------------------------------------------------
+
+private:
+ Mutex fLock; // Thread lock
+ const d_string fName; // Thread name
+ volatile pthread_t fHandle; // Handle for this thread
+ volatile bool fShouldExit; // true if thread should exit
+
+ /*
+ * Init pthread type.
+ */
+ void _init() noexcept
+ {
+#ifdef PTW32_DLLPORT
+ fHandle.p = nullptr;
+ fHandle.x = 0;
+#else
+ fHandle = 0;
+#endif
+ }
+
+ /*
+ * Copy our pthread type from another var.
+ */
+ void _copyFrom(const pthread_t& handle) noexcept
+ {
+#ifdef PTW32_DLLPORT
+ fHandle.p = handle.p;
+ fHandle.x = handle.x;
+#else
+ fHandle = handle;
+#endif
+ }
+
+ /*
+ * Copy our pthread type to another var.
+ */
+ void _copyTo(volatile pthread_t& handle) const noexcept
+ {
+#ifdef PTW32_DLLPORT
+ handle.p = fHandle.p;
+ handle.x = fHandle.x;
+#else
+ handle = fHandle;
+#endif
+ }
+
+ /*
+ * Thread entry point.
+ */
+ void _runEntryPoint() noexcept
+ {
+ // report ready
+ fLock.unlock();
+
+ setCurrentThreadName(fName);
+
+ try {
+ run();
+ } catch(...) {}
+
+ // done
+ _init();
+ }
+
+ /*
+ * Thread entry point.
+ */
+ static void* _entryPoint(void* userData) noexcept
+ {
+ static_cast<Thread*>(userData)->_runEntryPoint();
+ return nullptr;
+ }
+
+ DISTRHO_DECLARE_NON_COPY_CLASS(Thread)
+};
+
+// -----------------------------------------------------------------------
+
+END_NAMESPACE_DISTRHO
+
+#endif // DISTRHO_THREAD_HPP_INCLUDED
diff --git a/libs/distrho/src/DistrhoPluginLV2.cpp b/libs/distrho/src/DistrhoPluginLV2.cpp
index ba3c1c7..2739338 100644
--- a/libs/distrho/src/DistrhoPluginLV2.cpp
+++ b/libs/distrho/src/DistrhoPluginLV2.cpp
@@ -127,6 +127,9 @@ public:
{
fNeededUiSends = nullptr;
}
+#else
+ // unused
+ (void)fWorker;
#endif
#if DISTRHO_PLUGIN_WANT_TIMEPOS
@@ -537,7 +540,7 @@ public:
const d_string& key = fPlugin.getStateKey(i);
- for (StringMap::const_iterator cit=fStateMap.cbegin(), cite=fStateMap.cend(); cit != cite; ++cit)
+ for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const d_string& curKey = cit->first;
@@ -679,7 +682,7 @@ public:
#if DISTRHO_PLUGIN_WANT_STATE
LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle)
{
- for (StringMap::const_iterator cit=fStateMap.cbegin(), cite=fStateMap.cend(); cit != cite; ++cit)
+ for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const d_string& key = cit->first;
const d_string& value = cit->second;
diff --git a/libs/distrho/src/DistrhoPluginLV2export.cpp b/libs/distrho/src/DistrhoPluginLV2export.cpp
index fbc9340..c362d41 100644
--- a/libs/distrho/src/DistrhoPluginLV2export.cpp
+++ b/libs/distrho/src/DistrhoPluginLV2export.cpp
@@ -88,7 +88,7 @@ void lv2_generate_ttl(const char* const basename)
manifestString += "<" DISTRHO_UI_URI ">\n";
# if DISTRHO_OS_HAIKU
manifestString += " a ui:BeUI ;\n";
-# elif DISTRHO_OS_MACOS
+# elif DISTRHO_OS_MAC
manifestString += " a ui:CocoaUI ;\n";
# elif DISTRHO_OS_WINDOWS
manifestString += " a ui:WindowsUI ;\n";
diff --git a/libs/distrho/src/DistrhoPluginVST.cpp b/libs/distrho/src/DistrhoPluginVST.cpp
index 542c6e3..703ad79 100644
--- a/libs/distrho/src/DistrhoPluginVST.cpp
+++ b/libs/distrho/src/DistrhoPluginVST.cpp
@@ -295,7 +295,15 @@ public:
parameterValues[i] = 0.0f;
}
}
-#endif
+# if DISTRHO_OS_MAC
+# ifdef __LP64__
+ fUsingNsView = true;
+# else
+# warning 32bit VST UIs on OSX only work if the host supports "hasCockosViewAsConfig"
+ fUsingNsView = false;
+# endif
+# endif // DISTRHO_OS_MAC
+#endif // DISTRHO_PLUGIN_HAS_UI
#if DISTRHO_PLUGIN_WANT_STATE
fStateChunk = nullptr;
@@ -407,16 +415,20 @@ public:
case effEditOpen:
if (fVstUI == nullptr)
{
-# if DISTRHO_OS_MAC && ! defined(__LP64__)
- if ((fEffect->dispatcher(fEffect, effCanDo, 0, 0, (void*)"hasCockosViewAsConfig", 0.0f) & 0xffff0000) != 0xbeef0000)
+# if DISTRHO_OS_MAC
+ if (! fUsingNsView)
+ {
+ d_stderr("Host doesn't support hasCockosViewAsConfig, cannot use UI");
return 0;
+ }
# endif
d_lastUiSampleRate = fPlugin.getSampleRate();
+ d_stdout("effEditOpen with ptr = %p", ptr);
fVstUI = new UIVst(fAudioMaster, fEffect, this, &fPlugin, (intptr_t)ptr);
# if DISTRHO_PLUGIN_WANT_STATE
- for (StringMap::const_iterator cit=fStateMap.cbegin(), cite=fStateMap.cend(); cit != cite; ++cit)
+ for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const d_string& key = cit->first;
const d_string& value = cit->second;
@@ -469,7 +481,7 @@ public:
{
d_string chunkStr;
- for (StringMap::const_iterator cit=fStateMap.cbegin(), cite=fStateMap.cend(); cit != cite; ++cit)
+ for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const d_string& key = cit->first;
const d_string& value = cit->second;
@@ -568,27 +580,36 @@ public:
}
break;
+#if DISTRHO_PLUGIN_HAS_MIDI_INPUT || DISTRHO_PLUGIN_HAS_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_OS_MAC
case effCanDo:
if (const char* const canDo = (const char*)ptr)
{
-#if DISTRHO_PLUGIN_HAS_MIDI_INPUT
+# if DISTRHO_OS_MAC
+ if (std::strcmp(canDo, "hasCockosViewAsConfig") == 0)
+ {
+ fUsingNsView = true;
+ return 0xbeef0000;
+ }
+# endif
+# if DISTRHO_PLUGIN_HAS_MIDI_INPUT
if (std::strcmp(canDo, "receiveVstEvents") == 0)
return 1;
if (std::strcmp(canDo, "receiveVstMidiEvent") == 0)
return 1;
-#endif
-#if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT
+# endif
+# if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT
if (std::strcmp(canDo, "sendVstEvents") == 0)
return 1;
if (std::strcmp(canDo, "sendVstMidiEvent") == 0)
return 1;
-#endif
-#if DISTRHO_PLUGIN_WANT_TIMEPOS
+# endif
+# if DISTRHO_PLUGIN_WANT_TIMEPOS
if (std::strcmp(canDo, "receiveVstTimeInfo") == 0)
return 1;
-#endif
+# endif
}
break;
+#endif
//case effStartProcess:
//case effStopProcess:
@@ -710,6 +731,9 @@ private:
#if DISTRHO_PLUGIN_HAS_UI
UIVst* fVstUI;
ERect fVstRect;
+# if DISTRHO_OS_MAC
+ bool fUsingNsView;
+# endif
#endif
#if DISTRHO_PLUGIN_WANT_STATE
@@ -759,14 +783,23 @@ private:
// -----------------------------------------------------------------------
+struct VstObject {
+ audioMasterCallback audioMaster;
+ PluginVst* plugin;
+};
+
#ifdef VESTIGE_HEADER
-# define handlePtr ((PluginVst*)effect->ptr2)
-# define validEffect effect != nullptr && effect->ptr2 != nullptr
+# define validObject effect != nullptr && effect->ptr3 != nullptr
+# define validPlugin effect != nullptr && effect->ptr3 != nullptr && ((VstObject*)effect->ptr3)->plugin != nullptr
+# define vstObjectPtr (VstObject*)effect->ptr3
#else
-# define handlePtr ((PluginVst*)effect->resvd2)
-# define validEffect effect != nullptr && effect->resvd2 != 0
+# define validObject effect != nullptr && effect->object != nullptr
+# define validPlugin effect != nullptr && effect->object != nullptr && ((VstObject*)effect->object)->plugin != nullptr
+# define vstObjectPtr (VstObject*)effect->object
#endif
+#define pluginPtr (vstObjectPtr)->plugin
+
static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt)
{
// first internal init
@@ -796,15 +829,16 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t
switch (opcode)
{
case effOpen:
-#ifdef VESTIGE_HEADER
- if (effect != nullptr && effect->ptr3 != nullptr)
- {
- audioMasterCallback audioMaster = (audioMasterCallback)effect->ptr3;
-#else
- if (effect != nullptr && effect->object != nullptr)
+ if (VstObject* const obj = vstObjectPtr)
{
- audioMasterCallback audioMaster = (audioMasterCallback)effect->object;
-#endif
+ // this must always be valid
+ DISTRHO_SAFE_ASSERT_RETURN(obj->audioMaster != nullptr, 0);
+
+ // some hosts call effOpen twice
+ DISTRHO_SAFE_ASSERT_RETURN(obj->plugin == nullptr, 1);
+
+ audioMasterCallback audioMaster = (audioMasterCallback)obj->audioMaster;
+
d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f);
d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f);
@@ -814,31 +848,35 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t
if (d_lastSampleRate <= 0.0)
d_lastSampleRate = 44100.0;
- PluginVst* const plugin(new PluginVst(audioMaster, effect));
-#ifdef VESTIGE_HEADER
- effect->ptr2 = plugin;
-#else
- effect->resvd2 = (intptr_t)plugin;
-#endif
+ obj->plugin = new PluginVst(audioMaster, effect);
return 1;
}
return 0;
case effClose:
- if (validEffect)
+ if (VstObject* const obj = vstObjectPtr)
{
-#ifdef VESTIGE_HEADER
- delete (PluginVst*)effect->ptr2;
- effect->ptr2 = nullptr;
+ if (obj->plugin != nullptr)
+ {
+ delete obj->plugin;
+ obj->plugin = nullptr;
+ }
+
+#if 0
+ /* This code invalidates the object created in VSTPluginMain
+ * Probably not safe against all hosts */
+ obj->audioMaster = nullptr;
+# ifdef VESTIGE_HEADER
effect->ptr3 = nullptr;
-#else
- delete (PluginVst*)effect->resvd2;
- effect->resvd2 = 0;
- effect->object = nullptr;
+# else
+ vstObjectPtr = nullptr;
+# endif
+ delete obj;
#endif
- delete effect;
+
return 1;
}
+ //delete effect;
return 0;
case effGetParamLabel:
@@ -896,45 +934,48 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t
};
// handle advanced opcodes
- if (validEffect)
- return handlePtr->vst_dispatcher(opcode, index, value, ptr, opt);
+ if (validPlugin)
+ return pluginPtr->vst_dispatcher(opcode, index, value, ptr, opt);
return 0;
}
static float vst_getParameterCallback(AEffect* effect, int32_t index)
{
- if (validEffect)
- return handlePtr->vst_getParameter(index);
+ if (validPlugin)
+ return pluginPtr->vst_getParameter(index);
return 0.0f;
}
static void vst_setParameterCallback(AEffect* effect, int32_t index, float value)
{
- if (validEffect)
- handlePtr->vst_setParameter(index, value);
+ if (validPlugin)
+ pluginPtr->vst_setParameter(index, value);
}
static void vst_processCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
{
- if (validEffect)
- handlePtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
+ if (validPlugin)
+ pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
}
static void vst_processReplacingCallback(AEffect* effect, float** inputs, float** outputs, int32_t sampleFrames)
{
- if (validEffect)
- handlePtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
+ if (validPlugin)
+ pluginPtr->vst_processReplacing(const_cast<const float**>(inputs), outputs, sampleFrames);
}
-#undef handlePtr
+#undef pluginPtr
+#undef validObject
+#undef validPlugin
+#undef vstObjectPtr
// -----------------------------------------------------------------------
END_NAMESPACE_DISTRHO
DISTRHO_PLUGIN_EXPORT
-#if DISTRHO_OS_WINDOWS
+#if DISTRHO_OS_WINDOWS || DISTRHO_OS_MAC
const AEffect* VSTPluginMain(audioMasterCallback audioMaster);
#else
const AEffect* VSTPluginMain(audioMasterCallback audioMaster) asm ("main");
@@ -969,11 +1010,18 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
// VST doesn't support parameter outputs, hide them
int numParams = 0;
+ bool outputsReached = false;
for (uint32_t i=0, count=plugin->getParameterCount(); i < count; ++i)
{
if (! plugin->isParameterOutput(i))
+ {
+ // parameter outputs must be all at the end
+ DISTRHO_SAFE_ASSERT_BREAK(! outputsReached);
++numParams;
+ continue;
+ }
+ outputsReached = true;
}
// plugin fields
@@ -1002,10 +1050,13 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster)
effect->processReplacing = vst_processReplacingCallback;
// pointers
+ VstObject* const obj(new VstObject());
+ obj->audioMaster = audioMaster;
+ obj->plugin = nullptr;
#ifdef VESTIGE_HEADER
- effect->ptr3 = (void*)audioMaster;
+ effect->ptr3 = obj;
#else
- effect->object = (void*)audioMaster;
+ effect->object = obj;
#endif
return effect;
diff --git a/libs/distrho/src/DistrhoUIInternal.hpp b/libs/distrho/src/DistrhoUIInternal.hpp
index e5b5376..6bd421c 100644
--- a/libs/distrho/src/DistrhoUIInternal.hpp
+++ b/libs/distrho/src/DistrhoUIInternal.hpp
@@ -141,7 +141,11 @@ UI* createUiWrapper(void* const dspPtr, UIWindow* const window)
{
d_lastUiDspPtr = dspPtr;
d_lastUiWindow = window;
+#if DISTRHO_UI_USE_NTK
+ UI* const ret = window->getApp().createUI((void*)createUI);
+#else
UI* const ret = createUI();
+#endif
d_lastUiDspPtr = nullptr;
d_lastUiWindow = nullptr;
return ret;
@@ -164,7 +168,11 @@ public:
~UIExporterWindow()
{
+#if DISTRHO_UI_USE_NTK
+ getApp().deleteUI(fUI);
+#else
delete fUI;
+#endif
}
UI* getUI() const noexcept
diff --git a/libs/generate-vst-bundles.sh b/libs/generate-vst-bundles.sh
new file mode 100755
index 0000000..5f17687
--- /dev/null
+++ b/libs/generate-vst-bundles.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+if [ -d bin ]; then
+ cd bin
+else
+ echo "Please run this script from the root folder"
+ exit
+fi
+
+PWD=`pwd`
+
+if [ ! -d /System/Library ]; then
+ echo "This doesn't seem to be OSX, please stop!"
+ exit 0
+fi
+
+rm -rf *.vst/
+
+PLUGINS=`ls | grep vst.dylib`
+
+for i in $PLUGINS; do
+ FILE=`echo $i | awk 'sub("-vst.dylib","")'`
+ cp -r ../libs/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
+ SetFile -a B $FILE.vst
+done
+
+cd ..
diff --git a/libs/lv2-ttl-generator/GNUmakefile b/libs/lv2-ttl-generator/GNUmakefile
index a4c9f63..0052be4 100644
--- a/libs/lv2-ttl-generator/GNUmakefile
+++ b/libs/lv2-ttl-generator/GNUmakefile
@@ -9,10 +9,10 @@ build: ../lv2_ttl_generator
endif
../lv2_ttl_generator: lv2_ttl_generator.c
- $(CXX) lv2_ttl_generator.c -o ../lv2_ttl_generator -ldl
+ $(CC) lv2_ttl_generator.c -o ../lv2_ttl_generator -ldl
../lv2_ttl_generator.exe: lv2_ttl_generator.c
- $(CXX) lv2_ttl_generator.c -o ../lv2_ttl_generator.exe -static
+ $(CC) lv2_ttl_generator.c -o ../lv2_ttl_generator.exe -static
touch ../lv2_ttl_generator
clean:
diff --git a/libs/lv2-ttl-generator/lv2_ttl_generator.c b/libs/lv2-ttl-generator/lv2_ttl_generator.c
index 18b7508..5ef2b14 100644
--- a/libs/lv2-ttl-generator/lv2_ttl_generator.c
+++ b/libs/lv2-ttl-generator/lv2_ttl_generator.c
@@ -53,16 +53,24 @@ int main(int argc, char* argv[])
char basename[strlen(argv[1])+1];
#ifdef TTL_GENERATOR_WINDOWS
- if (char* base2 = strrchr(argv[1], '\\'))
+ char* base2 = strrchr(argv[1], '\\');
#else
- if (char* base2 = strrchr(argv[1], '/'))
+ char* base2 = strrchr(argv[1], '/');
#endif
+ if (base2 != NULL)
{
strcpy(basename, base2+1);
basename[strrchr(base2, '.')-base2-1] = '\0';
}
+ else if (argv[1][0] == '.' && argv[1][1] == '/')
+ {
+ strcpy(basename, argv[1]+2);
+ basename[strrchr(basename, '.')-basename] = '\0';
+ }
else
+ {
strcpy(basename, argv[1]);
+ }
printf("Generate ttl data for '%s', basename: '%s'\n", argv[1], basename);
diff --git a/libs/plugin.vst/Contents/Info.plist b/libs/plugin.vst/Contents/Info.plist
new file mode 100644
index 0000000..df723b5
--- /dev/null
+++ b/libs/plugin.vst/Contents/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>X-PROJECTNAME-X</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>net.sf.distrho.X-PROJECTNAME-X</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/libs/plugin.vst/Contents/MacOS/deleteme b/libs/plugin.vst/Contents/MacOS/deleteme
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/libs/plugin.vst/Contents/MacOS/deleteme
@@ -0,0 +1 @@
+
diff --git a/libs/plugin.vst/Contents/PkgInfo b/libs/plugin.vst/Contents/PkgInfo
new file mode 100644
index 0000000..43c9cb0
--- /dev/null
+++ b/libs/plugin.vst/Contents/PkgInfo
@@ -0,0 +1 @@
+BNDL????
diff --git a/libs/plugin.vst/Contents/Resources/empty.lproj b/libs/plugin.vst/Contents/Resources/empty.lproj
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/plugin.vst/Contents/Resources/empty.lproj