diff --git a/data/copy-dpf-stuff b/data/copy-dpf-stuff index ea4f619a8..35c0803bc 100755 --- a/data/copy-dpf-stuff +++ b/data/copy-dpf-stuff @@ -2,33 +2,33 @@ set -e -# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DPF/dgl/*.hpp /home/falktx/FOSS/GIT-mine/Carla/source/modules/dgl/ -# cp -r -v /home/falktx/FOSS/GIT-mine/DISTRHO/DPF/dgl/src /home/falktx/FOSS/GIT-mine/Carla/source/modules/dgl/ - -cp -r -v /home/falktx/FOSS/GIT-mine/DISTRHO/DPF/distrho/* /home/falktx/FOSS/GIT-mine/Carla/source/modules/distrho/ - -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_mini-series/plugins/3BandEQ/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/3bandeq/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_mini-series/plugins/3BandSplitter/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/3bandsplitter/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_mini-series/plugins/PingPongPan/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/pingpongpan/ - -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_nekobi/plugins/Nekobi/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/nekobi/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_nekobi/plugins/Nekobi/nekobee-src/{*.c,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/nekobi/nekobee-src/ - -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_prom/plugins/ProM/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/prom/ - -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/GrooveJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/groovejuice/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/PowerJuice/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/powerjuice/ -# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/PowerJuiceX2/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/powerjuicex2/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/SegmentJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/segmentjuice/ -# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/StutterJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/stutterjuice/ -# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/TriggerJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/triggerjuice/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/VectorJuice/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/vectorjuice/ -cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/WobbleJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/wobblejuice/ - -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamComp/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zamcomp/ -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamCompX2/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zamcompx2/ -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamEQ2/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zameq2/ -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamSynth/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zamsynth/ -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamTube/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zamtube/ -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZaMultiComp/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zamulticomp/ -cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZaMultiCompX2/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/Carla/source/modules/native-plugins/zamulticompx2/ +cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DPF/dgl/*.hpp /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/dgl/ +cp -r -v /home/falktx/FOSS/GIT-mine/DISTRHO/DPF/dgl/src /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/dgl/ + +cp -r -v /home/falktx/FOSS/GIT-mine/DISTRHO/DPF/distrho/* /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/distrho/ + +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_mini-series/plugins/3BandEQ/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/3bandeq/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_mini-series/plugins/3BandSplitter/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/3bandsplitter/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_mini-series/plugins/PingPongPan/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/pingpongpan/ +# +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_nekobi/plugins/Nekobi/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/nekobi/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_nekobi/plugins/Nekobi/nekobee-src/{*.c,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/nekobi/nekobee-src/ +# +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/DISTRHO_prom/plugins/ProM/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/prom/ +# +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/GrooveJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/groovejuice/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/PowerJuice/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/powerjuice/ +# # cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/PowerJuiceX2/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/powerjuicex2/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/SegmentJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/segmentjuice/ +# # cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/StutterJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/stutterjuice/ +# # cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/TriggerJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/triggerjuice/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/VectorJuice/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/vectorjuice/ +# cp -v /home/falktx/FOSS/GIT-mine/DISTRHO/JuicePlugins/plugins/WobbleJuice/{*.cpp,*.hpp,*.hxx,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/wobblejuice/ +# +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamComp/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zamcomp/ +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamCompX2/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zamcompx2/ +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamEQ2/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zameq2/ +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamSynth/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zamsynth/ +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZamTube/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zamtube/ +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZaMultiComp/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zamulticomp/ +# cp -v /home/falktx/FOSS/GIT-mine/zam-plugins-DPF/plugins/ZaMultiCompX2/{*.cpp,*.hpp,*.h} /home/falktx/FOSS/GIT-mine/falkTX/Carla/source/modules/native-plugins/zamulticompx2/ diff --git a/source/modules/dgl/NanoVG.hpp b/source/modules/dgl/NanoVG.hpp index 322c6cf8a..a7e68cac9 100644 --- a/source/modules/dgl/NanoVG.hpp +++ b/source/modules/dgl/NanoVG.hpp @@ -192,10 +192,10 @@ private: @code const char* txt = "Text me up."; - textBounds(vg, x,y, txt, NULL, bounds); - beginPath(vg); - roundedRect(vg, bounds[0], bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); - fill(vg); + vg.textBounds(x,y, txt, NULL, bounds); + vg.beginPath(); + vg.roundedRect(bounds[0], bounds[1], bounds[2]-bounds[0], bounds[3]-bounds[1]); + vg.fill(); @endcode Note: currently only solid color fill is supported for text. diff --git a/source/modules/dgl/Widget.hpp b/source/modules/dgl/Widget.hpp index 1ba3c1c5b..74bf1837d 100644 --- a/source/modules/dgl/Widget.hpp +++ b/source/modules/dgl/Widget.hpp @@ -111,7 +111,7 @@ public: /** Mouse event. @a button The button number (1 = left, 2 = middle, 3 = right). - @a press True if the key was pressed, false if released. + @a press True if the button was pressed, false if released. @a pos The widget-relative coordinates of the pointer. @see onMouse */ diff --git a/source/modules/dgl/Window.hpp b/source/modules/dgl/Window.hpp index 8673dc7e1..90d255fc1 100644 --- a/source/modules/dgl/Window.hpp +++ b/source/modules/dgl/Window.hpp @@ -19,6 +19,10 @@ #include "Geometry.hpp" +START_NAMESPACE_DISTRHO +class UIExporter; +END_NAMESPACE_DISTRHO + START_NAMESPACE_DGL // ----------------------------------------------------------------------- @@ -125,11 +129,15 @@ private: friend class Application; friend class Widget; friend class StandaloneWindow; + friend class DISTRHO_NAMESPACE::UIExporter; virtual void _addWidget(Widget* const widget); virtual void _removeWidget(Widget* const widget); void _idle(); + bool handlePluginKeyboard(const bool press, const uint key); + bool handlePluginSpecial(const bool press, const Key key); + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window) }; diff --git a/source/modules/dgl/src/Image.cpp b/source/modules/dgl/src/Image.cpp index c34eadb69..b79b8d445 100644 --- a/source/modules/dgl/src/Image.cpp +++ b/source/modules/dgl/src/Image.cpp @@ -68,7 +68,9 @@ Image::~Image() { if (fTextureId != 0) { +#ifndef DISTRHO_OS_MAC // FIXME glDeleteTextures(1, &fTextureId); +#endif fTextureId = 0; } } diff --git a/source/modules/dgl/src/NanoVG.cpp b/source/modules/dgl/src/NanoVG.cpp index 2c2987a6e..2b9f0d4a5 100644 --- a/source/modules/dgl/src/NanoVG.cpp +++ b/source/modules/dgl/src/NanoVG.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 diff --git a/source/modules/dgl/src/Window.cpp b/source/modules/dgl/src/Window.cpp index 2855a2c10..173672994 100644 --- a/source/modules/dgl/src/Window.cpp +++ b/source/modules/dgl/src/Window.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 @@ -34,14 +34,12 @@ # include "pugl/pugl_win.cpp" #elif defined(DISTRHO_OS_MAC) # include "pugl/pugl_osx.m" -#elif defined(DISTRHO_OS_LINUX) +#else # include # include extern "C" { # include "pugl/pugl_x11.c" } -#else -# error Unsupported platform #endif #if defined(__GNUC__) && (__GNUC__ >= 7) @@ -90,13 +88,13 @@ struct Window::PrivateData { fModal(), #if defined(DISTRHO_OS_WINDOWS) hwnd(0) -#elif defined(DISTRHO_OS_LINUX) - xDisplay(nullptr), - xWindow(0) #elif defined(DISTRHO_OS_MAC) fNeedsIdle(true), mView(nullptr), mWindow(nullptr) +#else + xDisplay(nullptr), + xWindow(0) #endif { DBG("Creating window without parent..."); DBGF; @@ -118,27 +116,30 @@ struct Window::PrivateData { fModal(parent.pData), #if defined(DISTRHO_OS_WINDOWS) hwnd(0) -#elif defined(DISTRHO_OS_LINUX) - xDisplay(nullptr), - xWindow(0) #elif defined(DISTRHO_OS_MAC) fNeedsIdle(false), mView(nullptr), mWindow(nullptr) +#else + xDisplay(nullptr), + xWindow(0) #endif { DBG("Creating window with parent..."); DBGF; init(); const PuglInternals* const parentImpl(parent.pData->fView->impl); -#if defined(DISTRHO_OS_LINUX) - XSetTransientForHint(xDisplay, xWindow, parentImpl->win); -//#elif defined(DISTRHO_OS_MAC) -// [parentImpl->window orderWindow:NSWindowBelow relativeTo:[[mView window] windowNumber]]; +#if defined(DISTRHO_OS_WINDOWS) + // TODO +#elif defined(DISTRHO_OS_MAC) + [parentImpl->window orderWindow:NSWindowBelow relativeTo:[[mView window] windowNumber]]; #else - // unused - return; (void)parentImpl; + XSetTransientForHint(xDisplay, xWindow, parentImpl->win); #endif + return; + + // maybe unused + (void)parentImpl; } PrivateData(Application& app, Window* const self, const intptr_t parentId) @@ -156,13 +157,13 @@ struct Window::PrivateData { fModal(), #if defined(DISTRHO_OS_WINDOWS) hwnd(0) -#elif defined(DISTRHO_OS_LINUX) - xDisplay(nullptr), - xWindow(0) #elif defined(DISTRHO_OS_MAC) fNeedsIdle(parentId == 0), mView(nullptr), mWindow(nullptr) +#else + xDisplay(nullptr), + xWindow(0) #endif { if (fUsingEmbed) @@ -226,7 +227,7 @@ struct Window::PrivateData { } else { DISTRHO_SAFE_ASSERT(mWindow != nullptr); } -#elif defined(DISTRHO_OS_LINUX) +#else xDisplay = impl->display; xWindow = impl->win; DISTRHO_SAFE_ASSERT(xWindow != 0); @@ -286,7 +287,7 @@ struct Window::PrivateData { #elif defined(DISTRHO_OS_MAC) mView = nullptr; mWindow = nullptr; -#elif defined(DISTRHO_OS_LINUX) +#else xDisplay = nullptr; xWindow = 0; #endif @@ -380,7 +381,7 @@ struct Window::PrivateData { // TODO #elif defined(DISTRHO_OS_MAC) // TODO -#elif defined(DISTRHO_OS_LINUX) +#else int i, wx, wy; uint u; ::Window w; @@ -404,7 +405,7 @@ struct Window::PrivateData { #elif defined(DISTRHO_OS_MAC) if (mWindow != nullptr) [mWindow makeKeyWindow]; -#elif defined(DISTRHO_OS_LINUX) +#else XRaiseWindow(xDisplay, xWindow); XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); XFlush(xDisplay); @@ -455,7 +456,7 @@ struct Window::PrivateData { else [mView setHidden:YES]; } -#elif defined(DISTRHO_OS_LINUX) +#else if (yesNo) XMapRaised(xDisplay, xWindow); else @@ -559,7 +560,7 @@ struct Window::PrivateData { [[mWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; } } -#elif defined(DISTRHO_OS_LINUX) +#else XResizeWindow(xDisplay, xWindow, width, height); if (! fResizable) @@ -615,7 +616,7 @@ struct Window::PrivateData { [mWindow setTitle:titleString]; } -#elif defined(DISTRHO_OS_LINUX) +#else XStoreName(xDisplay, xWindow, title); #endif } @@ -624,14 +625,16 @@ struct Window::PrivateData { { DISTRHO_SAFE_ASSERT_RETURN(winId != 0,); -#if defined(DISTRHO_OS_MAC) - NSWindow* window = [NSApp windowWithWindowNumber:winId]; +#if defined(DISTRHO_OS_WINDOWS) + // TODO +#elif defined(DISTRHO_OS_MAC) + NSWindow* const window = [NSApp windowWithWindowNumber:winId]; DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); [window addChildWindow:mWindow ordered:NSWindowAbove]; [mWindow makeKeyWindow]; -#elif defined(DISTRHO_OS_LINUX) +#else XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId)); #endif } @@ -859,6 +862,90 @@ struct Window::PrivateData { // ------------------------------------------------------------------- + bool handlePluginKeyboard(const bool press, const uint key) + { + DBGp("PUGL: handlePluginKeyboard : %i %i\n", press, key); + + if (fModal.childFocus != nullptr) + { + fModal.childFocus->focus(); + return true; + } + + Widget::KeyboardEvent ev; + ev.press = press; + ev.key = key; + ev.mod = static_cast(fView->mods); + ev.time = 0; + + if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z') + ev.key -= 'a' - 'A'; // a-z -> A-Z + + FOR_EACH_WIDGET_INV(rit) + { + Widget* const widget(*rit); + + if (widget->isVisible() && widget->onKeyboard(ev)) + return true; + } + + return false; + } + + bool handlePluginSpecial(const bool press, const Key key) + { + DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key); + + if (fModal.childFocus != nullptr) + { + fModal.childFocus->focus(); + return true; + } + + int mods = 0x0; + + switch (key) + { + case kKeyShift: + mods |= kModifierShift; + break; + case kKeyControl: + mods |= kModifierControl; + break; + case kKeyAlt: + mods |= kModifierAlt; + break; + default: + break; + } + + if (mods != 0x0) + { + if (press) + fView->mods |= mods; + else + fView->mods &= ~(mods); + } + + Widget::SpecialEvent ev; + ev.press = press; + ev.key = key; + ev.mod = static_cast(fView->mods); + ev.time = 0; + + FOR_EACH_WIDGET_INV(rit) + { + Widget* const widget(*rit); + + if (widget->isVisible() && widget->onSpecial(ev)) + return true; + } + + return false; + } + + // ------------------------------------------------------------------- + Application& fApp; Window* fSelf; PuglView* fView; @@ -898,13 +985,13 @@ struct Window::PrivateData { #if defined(DISTRHO_OS_WINDOWS) HWND hwnd; -#elif defined(DISTRHO_OS_LINUX) - Display* xDisplay; - ::Window xWindow; #elif defined(DISTRHO_OS_MAC) bool fNeedsIdle; PuglOpenGLView* mView; id mWindow; +#else + Display* xDisplay; + ::Window xWindow; #endif // ------------------------------------------------------------------- @@ -1020,7 +1107,7 @@ void Window::repaint() noexcept #ifndef DGL_FILE_BROWSER_DISABLED bool Window::openFileBrowser(const FileBrowserOptions& options) { -#ifdef SOFD_HAVE_X11 +# ifdef SOFD_HAVE_X11 using DISTRHO_NAMESPACE::String; // -------------------------------------------------------------------------- @@ -1078,10 +1165,10 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) // show return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0); -#else +# else // not implemented return false; -#endif +# endif } #endif @@ -1220,6 +1307,26 @@ void Window::fileBrowserSelected(const char*) } #endif +bool Window::handlePluginKeyboard(const bool press, const uint key) +{ + return pData->handlePluginKeyboard(press, key); +} + +bool Window::handlePluginSpecial(const bool press, const Key key) +{ + return pData->handlePluginSpecial(press, key); +} + +bool Window::handlePluginKeyboard(const bool press, const uint key) +{ + return pData->handlePluginKeyboard(press, key); +} + +bool Window::handlePluginSpecial(const bool press, const Key key) +{ + return pData->handlePluginSpecial(press, key); +} + // ----------------------------------------------------------------------- StandaloneWindow::StandaloneWindow() diff --git a/source/modules/dgl/src/pugl/pugl_osx.m b/source/modules/dgl/src/pugl/pugl_osx.m index 8bd2bb9c1..fb8487917 100644 --- a/source/modules/dgl/src/pugl/pugl_osx.m +++ b/source/modules/dgl/src/pugl/pugl_osx.m @@ -202,8 +202,6 @@ puglDisplay(PuglView* view) - (void) reshape { - [[self openGLContext] update]; - if (!puglview) { /* NOTE: Apparently reshape gets called when the GC gets around to deleting the view (?), so we must have reset puglview to NULL when @@ -212,6 +210,8 @@ puglDisplay(PuglView* view) return; } + [[self openGLContext] update]; + NSRect bounds = [self bounds]; int width = bounds.size.width; int height = bounds.size.height; diff --git a/source/modules/dgl/src/pugl/pugl_x11.c b/source/modules/dgl/src/pugl/pugl_x11.c index ebd5a7b37..224324886 100644 --- a/source/modules/dgl/src/pugl/pugl_x11.c +++ b/source/modules/dgl/src/pugl/pugl_x11.c @@ -445,7 +445,7 @@ dispatchKey(PuglView* view, XEvent* event, bool press) view->redisplay = false; return; } - if (n == 0) { + if (n == 0 && sym == 0) { goto send_event; return; } diff --git a/source/modules/distrho/DistrhoPlugin.hpp b/source/modules/distrho/DistrhoPlugin.hpp index ebb9a9dc2..fcb40dd59 100644 --- a/source/modules/distrho/DistrhoPlugin.hpp +++ b/source/modules/distrho/DistrhoPlugin.hpp @@ -133,6 +133,29 @@ struct AudioPort { symbol() {} }; +/** + Parameter designation.@n + Allows a parameter to be specially designated for a task, like bypass. + + Each designation is unique, there must be only one parameter that uses it.@n + The use of designated parameters is completely optional. + + @note Designated parameters have strict ranges. + @see ParameterRanges::adjustForDesignation() + */ +enum ParameterDesignation { + /** + Null or unset designation. + */ + kParameterDesignationNull = 0, + + /** + Bypass designation.@n + When on (> 0.5f), it means the plugin must run in a bypassed state. + */ + kParameterDesignationBypass = 1 +}; + /** Parameter ranges.@n This is used to set the default, minimum and maximum values of a parameter. @@ -289,6 +312,19 @@ struct Parameter { */ ParameterRanges ranges; + /** + Designation for this parameter. + */ + ParameterDesignation designation; + + /** + MIDI CC to use by default on this parameter.@n + A value of 0 or 32 (bank change) is considered invalid.@n + Must also be less or equal to 120. + @note This value is only a hint! Hosts might map it automatically or completely ignore it. + */ + uint8_t midiCC; + /** Default constructor for a null parameter. */ @@ -297,7 +333,9 @@ struct Parameter { name(), symbol(), unit(), - ranges() {} + ranges(), + designation(kParameterDesignationNull), + midiCC(0) {} /** Constructor using custom values. @@ -307,7 +345,33 @@ struct Parameter { name(n), symbol(s), unit(u), - ranges(def, min, max) {} + ranges(def, min, max), + designation(kParameterDesignationNull), + midiCC(0) {} + + /** + Initialize a parameter for a specific designation. + */ + void initDesignation(ParameterDesignation d) noexcept + { + designation = d; + + switch (d) + { + case kParameterDesignationNull: + break; + case kParameterDesignationBypass: + hints = kParameterIsAutomable|kParameterIsBoolean|kParameterIsInteger; + name = "Bypass"; + symbol = "dpf_bypass"; + unit = ""; + midiCC = 0; + ranges.def = 0.0f; + ranges.min = 0.0f; + ranges.max = 1.0f; + break; + } + } }; /** @@ -531,7 +595,7 @@ public: Returns false when the host buffer is full, in which case do not call this again until the next run(). @note This function is not implemented yet!@n It's here so that developers can prepare MIDI plugins in advance.@n - If you plan to use this, please report to DPF authos so it can be implemented. + If you plan to use this, please report to DPF authors so it can be implemented. */ bool writeMidiEvent(const MidiEvent& midiEvent) noexcept; #endif @@ -651,7 +715,7 @@ protected: /** Get the value of an internal state.@n The host may call this function from any non-realtime context.@n - Must be implemented by your plugin class if DISTRHO_PLUGIN_WANT_PROGRAMS or DISTRHO_PLUGIN_WANT_FULL_STATE is enabled. + Must be implemented by your plugin class if DISTRHO_PLUGIN_WANT_FULL_STATE is enabled. @note The use of this function breaks compatibility with the DSSI format. */ virtual String getState(const char* key) const = 0; diff --git a/source/modules/distrho/DistrhoUtils.hpp b/source/modules/distrho/DistrhoUtils.hpp index cf56be60f..ee2cb5711 100644 --- a/source/modules/distrho/DistrhoUtils.hpp +++ b/source/modules/distrho/DistrhoUtils.hpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2018 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 diff --git a/source/modules/distrho/extra/ExternalWindow.hpp b/source/modules/distrho/extra/ExternalWindow.hpp index 392a57e4d..8ad2df0f2 100644 --- a/source/modules/distrho/extra/ExternalWindow.hpp +++ b/source/modules/distrho/extra/ExternalWindow.hpp @@ -19,13 +19,13 @@ #include "String.hpp" -#ifdef DISTRHO_OS_UNIX +#ifdef DISTRHO_OS_WINDOWS +# error Unsupported platform! +#else # include # include # include # include -#else -# error Unsupported platform! #endif START_NAMESPACE_DISTRHO diff --git a/source/modules/distrho/extra/String.hpp b/source/modules/distrho/extra/String.hpp index 73c71d5ea..650c5bbde 100644 --- a/source/modules/distrho/extra/String.hpp +++ b/source/modules/distrho/extra/String.hpp @@ -579,7 +579,7 @@ public: "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; - const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast(dataSize/3)), 65536U); + const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(dataSize/3), 65536U); const uchar* bytesToEncode((const uchar*)data); diff --git a/source/modules/distrho/extra/Thread.hpp b/source/modules/distrho/extra/Thread.hpp index 5738fc606..b3d92c983 100644 --- a/source/modules/distrho/extra/Thread.hpp +++ b/source/modules/distrho/extra/Thread.hpp @@ -21,7 +21,7 @@ #include "Sleep.hpp" #include "String.hpp" -#ifdef DISTRHO_OS_LINUX_FULL +#ifdef DISTRHO_OS_LINUX # include #endif @@ -198,7 +198,7 @@ public: { DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); -#ifdef DISTRHO_OS_LINUX_FULL +#ifdef DISTRHO_OS_LINUX prctl(PR_SET_NAME, name, 0, 0, 0); #endif #if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 diff --git a/source/modules/distrho/src/DistrhoDefines.h b/source/modules/distrho/src/DistrhoDefines.h index 44499980e..16c069444 100644 --- a/source/modules/distrho/src/DistrhoDefines.h +++ b/source/modules/distrho/src/DistrhoDefines.h @@ -38,17 +38,10 @@ # elif defined(__HAIKU__) # define DISTRHO_OS_HAIKU 1 # elif defined(__linux__) || defined(__linux) -# define DISTRHO_OS_LINUX 1 -# define DISTRHO_OS_LINUX_FULL 1 -# elif defined(__FreeBSD__) || defined(__GNU__) -# define DISTRHO_OS_LINUX 1 +# define DISTRHO_OS_LINUX 1 # endif #endif -#if defined(DISTRHO_OS_LINUX) || defined(DISTRHO_OS_MAC) -# define DISTRHO_OS_UNIX -#endif - #ifndef DISTRHO_DLL_EXTENSION # define DISTRHO_DLL_EXTENSION "so" #endif diff --git a/source/modules/distrho/src/DistrhoPluginInternal.hpp b/source/modules/distrho/src/DistrhoPluginInternal.hpp index d857d6ef4..d9677c140 100644 --- a/source/modules/distrho/src/DistrhoPluginInternal.hpp +++ b/source/modules/distrho/src/DistrhoPluginInternal.hpp @@ -43,6 +43,7 @@ struct Plugin::PrivateData { #endif uint32_t parameterCount; + uint32_t parameterOffset; Parameter* parameters; #if DISTRHO_PLUGIN_WANT_PROGRAMS @@ -73,6 +74,7 @@ struct Plugin::PrivateData { audioPorts(nullptr), #endif parameterCount(0), + parameterOffset(0), parameters(nullptr), #if DISTRHO_PLUGIN_WANT_PROGRAMS programCount(0), @@ -91,6 +93,22 @@ struct Plugin::PrivateData { { DISTRHO_SAFE_ASSERT(bufferSize != 0); DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); + +#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) + parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; +# if DISTRHO_PLUGIN_WANT_LATENCY + parameterOffset += 1; +# endif +#endif + +#ifdef DISTRHO_PLUGIN_TARGET_LV2 +# if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) + parameterOffset += 1; +# if DISTRHO_PLUGIN_WANT_STATE + parameterOffset += 1; +# endif +# endif +#endif } ~PrivateData() noexcept @@ -283,6 +301,13 @@ public: return fData->parameterCount; } + uint32_t getParameterOffset() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->parameterOffset; + } + uint32_t getParameterHints(const uint32_t index) const noexcept { DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0x0); @@ -290,6 +315,13 @@ public: return fData->parameters[index].hints; } + ParameterDesignation getParameterDesignation(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kParameterDesignationNull); + + return fData->parameters[index].designation; + } + bool isParameterOutput(const uint32_t index) const noexcept { return (getParameterHints(index) & kParameterIsOutput); @@ -323,6 +355,13 @@ public: return fData->parameters[index].ranges; } + uint8_t getParameterMidiCC(const uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0); + + return fData->parameters[index].midiCC; + } + float getParameterValue(const uint32_t index) const { DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); diff --git a/source/modules/distrho/src/DistrhoPluginJack.cpp b/source/modules/distrho/src/DistrhoPluginJack.cpp index 93e5d4137..b735e7d7e 100644 --- a/source/modules/distrho/src/DistrhoPluginJack.cpp +++ b/source/modules/distrho/src/DistrhoPluginJack.cpp @@ -70,20 +70,14 @@ static void closeSignalHandler(int) noexcept static void initSignalHandler() { - struct sigaction sint; - struct sigaction sterm; - - sint.sa_handler = closeSignalHandler; - sint.sa_flags = SA_RESTART; - sint.sa_restorer = nullptr; - sigemptyset(&sint.sa_mask); - sigaction(SIGINT, &sint, nullptr); - - sterm.sa_handler = closeSignalHandler; - sterm.sa_flags = SA_RESTART; - sterm.sa_restorer = nullptr; - sigemptyset(&sterm.sa_mask); - sigaction(SIGTERM, &sterm, nullptr); + struct sigaction sig; + memset(&sig, 0, sizeof(sig)); + + sig.sa_handler = closeSignalHandler; + sig.sa_flags = SA_RESTART; + sigemptyset(&sig.sa_mask); + sigaction(SIGINT, &sig, nullptr); + sigaction(SIGTERM, &sig, nullptr); } #endif @@ -103,28 +97,27 @@ public: #endif fClient(client) { +#if DISTRHO_PLUGIN_NUM_INPUTS > 0 || DISTRHO_PLUGIN_NUM_OUTPUTS > 0 char strBuf[0xff+1]; strBuf[0xff] = '\0'; -#if DISTRHO_PLUGIN_NUM_INPUTS > 0 +# if DISTRHO_PLUGIN_NUM_INPUTS > 0 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) { std::snprintf(strBuf, 0xff, "in%i", i+1); fPortAudioIns[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); } -#endif - -#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 +# endif +# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) { std::snprintf(strBuf, 0xff, "out%i", i+1); fPortAudioOuts[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); } +# endif #endif -#if DISTRHO_PLUGIN_IS_SYNTH - fPortMidiIn = jack_port_register(fClient, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); -#endif + fPortEventsIn = jack_port_register(fClient, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); #if DISTRHO_PLUGIN_WANT_PROGRAMS if (fPlugin.getProgramCount() > 0) @@ -134,11 +127,18 @@ public: fUI.programLoaded(0); # endif } +# if DISTRHO_PLUGIN_HAS_UI + fProgramChanged = -1; +# endif #endif if (const uint32_t count = fPlugin.getParameterCount()) { fLastOutputValues = new float[count]; +#if DISTRHO_PLUGIN_HAS_UI + fParametersChanged = new bool[count]; + std::memset(fParametersChanged, 0, sizeof(bool)*count); +#endif for (uint32_t i=0; i < count; ++i) { @@ -149,15 +149,18 @@ public: else { fLastOutputValues[i] = 0.0f; -# if DISTRHO_PLUGIN_HAS_UI +#if DISTRHO_PLUGIN_HAS_UI fUI.parameterChanged(i, fPlugin.getParameterValue(i)); -# endif +#endif } } } else { fLastOutputValues = nullptr; +#if DISTRHO_PLUGIN_HAS_UI + fParametersChanged = nullptr; +#endif } jack_set_buffer_size_callback(fClient, jackBufferSizeCallback, this); @@ -198,10 +201,8 @@ public: if (fClient == nullptr) return; -#if DISTRHO_PLUGIN_IS_SYNTH - jack_port_unregister(fClient, fPortMidiIn); - fPortMidiIn = nullptr; -#endif + jack_port_unregister(fClient, fPortEventsIn); + fPortEventsIn = nullptr; #if DISTRHO_PLUGIN_NUM_INPUTS > 0 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) @@ -231,20 +232,31 @@ protected: if (gCloseSignalReceived) return fUI.quit(); - float value; +# if DISTRHO_PLUGIN_WANT_PROGRAMS + if (fProgramChanged >= 0) + { + fUI.programLoaded(fProgramChanged); + fProgramChanged = -1; + } +# endif for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) { - if (! fPlugin.isParameterOutput(i)) - continue; - - value = fPlugin.getParameterValue(i); + if (fPlugin.isParameterOutput(i)) + { + const float value = fPlugin.getParameterValue(i); - if (fLastOutputValues[i] == value) - continue; + if (d_isEqual(fLastOutputValues[i], value)) + continue; - fLastOutputValues[i] = value; - fUI.parameterChanged(i, value); + fLastOutputValues[i] = value; + fUI.parameterChanged(i, value); + } + else if (fParametersChanged[i]) + { + fParametersChanged[i] = false; + fUI.parameterChanged(i, fPlugin.getParameterValue(i)); + } } fUI.exec_idle(); @@ -316,14 +328,14 @@ protected: fPlugin.setTimePosition(fTimePosition); #endif -#if DISTRHO_PLUGIN_IS_SYNTH - void* const midiBuf = jack_port_get_buffer(fPortMidiIn, nframes); + void* const midiBuf = jack_port_get_buffer(fPortEventsIn, nframes); if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf)) { +#if DISTRHO_PLUGIN_IS_SYNTH uint32_t midiEventCount = 0; MidiEvent midiEvents[eventCount]; - +#endif jack_midi_event_t jevent; for (uint32_t i=0; i < eventCount; ++i) @@ -331,6 +343,47 @@ protected: if (jack_midi_event_get(&jevent, midiBuf, i) != 0) break; + // Check if message is control change on channel 1 + if (jevent.buffer[0] == 0xB0 && jevent.size == 3) + { + const uint8_t control = jevent.buffer[1]; + const uint8_t value = jevent.buffer[2]; + + /* NOTE: This is not optimal, we're iterating all parameters on every CC message. + Since the JACK standalone is more of a test tool, this will do for now. */ + for (uint32_t j=0, paramCount=fPlugin.getParameterCount(); j < paramCount; ++j) + { + if (fPlugin.isParameterOutput(j)) + continue; + if (fPlugin.getParameterMidiCC(j) != control) + continue; + + const float scaled = static_cast(value)/127.0f; + const float fvalue = fPlugin.getParameterRanges(j).getUnnormalizedValue(scaled); + fPlugin.setParameterValue(j, fvalue); +#if DISTRHO_PLUGIN_HAS_UI + fParametersChanged[j] = true; +#endif + break; + } + } +#if DISTRHO_PLUGIN_WANT_PROGRAMS + // Check if message is program change on channel 1 + else if (jevent.buffer[0] == 0xC0 && jevent.size == 2) + { + const uint8_t program = jevent.buffer[1]; + + if (program < fPlugin.getProgramCount()) + { + fPlugin.loadProgram(program); +# if DISTRHO_PLUGIN_HAS_UI + fProgramChanged = program; +# endif + } + } +#endif + +#if DISTRHO_PLUGIN_IS_SYNTH MidiEvent& midiEvent(midiEvents[midiEventCount++]); midiEvent.frame = jevent.time; @@ -340,10 +393,14 @@ protected: midiEvent.dataExt = jevent.buffer; else std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size); +#endif } +#if DISTRHO_PLUGIN_IS_SYNTH fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount); +#endif } +#if DISTRHO_PLUGIN_IS_SYNTH else { fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0); @@ -399,9 +456,7 @@ private: #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 jack_port_t* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; #endif -#if DISTRHO_PLUGIN_IS_SYNTH - jack_port_t* fPortMidiIn; -#endif + jack_port_t* fPortEventsIn; #if DISTRHO_PLUGIN_WANT_TIMEPOS TimePosition fTimePosition; #endif @@ -409,6 +464,14 @@ private: // Temporary data float* fLastOutputValues; +#if DISTRHO_PLUGIN_HAS_UI + // Store DSP changes to send to UI + bool* fParametersChanged; +# if DISTRHO_PLUGIN_WANT_PROGRAMS + int fProgramChanged; +# endif +#endif + // ------------------------------------------------------------------- // Callbacks diff --git a/source/modules/distrho/src/DistrhoPluginLADSPA+DSSI.cpp b/source/modules/distrho/src/DistrhoPluginLADSPA+DSSI.cpp index 455f9a8f6..01bb19d7f 100644 --- a/source/modules/distrho/src/DistrhoPluginLADSPA+DSSI.cpp +++ b/source/modules/distrho/src/DistrhoPluginLADSPA+DSSI.cpp @@ -250,17 +250,16 @@ public: midiEvents[j].data[2] = 0; midiEvents[j].data[3] = 0; break; -#if 0 // TODO case SND_SEQ_EVENT_PITCHBEND: j = midiEventCount++; midiEvents[j].frame = seqEvent.time.tick; midiEvents[j].size = 3; midiEvents[j].data[0] = 0xE0 + seqEvent.data.control.channel; - midiEvents[j].data[1] = 0; - midiEvents[j].data[2] = 0; + uint16_t tempvalue = seqEvent.data.control.value + 8192; + midiEvents[j].data[1] = tempvalue & 0x7F; + midiEvents[j].data[2] = tempvalue >> 7; midiEvents[j].data[3] = 0; break; -#endif } } @@ -329,6 +328,21 @@ public: } } # endif + + int dssi_get_midi_controller_for_port(const ulong port) noexcept + { + const uint32_t parameterOffset = fPlugin.getParameterOffset(); + + if (port > parameterOffset) + return DSSI_NONE; + + const uint8_t midiCC = fPlugin.getParameterMidiCC(port-parameterOffset); + + if (midiCC == 0 || midiCC == 32 || midiCC >= 0x78) + return DSSI_NONE; + + return DSSI_CC(midiCC); + } #endif // ------------------------------------------------------------------- @@ -435,6 +449,11 @@ static void dssi_select_program(LADSPA_Handle instance, ulong bank, ulong progra } # endif +static int dssi_get_midi_controller_for_port(LADSPA_Handle instance, ulong port) +{ + return instancePtr->dssi_get_midi_controller_for_port(port); +} + # if DISTRHO_PLUGIN_WANT_MIDI_INPUT static void dssi_run_synth(LADSPA_Handle instance, ulong sampleCount, snd_seq_event_t* events, ulong eventCount) { @@ -489,7 +508,7 @@ static DSSI_Descriptor sDssiDescriptor = { /* get_program */ nullptr, /* select_program */ nullptr, # endif - /* get_midi_controller_for_port */ nullptr, + dssi_get_midi_controller_for_port, # if DISTRHO_PLUGIN_WANT_MIDI_INPUT dssi_run_synth, # else @@ -614,11 +633,16 @@ public: const uint32_t hints(plugin.getParameterHints(i)); if (hints & kParameterIsBoolean) + { portRangeHints[port].HintDescriptor |= LADSPA_HINT_TOGGLED; - if (hints & kParameterIsInteger) - portRangeHints[port].HintDescriptor |= LADSPA_HINT_INTEGER; - if (hints & kParameterIsLogarithmic) - portRangeHints[port].HintDescriptor |= LADSPA_HINT_LOGARITHMIC; + } + else + { + if (hints & kParameterIsInteger) + portRangeHints[port].HintDescriptor |= LADSPA_HINT_INTEGER; + if (hints & kParameterIsLogarithmic) + portRangeHints[port].HintDescriptor |= LADSPA_HINT_LOGARITHMIC; + } } } diff --git a/source/modules/distrho/src/DistrhoPluginLV2.cpp b/source/modules/distrho/src/DistrhoPluginLV2.cpp index 606c65a64..cd76bffe1 100644 --- a/source/modules/distrho/src/DistrhoPluginLV2.cpp +++ b/source/modules/distrho/src/DistrhoPluginLV2.cpp @@ -30,6 +30,10 @@ #include "lv2/lv2_kxstudio_properties.h" #include "lv2/lv2_programs.h" +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD +# include "libmodauth.h" +#endif + #ifdef noexcept # undef noexcept #endif @@ -58,6 +62,9 @@ class PluginLv2 public: PluginLv2(const double sampleRate, const LV2_URID_Map* const uridMap, const LV2_Worker_Schedule* const worker, const bool usingNominal) : fUsingNominal(usingNominal), +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD + fRunCount(0), +#endif fPortControls(nullptr), fLastControlValues(nullptr), fSampleRate(sampleRate), @@ -512,6 +519,12 @@ public: if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) { fLastControlValues[i] = curValue; + + if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) + { + curValue = 1.0f - curValue; + } + fPlugin.setParameterValue(i, curValue); } } @@ -519,12 +532,21 @@ public: // Run plugin if (sampleCount != 0) { +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD + fRunCount = mod_license_run_begin(fRunCount, sampleCount); +#endif + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); #else fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); #endif +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD + for (uint32_t i=0; iatom.size; - bool needsInit = true; uint32_t size, offset = 0; LV2_Atom_Event* aev; + fPortEventsOut->atom.size = sizeof(LV2_Atom_Sequence_Body); + fPortEventsOut->atom.type = fURIDs.atomSequence; + fPortEventsOut->body.unit = 0; + fPortEventsOut->body.pad = 0; + // TODO - MIDI Output for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) @@ -617,15 +643,6 @@ public: if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) break; - if (needsInit) - { - fPortEventsOut->atom.size = 0; - fPortEventsOut->atom.type = fURIDs.atomSequence; - fPortEventsOut->body.unit = 0; - fPortEventsOut->body.pad = 0; - needsInit = false; - } - // reserve msg space char msgBuf[msgSize]; std::memset(msgBuf, 0, msgSize); @@ -846,6 +863,10 @@ private: PluginExporter fPlugin; const bool fUsingNominal; // if false use maxBlockLength +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD + uint32_t fRunCount; +#endif + // LV2 ports #if DISTRHO_PLUGIN_NUM_INPUTS > 0 const float* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; @@ -1034,6 +1055,10 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons } #endif +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD + mod_check_license(features, DISTRHO_PLUGIN_URI); +#endif + d_lastBufferSize = 0; bool usingNominal = false; @@ -1193,7 +1218,11 @@ static const void* lv2_extension_data(const char* uri) return &directaccess; #endif +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD + return mod_license_interface(uri); +#else return nullptr; +#endif } #undef instancePtr diff --git a/source/modules/distrho/src/DistrhoPluginLV2export.cpp b/source/modules/distrho/src/DistrhoPluginLV2export.cpp index aa92bf7d6..961d62bda 100644 --- a/source/modules/distrho/src/DistrhoPluginLV2export.cpp +++ b/source/modules/distrho/src/DistrhoPluginLV2export.cpp @@ -1,6 +1,6 @@ /* * DISTRHO Plugin Framework (DPF) - * Copyright (C) 2012-2016 Filipe Coelho + * Copyright (C) 2012-2017 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 @@ -34,6 +34,10 @@ #include "lv2/lv2_kxstudio_properties.h" #include "lv2/lv2_programs.h" +#ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD +# include "mod-license.h" +#endif + #include #include @@ -224,6 +228,9 @@ void lv2_generate_ttl(const char* const basename) #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"; @@ -241,6 +248,9 @@ void lv2_generate_ttl(const char* const basename) 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"; @@ -359,7 +369,7 @@ void lv2_generate_ttl(const char* const basename) pluginString += " lv2:name \"Latency\" ;\n"; pluginString += " lv2:symbol \"lv2_latency\" ;\n"; pluginString += " lv2:designation lv2:latency ;\n"; - pluginString += " lv2:portProperty lv2:reportsLatency, lv2:integer ;\n"; + pluginString += " lv2:portProperty lv2:reportsLatency, lv2:integer, <" LV2_PORT_PROPS__notOnGUI "> ;\n"; pluginString += " ] ;\n\n"; ++portIndex; #endif @@ -377,10 +387,34 @@ void lv2_generate_ttl(const char* const basename) pluginString += " a lv2:InputPort, lv2:ControlPort ;\n"; pluginString += " lv2:index " + String(portIndex) + " ;\n"; - pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; - // symbol + bool designated = false; + + // designation + if (! plugin.isParameterOutput(i)) + { + switch (plugin.getParameterDesignation(i)) + { + case kParameterDesignationNull: + break; + case kParameterDesignationBypass: + designated = true; + pluginString += " lv2:name \"Enabled\" ;\n"; + pluginString += " lv2:symbol \"lv2_enabled\" ;\n"; + pluginString += " lv2:default 1 ;\n"; + pluginString += " lv2:minimum 0 ;\n"; + pluginString += " lv2:maximum 1 ;\n"; + pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; + pluginString += " lv2:designation lv2:enabled ;\n"; + break; + } + } + + // name and symbol + if (! designated) { + pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n"; + String symbol(plugin.getParameterSymbol(i)); if (symbol.isEmpty()) @@ -390,24 +424,28 @@ void lv2_generate_ttl(const char* const basename) } // ranges + if (! designated) { const ParameterRanges& ranges(plugin.getParameterRanges(i)); if (plugin.getParameterHints(i) & kParameterIsInteger) { - pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; + if (! plugin.isParameterOutput(i)) + pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n"; pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n"; pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n"; } else { - pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; + if (! plugin.isParameterOutput(i)) + pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n"; pluginString += " lv2:minimum " + String(ranges.min) + " ;\n"; pluginString += " lv2:maximum " + String(ranges.max) + " ;\n"; } } // unit + if (! designated) { const String& unit(plugin.getParameterUnit(i)); @@ -453,6 +491,7 @@ void lv2_generate_ttl(const char* const basename) } // hints + if (! designated) { const uint32_t hints(plugin.getParameterHints(i)); @@ -606,7 +645,18 @@ void lv2_generate_ttl(const char* const basename) plugin.loadProgram(i); - presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; + presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; + +# if DISTRHO_PLUGIN_WANT_FULL_STATE + if (numParameters == 0 && numStates == 0) +#else + if (numParameters == 0) +#endif + { + presetString += " ."; + presetsString += presetString; + continue; + } # if DISTRHO_PLUGIN_WANT_FULL_STATE presetString += " state:state [\n"; @@ -629,12 +679,22 @@ void lv2_generate_ttl(const char* const basename) presetString += " ] .\n\n"; # endif + bool firstParameter = true; + for (uint32_t j=0; j getInstancePointer()) + fUI(this, winId, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, plugin->getInstancePointer()), + fShouldCaptureVstKeys(false) { + // FIXME only needed for windows? +//#ifdef DISTRHO_OS_WINDOWS + char strBuf[0xff+1]; + std::memset(strBuf, 0, sizeof(char)*(0xff+1)); + hostCallback(audioMasterGetProductString, 0, 0, strBuf); + d_stdout("Plugin UI running in '%s'", strBuf); + + // TODO make a white-list of needed hosts + if (/*std::strcmp(strBuf, "") == 0*/ true) + fShouldCaptureVstKeys = true; +//#endif } // ------------------------------------------------------------------- @@ -167,6 +181,60 @@ public: } # endif + int handlePluginKeyEvent(const bool down, int32_t index, const intptr_t value) + { +# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI + if (! fShouldCaptureVstKeys) + return 0; + + d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value); + + int special = 0; + switch (value) + { + // convert some specials to normal keys + case 1: index = kCharBackspace; break; + case 6: index = kCharEscape; break; + case 7: index = ' '; break; + case 22: index = kCharDelete; break; + + // handle rest of special keys + case 40: special = kKeyF1; break; + case 41: special = kKeyF2; break; + case 42: special = kKeyF3; break; + case 43: special = kKeyF4; break; + case 44: special = kKeyF5; break; + case 45: special = kKeyF6; break; + case 46: special = kKeyF7; break; + case 47: special = kKeyF8; break; + case 48: special = kKeyF9; break; + case 49: special = kKeyF10; break; + case 50: special = kKeyF11; break; + case 51: special = kKeyF12; break; + case 11: special = kKeyLeft; break; + case 12: special = kKeyUp; break; + case 13: special = kKeyRight; break; + case 14: special = kKeyDown; break; + case 15: special = kKeyPageUp; break; + case 16: special = kKeyPageDown; break; + case 10: special = kKeyHome; break; + case 9: special = kKeyEnd; break; + case 21: special = kKeyInsert; break; + case 54: special = kKeyShift; break; + case 55: special = kKeyControl; break; + case 56: special = kKeyAlt; break; + } + + if (special != 0) + return fUI.handlePluginSpecial(down, static_cast(special)); + + if (index >= 0) + return fUI.handlePluginKeyboard(down, static_cast(index)); +# endif + + return 0; + } + // ------------------------------------------------------------------- protected: @@ -231,6 +299,7 @@ private: // Plugin UI UIExporter fUI; + bool fShouldCaptureVstKeys; // ------------------------------------------------------------------- // Callbacks @@ -499,6 +568,16 @@ public: if (fVstUI != nullptr) fVstUI->idle(); break; + + case effEditKeyDown: + if (fVstUI != nullptr) + return fVstUI->handlePluginKeyEvent(true, index, value); + break; + + case effEditKeyUp: + if (fVstUI != nullptr) + return fVstUI->handlePluginKeyEvent(false, index, value); + break; #endif // DISTRHO_PLUGIN_HAS_UI #if DISTRHO_PLUGIN_WANT_STATE diff --git a/source/modules/distrho/src/DistrhoUIInternal.hpp b/source/modules/distrho/src/DistrhoUIInternal.hpp index 7da7c0063..b2dd7e67a 100644 --- a/source/modules/distrho/src/DistrhoUIInternal.hpp +++ b/source/modules/distrho/src/DistrhoUIInternal.hpp @@ -418,6 +418,16 @@ public: return ! glApp.isQuiting(); } + + bool handlePluginKeyboard(const bool press, const uint key) + { + return glWindow.handlePluginKeyboard(press, key); + } + + bool handlePluginSpecial(const bool press, const Key key) + { + return glWindow.handlePluginKeyboard(press, key); + } #else void setWindowSize(const uint width, const uint height, const bool updateUI = false) {} void setWindowTransientWinId(const uintptr_t winId) {} diff --git a/source/modules/distrho/src/DistrhoUILV2.cpp b/source/modules/distrho/src/DistrhoUILV2.cpp index 7eaec209c..5ab909b5d 100644 --- a/source/modules/distrho/src/DistrhoUILV2.cpp +++ b/source/modules/distrho/src/DistrhoUILV2.cpp @@ -23,6 +23,7 @@ #include "lv2/data-access.h" #include "lv2/instance-access.h" #include "lv2/options.h" +#include "lv2/parameters.h" #include "lv2/ui.h" #include "lv2/urid.h" #include "lv2/lv2_kxstudio_properties.h" @@ -114,7 +115,9 @@ public: { const uint32_t parameterOffset(fUI.getParameterOffset()); - DISTRHO_SAFE_ASSERT_RETURN(rindex >= parameterOffset,) + if (rindex < parameterOffset) + return; + DISTRHO_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),) const float value(*(const float*)buffer); @@ -173,17 +176,17 @@ public: { for (int i=0; options[i].key != 0; ++i) { - if (options[i].key == fUridMap->map(fUridMap->handle, LV2_CORE__sampleRate)) + if (options[i].key == fUridMap->map(fUridMap->handle, LV2_PARAMETERS__sampleRate)) { - if (options[i].type == fUridMap->map(fUridMap->handle, LV2_ATOM__Double)) + if (options[i].type == fUridMap->map(fUridMap->handle, LV2_ATOM__Float)) { - const double sampleRate(*(const double*)options[i].value); + const float sampleRate(*(const float*)options[i].value); fUI.setSampleRate(sampleRate); continue; } else { - d_stderr("Host changed sampleRate but with wrong value type"); + d_stderr("Host changed UI sample-rate but with wrong value type"); continue; } } @@ -237,7 +240,7 @@ protected: const size_t msgSize(tmpStr.length()+1); // reserve atom space - const size_t atomSize(lv2_atom_pad_size(sizeof(LV2_Atom) + msgSize)); + const size_t atomSize(sizeof(LV2_Atom) + msgSize); char atomBuf[atomSize]; std::memset(atomBuf, 0, atomSize); @@ -400,23 +403,23 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char* uri, if (options != nullptr) { - const LV2_URID uridSampleRate(uridMap->map(uridMap->handle, LV2_CORE__sampleRate)); + const LV2_URID uridSampleRate(uridMap->map(uridMap->handle, LV2_PARAMETERS__sampleRate)); for (int i=0; options[i].key != 0; ++i) { if (options[i].key == uridSampleRate) { - if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Double)) - d_lastUiSampleRate = *(const double*)options[i].value; + if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Float)) + d_lastUiSampleRate = *(const float*)options[i].value; else - d_stderr("Host provides sampleRate but has wrong value type"); + d_stderr("Host provides UI sample-rate but has wrong value type"); break; } } } - if (d_lastUiSampleRate == 0.0) + if (d_lastUiSampleRate < 1.0) { d_stdout("WARNING: this host does not send sample-rate information for LV2 UIs, using 44100 as fallback (this could be wrong)"); d_lastUiSampleRate = 44100.0;