diff options
author | Damien Zammit <damien@zamaudio.com> | 2014-10-12 11:12:17 +1100 |
---|---|---|
committer | Damien Zammit <damien@zamaudio.com> | 2014-10-12 11:12:17 +1100 |
commit | d6b40348af534f6497aa7a90609dbd706b54ad65 (patch) | |
tree | 54adea7a30ae831c877bb1dce58a196096540885 | |
parent | bef37b553942ed8de3e6caed2e5a8f5dc065543d (diff) | |
parent | 28211b04bffad076dc47c3a2525174d03c4db958 (diff) |
Merge pull request #23 from falkTX/master
Update for working OSX LV2/VST UIs
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | libs/dgl/Geometry.hpp | 1 | ||||
-rw-r--r-- | libs/dgl/Makefile | 5 | ||||
-rw-r--r-- | libs/dgl/ntk/NtkApp.hpp | 205 | ||||
-rw-r--r-- | libs/dgl/src/Geometry.cpp | 4 | ||||
-rw-r--r-- | libs/dgl/src/Window.cpp | 87 | ||||
-rw-r--r-- | libs/dgl/src/Window.mm | 17 | ||||
-rw-r--r-- | libs/dgl/src/pugl/pugl_osx.m | 5 | ||||
-rw-r--r-- | libs/distrho/DistrhoUIMain.cpp | 25 | ||||
-rw-r--r-- | libs/distrho/extra/d_thread.hpp | 291 | ||||
-rw-r--r-- | libs/distrho/src/DistrhoPluginLV2.cpp | 7 | ||||
-rw-r--r-- | libs/distrho/src/DistrhoPluginLV2export.cpp | 2 | ||||
-rw-r--r-- | libs/distrho/src/DistrhoPluginVST.cpp | 155 | ||||
-rw-r--r-- | libs/distrho/src/DistrhoUIInternal.hpp | 8 | ||||
-rwxr-xr-x | libs/generate-vst-bundles.sh | 33 | ||||
-rw-r--r-- | libs/lv2-ttl-generator/GNUmakefile | 4 | ||||
-rw-r--r-- | libs/lv2-ttl-generator/lv2_ttl_generator.c | 12 | ||||
-rw-r--r-- | libs/plugin.vst/Contents/Info.plist | 24 | ||||
-rw-r--r-- | libs/plugin.vst/Contents/MacOS/deleteme | 1 | ||||
-rw-r--r-- | libs/plugin.vst/Contents/PkgInfo | 1 | ||||
-rw-r--r-- | libs/plugin.vst/Contents/Resources/empty.lproj | 0 |
22 files changed, 741 insertions, 151 deletions
@@ -7,9 +7,11 @@ *.so .kdev_include_paths +.DS_Store bin/*-dssi/ bin/*.lv2/ +bin/*.vst/ libs/lv2_ttl_generator bin/ZamAutoSat @@ -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 |