From f080e2d6a4bcf237e987018fa7a823ce61c50a16 Mon Sep 17 00:00:00 2001 From: Olivier Humbert Date: Sat, 12 Jan 2019 09:08:32 +0100 Subject: [PATCH 01/12] Adds YK chorus (#107) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a3af4218..b8788fc0 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ List of plugins made with DPF:
- [ZamAudio Suite](https://github.com/zamaudio/zam-plugins) - [DragonFly-Reverb](https://github.com/michaelwillis/dragonfly-reverb) - [Wolf-Shaper](https://github.com/pdesaulniers/wolf-shaper) + - [YK Chorus](https://github.com/SpotlightKid/ykchorus) Plugin examples are available in the `example/` folder inside this repo.
From 1503c4eccb8dbcf46b703f64531764495f372517 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 12 Jan 2019 20:03:51 +0100 Subject: [PATCH 02/12] Fix Size::isValid() check Signed-off-by: falkTX --- dgl/src/Geometry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dgl/src/Geometry.cpp b/dgl/src/Geometry.cpp index 7ea3af34..c76809dc 100644 --- a/dgl/src/Geometry.cpp +++ b/dgl/src/Geometry.cpp @@ -237,7 +237,7 @@ bool Size::isNotNull() const noexcept template bool Size::isValid() const noexcept { - return fWidth > 1 && fHeight > 1; + return fWidth > 0 && fHeight > 0; } template From 4661d1461ea092da06c7fada279cd3405de473c2 Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 29 Jan 2019 14:19:11 +0100 Subject: [PATCH 03/12] Add Window::isEmbed() method, for convenience Signed-off-by: falkTX --- dgl/Window.hpp | 2 ++ dgl/src/Window.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/dgl/Window.hpp b/dgl/Window.hpp index dbe3abfd..bc686c2c 100644 --- a/dgl/Window.hpp +++ b/dgl/Window.hpp @@ -92,6 +92,8 @@ public: bool openFileBrowser(const FileBrowserOptions& options); #endif + bool isEmbed() const noexcept; + bool isVisible() const noexcept; void setVisible(bool yesNo); diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index ae46addb..d155f3b4 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -1270,6 +1270,11 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) } #endif +bool Window::isEmbed() const noexcept +{ + return pData->fUsingEmbed; +} + bool Window::isVisible() const noexcept { return pData->fVisible; From e73e19e0251e2bf8a4707ea1f33239f6db35e0c4 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Fri, 8 Feb 2019 14:12:33 +0100 Subject: [PATCH 04/12] png2rgba: Support palette-based PNG files (#128) --- utils/png2rgba.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/png2rgba.py b/utils/png2rgba.py index 3575db7a..81354be1 100755 --- a/utils/png2rgba.py +++ b/utils/png2rgba.py @@ -52,7 +52,10 @@ def png2rgba(namespace, filenames): shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0] shortFilename = shortFilename.replace("-", "_") - png = Image.open(filename) + png = Image.open(filename) + if png.getpalette(): + png = png.convert() + pngNumpy = numpy.array(png) pngData = pngNumpy.tolist() #pngData.reverse() From 4206ad194ef21a31cfb8d20acee67159a7290413 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Thu, 7 Feb 2019 21:24:00 +0100 Subject: [PATCH 05/12] Provide a DISTRHO_DEPRECATED attribute --- distrho/src/DistrhoDefines.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/distrho/src/DistrhoDefines.h b/distrho/src/DistrhoDefines.h index c14cfb8a..f16e44d5 100644 --- a/distrho/src/DistrhoDefines.h +++ b/distrho/src/DistrhoDefines.h @@ -66,6 +66,15 @@ # define nullptr NULL #endif +/* Define DISTRHO_DEPRECATED */ +#if defined(__GNUC__) +# define DISTRHO_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define DISTRHO_DEPRECATED __declspec(deprecated) +#else +# define DISTRHO_DEPRECATED +#endif + /* Define DISTRHO_SAFE_ASSERT* */ #define DISTRHO_SAFE_ASSERT(cond) if (! (cond)) d_safe_assert(#cond, __FILE__, __LINE__); #define DISTRHO_SAFE_ASSERT_BREAK(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); break; } From e32be495c12dc641f93f16610347611eea0e75c1 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Thu, 7 Feb 2019 21:34:48 +0100 Subject: [PATCH 06/12] Add png2c, embedder of images in PNG format --- utils/png2c.py | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100755 utils/png2c.py diff --git a/utils/png2c.py b/utils/png2c.py new file mode 100755 index 00000000..6dc3ae62 --- /dev/null +++ b/utils/png2c.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# DISTRHO Plugin Framework (DPF) +# Copyright (C) 2012-2019 Filipe Coelho +# +# Permission to use, copy, modify, and/or distribute this software for any purpose with +# or without fee is hereby granted, provided that the above copyright notice and this +# 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. + +import os, sys + +# ----------------------------------------------------- + +def png2c(namespace, filenames): + + fdH = open("%s.hpp" % namespace, "w") + fdH.write("/* (Auto-generated binary data file). */\n") + fdH.write("\n") + fdH.write("#ifndef BINARY_%s_HPP\n" % namespace.upper()) + fdH.write("#define BINARY_%s_HPP\n" % namespace.upper()) + fdH.write("\n") + fdH.write("namespace %s\n" % namespace) + fdH.write("{\n") + + fdC = open("%s.cpp" % namespace, "w") + fdC.write("/* (Auto-generated binary data file). */\n") + fdC.write("\n") + fdC.write("#include \"%s.hpp\"\n" % namespace) + fdC.write("\n") + + tempIndex = 1 + + for filename in filenames: + shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0] + shortFilename = shortFilename.replace("-", "_") + + pngData = open(filename, 'rb').read() + + print("Generating data for \"%s\"" % (filename)) + + fdH.write(" extern const char* %sData;\n" % shortFilename) + fdH.write(" const unsigned int %sDataSize = %i;\n" % (shortFilename, len(pngData))) + + if tempIndex != len(filenames): + fdH.write("\n") + + fdC.write("static const unsigned char temp_%s_%i[] = {\n" % (shortFilename, tempIndex)) + + curColumn = 1 + fdC.write(" ") + + for data in pngData: + if curColumn == 0: + fdC.write(" ") + + fdC.write(" %3u," % data) + + if curColumn > 20: + fdC.write("\n ") + curColumn = 1 + else: + curColumn += 1 + + fdC.write("};\n") + fdC.write("const char* %s::%sData = (const char*)temp_%s_%i;\n" % (namespace, shortFilename, shortFilename, tempIndex)) + + if tempIndex != len(filenames): + fdC.write("\n") + + tempIndex += 1 + + fdH.write("}\n") + fdH.write("\n") + fdH.write("#endif // BINARY_%s_HPP\n" % namespace.upper()) + fdH.write("\n") + fdH.close() + + fdC.write("\n") + fdC.close() + +# ----------------------------------------------------- + +if __name__ == '__main__': + if len(sys.argv) != 3: + print("Usage: %s " % sys.argv[0]) + quit() + + namespace = sys.argv[1].replace("-","_") + artFolder = sys.argv[2] + + if not os.path.exists(artFolder): + print("Folder '%s' does not exist" % artFolder) + quit() + + # find png files + pngFiles = [] + + for root, dirs, files in os.walk(artFolder): + for name in [name for name in files if name.lower().endswith(".png")]: + pngFiles.append(os.path.join(root, name)) + + pngFiles.sort() + + # create code now + png2c(namespace, pngFiles) From 9f47e4f9f3539e536a3e611a81ba5a13e9a9ca80 Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 12 Feb 2019 10:59:25 +0100 Subject: [PATCH 07/12] Fix shebang on python scripts Signed-off-by: falkTX --- utils/png2c.py | 2 +- utils/png2rgba.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/png2c.py b/utils/png2c.py index 6dc3ae62..ab023658 100755 --- a/utils/png2c.py +++ b/utils/png2c.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # DISTRHO Plugin Framework (DPF) diff --git a/utils/png2rgba.py b/utils/png2rgba.py index 81354be1..99a50899 100755 --- a/utils/png2rgba.py +++ b/utils/png2rgba.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # DISTRHO Plugin Framework (DPF) -# Copyright (C) 2012-2016 Filipe Coelho +# Copyright (C) 2012-2019 Filipe Coelho # # Permission to use, copy, modify, and/or distribute this software for any purpose with # or without fee is hereby granted, provided that the above copyright notice and this From 2d617789feb8b4e82415eca1ace7be9e715a6651 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Wed, 9 Jan 2019 21:47:35 +0100 Subject: [PATCH 08/12] Fix some warnings emitted by GCC 8 and Clang 7 --- distrho/DistrhoPlugin.hpp | 26 ++++++++++++++++++++++++ distrho/src/DistrhoPluginLADSPA+DSSI.cpp | 4 ++-- distrho/src/DistrhoPluginLV2.cpp | 2 +- distrho/src/lv2/atom-util.h | 8 ++++---- examples/Meters/ExampleUIMeters.cpp | 2 +- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp index 527fcbe9..1da2bdb6 100644 --- a/distrho/DistrhoPlugin.hpp +++ b/distrho/DistrhoPlugin.hpp @@ -590,6 +590,22 @@ struct TimePosition { beatType(0.0f), ticksPerBeat(0.0), beatsPerMinute(0.0) {} + + /** + Reinitialize this position using the default null initialization. + */ + void clear() noexcept + { + valid = false; + bar = 0; + beat = 0; + tick = 0; + barStartTick = 0.0; + beatsPerBar = 0.0f; + beatType = 0.0f; + ticksPerBeat = 0.0; + beatsPerMinute = 0.0; + } } bbt; /** @@ -599,6 +615,16 @@ struct TimePosition { : playing(false), frame(0), bbt() {} + + /** + Reinitialize this position using the default null initialization. + */ + void clear() noexcept + { + playing = false; + frame = 0; + bbt.clear(); + } }; /** @} */ diff --git a/distrho/src/DistrhoPluginLADSPA+DSSI.cpp b/distrho/src/DistrhoPluginLADSPA+DSSI.cpp index 6f45decd..79dcf402 100644 --- a/distrho/src/DistrhoPluginLADSPA+DSSI.cpp +++ b/distrho/src/DistrhoPluginLADSPA+DSSI.cpp @@ -286,9 +286,9 @@ public: # if DISTRHO_PLUGIN_WANT_STATE char* dssi_configure(const char* const key, const char* const value) { - if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX) == 0)) + if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX)) == 0) return nullptr; - if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX) == 0)) + if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX)) == 0) return nullptr; fPlugin.setState(key, value); diff --git a/distrho/src/DistrhoPluginLV2.cpp b/distrho/src/DistrhoPluginLV2.cpp index b01df4eb..e66ec1d0 100644 --- a/distrho/src/DistrhoPluginLV2.cpp +++ b/distrho/src/DistrhoPluginLV2.cpp @@ -169,7 +169,7 @@ public: void lv2_activate() { #if DISTRHO_PLUGIN_WANT_TIMEPOS - std::memset(&fTimePosition, 0, sizeof(TimePosition)); + fTimePosition.clear(); // hosts may not send all values, resulting on some invalid data fTimePosition.bbt.bar = 1; diff --git a/distrho/src/lv2/atom-util.h b/distrho/src/lv2/atom-util.h index 13536872..cad90f89 100644 --- a/distrho/src/lv2/atom-util.h +++ b/distrho/src/lv2/atom-util.h @@ -117,13 +117,13 @@ lv2_atom_sequence_next(const LV2_Atom_Event* i) @endcode */ #define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ - for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ + for (const LV2_Atom_Event* iter = lv2_atom_sequence_begin(&(seq)->body); \ !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ (iter) = lv2_atom_sequence_next(iter)) /** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ #define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ - for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ + for (const LV2_Atom_Event* iter = lv2_atom_sequence_begin(body); \ !lv2_atom_sequence_is_end(body, size, (iter)); \ (iter) = lv2_atom_sequence_next(iter)) @@ -214,13 +214,13 @@ lv2_atom_tuple_next(const LV2_Atom* i) @endcode */ #define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ - for (const LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ + for (const LV2_Atom* iter = lv2_atom_tuple_begin(tuple); \ !lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(tuple), (tuple)->size, (iter)); \ (iter) = lv2_atom_tuple_next(iter)) /** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ #define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ - for (const LV2_Atom* (iter) = (const LV2_Atom*)body; \ + for (const LV2_Atom* iter = (const LV2_Atom*)body; \ !lv2_atom_tuple_is_end(body, size, (iter)); \ (iter) = lv2_atom_tuple_next(iter)) diff --git a/examples/Meters/ExampleUIMeters.cpp b/examples/Meters/ExampleUIMeters.cpp index d57c461f..3aa952fe 100644 --- a/examples/Meters/ExampleUIMeters.cpp +++ b/examples/Meters/ExampleUIMeters.cpp @@ -93,7 +93,7 @@ protected: A state has changed on the plugin side. This is called by the host to inform the UI about state changes. */ - void stateChanged(const char*, const char*) + void stateChanged(const char*, const char*) override { // nothing here } From 9647aaf225bf8f477dc27e78bb284212e2e106ca Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 30 Dec 2018 17:51:24 +0100 Subject: [PATCH 09/12] Adjust things for better external ui support, add example plugin Signed-off-by: falkTX --- Makefile | 9 + distrho/DistrhoUI.hpp | 15 +- distrho/extra/ExternalWindow.hpp | 50 ++++- distrho/src/DistrhoPluginJack.cpp | 5 - distrho/src/DistrhoUI.cpp | 33 ++- distrho/src/DistrhoUIDSSI.cpp | 2 + distrho/src/DistrhoUIInternal.hpp | 180 +++++++++++------ examples/ExternalUI/DistrhoPluginInfo.h | 36 ++++ examples/ExternalUI/ExternalExamplePlugin.cpp | 188 ++++++++++++++++++ examples/ExternalUI/ExternalExampleUI.cpp | 187 +++++++++++++++++ examples/ExternalUI/ExternalLauncher.sh | 40 ++++ examples/ExternalUI/Makefile | 40 ++++ examples/ExternalUI/README.md | 11 + 13 files changed, 696 insertions(+), 100 deletions(-) create mode 100644 examples/ExternalUI/DistrhoPluginInfo.h create mode 100644 examples/ExternalUI/ExternalExamplePlugin.cpp create mode 100644 examples/ExternalUI/ExternalExampleUI.cpp create mode 100755 examples/ExternalUI/ExternalLauncher.sh create mode 100644 examples/ExternalUI/Makefile create mode 100644 examples/ExternalUI/README.md diff --git a/Makefile b/Makefile index e27a4936..cf1b0cbc 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ ifeq ($(HAVE_DGL),true) endif examples: dgl + $(MAKE) all -C examples/ExternalUI $(MAKE) all -C examples/Info $(MAKE) all -C examples/Latency $(MAKE) all -C examples/Meters @@ -23,6 +24,13 @@ examples: dgl $(MAKE) all -C examples/Parameters $(MAKE) all -C examples/States + # ExternalUI launcher + install -d bin/d_extui-dssi + install -d bin/d_extui.lv2 + install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui.sh + install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui-dssi/d_extui.sh + install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui.lv2/d_extui.sh + ifneq ($(CROSS_COMPILING),true) gen: examples utils/lv2_ttl_generator @$(CURDIR)/utils/generate-ttl.sh @@ -40,6 +48,7 @@ endif clean: $(MAKE) clean -C dgl + $(MAKE) clean -C examples/ExternalUI $(MAKE) clean -C examples/Info $(MAKE) clean -C examples/Latency $(MAKE) clean -C examples/Meters diff --git a/distrho/DistrhoUI.hpp b/distrho/DistrhoUI.hpp index e33a4ca4..244b25bc 100644 --- a/distrho/DistrhoUI.hpp +++ b/distrho/DistrhoUI.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 @@ -20,7 +20,8 @@ #include "extra/LeakDetector.hpp" #include "src/DistrhoPluginChecks.h" -#ifndef HAVE_DGL +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include "../dgl/Base.hpp" # include "extra/ExternalWindow.hpp" typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; #elif DISTRHO_UI_USE_NANOVG @@ -67,7 +68,7 @@ public: */ bool isUserResizable() const noexcept; -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /** Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. @see Window::setGeometryConstraints(uint,uint,bool) @@ -181,7 +182,7 @@ protected: */ virtual void sampleRateChanged(double newSampleRate); -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /* -------------------------------------------------------------------------------------------------------- * UI Callbacks (optional) */ @@ -191,13 +192,13 @@ protected: */ virtual void uiIdle() {} -#ifndef DGL_FILE_BROWSER_DISABLED +# ifndef DGL_FILE_BROWSER_DISABLED /** File browser selected function. @see Window::fileBrowserSelected(const char*) */ virtual void uiFileBrowserSelected(const char* filename); -#endif +# endif /** OpenGL window reshape function, called when parent window is resized. @@ -225,7 +226,7 @@ private: friend class UIExporter; friend class UIExporterWindow; -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI // these should not be used void setAbsoluteX(int) const noexcept {} void setAbsoluteY(int) const noexcept {} diff --git a/distrho/extra/ExternalWindow.hpp b/distrho/extra/ExternalWindow.hpp index 8ad2df0f..c39f55c7 100644 --- a/distrho/extra/ExternalWindow.hpp +++ b/distrho/extra/ExternalWindow.hpp @@ -40,6 +40,8 @@ public: : width(w), height(h), title(t), + transientWinId(0), + visible(false), pid(0) {} virtual ~ExternalWindow() @@ -62,9 +64,14 @@ public: return title; } - void setTitle(const char* const t) noexcept + uintptr_t getTransientWinId() const noexcept { - title = t; + return transientWinId; + } + + bool isVisible() const noexcept + { + return visible; } bool isRunning() noexcept @@ -84,6 +91,27 @@ public: return true; } + virtual void setSize(uint w, uint h) + { + width = w; + height = h; + } + + virtual void setTitle(const char* const t) + { + title = t; + } + + virtual void setTransientWinId(const uintptr_t winId) + { + transientWinId = winId; + } + + virtual void setVisible(const bool yesNo) + { + visible = yesNo; + } + protected: bool startExternalProcess(const char* args[]) { @@ -107,14 +135,6 @@ protected: } } -private: - uint width; - uint height; - String title; - pid_t pid; - - friend class UIExporter; - void terminateAndWaitForProcess() { if (pid <= 0) @@ -162,6 +182,16 @@ private: } } +private: + uint width; + uint height; + String title; + uintptr_t transientWinId; + bool visible; + pid_t pid; + + friend class UIExporter; + DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) }; diff --git a/distrho/src/DistrhoPluginJack.cpp b/distrho/src/DistrhoPluginJack.cpp index 98ce73ca..edafaf66 100644 --- a/distrho/src/DistrhoPluginJack.cpp +++ b/distrho/src/DistrhoPluginJack.cpp @@ -16,11 +16,6 @@ #include "DistrhoPluginInternal.hpp" -#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI -# undef DISTRHO_PLUGIN_HAS_UI -# define DISTRHO_PLUGIN_HAS_UI 0 -#endif - #if DISTRHO_PLUGIN_HAS_UI # include "DistrhoUIInternal.hpp" #else diff --git a/distrho/src/DistrhoUI.cpp b/distrho/src/DistrhoUI.cpp index 89162d67..a9502161 100644 --- a/distrho/src/DistrhoUI.cpp +++ b/distrho/src/DistrhoUI.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 @@ -15,8 +15,7 @@ */ #include "DistrhoUIInternal.hpp" - -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI # include "src/WidgetPrivateData.hpp" #endif @@ -27,16 +26,21 @@ START_NAMESPACE_DISTRHO double d_lastUiSampleRate = 0.0; void* d_lastUiDspPtr = nullptr; -#ifdef HAVE_DGL -Window* d_lastUiWindow = nullptr; -#endif +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI uintptr_t g_nextWindowId = 0; const char* g_nextBundlePath = nullptr; +#else +Window* d_lastUiWindow = nullptr; +#endif /* ------------------------------------------------------------------------------------------------------------ * UI */ -#ifdef HAVE_DGL +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +UI::UI(uint width, uint height, bool userResizable) + : UIWidget(width, height), + pData(new PrivateData(userResizable)) {} +#else UI::UI(uint width, uint height, bool userResizable) : UIWidget(*d_lastUiWindow), pData(new PrivateData(userResizable)) @@ -46,10 +50,6 @@ UI::UI(uint width, uint height, bool userResizable) if (width > 0 && height > 0) setSize(width, height); } -#else -UI::UI(uint width, uint height, bool userResizable) - : UIWidget(width, height), - pData(new PrivateData(userResizable)) {} #endif UI::~UI() @@ -62,7 +62,7 @@ bool UI::isUserResizable() const noexcept return pData->userResizable; } -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) { DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); @@ -73,7 +73,6 @@ void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRa pData->minHeight = minHeight; getParentWindow().setGeometryConstraints(minWidth, minHeight, keepAspectRatio); - } #endif @@ -141,15 +140,15 @@ uintptr_t UI::getNextWindowId() noexcept void UI::sampleRateChanged(double) {} -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI /* ------------------------------------------------------------------------------------------------------------ * UI Callbacks (optional) */ -#ifndef DGL_FILE_BROWSER_DISABLED +# ifndef DGL_FILE_BROWSER_DISABLED void UI::uiFileBrowserSelected(const char*) { } -#endif +# endif void UI::uiReshape(uint width, uint height) { @@ -173,7 +172,7 @@ void UI::onResize(const ResizeEvent& ev) pData->setSizeCallback(ev.size.getWidth(), ev.size.getHeight()); } -#endif +#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI // ----------------------------------------------------------------------------------------------------------- diff --git a/distrho/src/DistrhoUIDSSI.cpp b/distrho/src/DistrhoUIDSSI.cpp index b11e1d0f..1ff4b47d 100644 --- a/distrho/src/DistrhoUIDSSI.cpp +++ b/distrho/src/DistrhoUIDSSI.cpp @@ -112,6 +112,7 @@ public: void exec() { + d_stdout("exec 1"); for (;;) { fOscData.idle(); @@ -121,6 +122,7 @@ public: d_msleep(30); } + d_stdout("exec 3"); } // ------------------------------------------------------------------- diff --git a/distrho/src/DistrhoUIInternal.hpp b/distrho/src/DistrhoUIInternal.hpp index a7a8ac3b..4ea26580 100644 --- a/distrho/src/DistrhoUIInternal.hpp +++ b/distrho/src/DistrhoUIInternal.hpp @@ -19,7 +19,10 @@ #include "../DistrhoUI.hpp" -#ifdef HAVE_DGL +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +# include "../extra/Sleep.hpp" +using DGL_NAMESPACE::IdleCallback; +#else # include "../../dgl/Application.hpp" # include "../../dgl/Window.hpp" using DGL_NAMESPACE::Application; @@ -34,7 +37,7 @@ START_NAMESPACE_DISTRHO extern double d_lastUiSampleRate; extern void* d_lastUiDspPtr; -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI extern Window* d_lastUiWindow; #endif extern uintptr_t g_nextWindowId; @@ -146,7 +149,20 @@ struct UI::PrivateData { // ----------------------------------------------------------------------- // Plugin Window, needed to take care of resize properly -#ifdef HAVE_DGL +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI +static inline +UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) +{ + d_lastUiDspPtr = dspPtr; + g_nextWindowId = winId; + g_nextBundlePath = bundlePath; + UI* const ret = createUI(); + d_lastUiDspPtr = nullptr; + g_nextWindowId = 0; + g_nextBundlePath = nullptr; + return ret; +} +#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI static inline UI* createUiWrapper(void* const dspPtr, Window* const window) { @@ -212,7 +228,7 @@ protected: fIsReady = true; } -#ifndef DGL_FILE_BROWSER_DISABLED +# ifndef DGL_FILE_BROWSER_DISABLED // custom file-browser selected void fileBrowserSelected(const char* filename) override { @@ -220,26 +236,13 @@ protected: fUI->uiFileBrowserSelected(filename); } -#endif +# endif private: UI* const fUI; bool fIsReady; }; -#else -static inline -UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath) -{ - d_lastUiDspPtr = dspPtr; - g_nextWindowId = winId; - g_nextBundlePath = bundlePath; - UI* const ret = createUI(); - d_lastUiDspPtr = nullptr; - g_nextWindowId = 0; - g_nextBundlePath = nullptr; - return ret; -} -#endif +#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI // ----------------------------------------------------------------------- // UI exporter class @@ -256,13 +259,13 @@ public: const setSizeFunc setSizeCall, void* const dspPtr = nullptr, const char* const bundlePath = nullptr) -#ifdef HAVE_DGL +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + : fUI(createUiWrapper(dspPtr, winId, bundlePath)), +#else : glApp(), glWindow(glApp, winId, dspPtr), fChangingSize(false), fUI(glWindow.getUI()), -#else - : fUI(createUiWrapper(dspPtr, winId, bundlePath)), #endif fData((fUI != nullptr) ? fUI->pData : nullptr) { @@ -276,54 +279,65 @@ public: fData->sendNoteCallbackFunc = sendNoteCall; fData->setSizeCallbackFunc = setSizeCall; -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI // unused return; (void)bundlePath; #endif } +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + ~UIExporter() + { + delete fUI; + } +#endif + // ------------------------------------------------------------------- +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI uint getWidth() const noexcept { -#ifdef HAVE_DGL - return glWindow.getWidth(); -#else DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); return fUI->getWidth(); -#endif } uint getHeight() const noexcept { -#ifdef HAVE_DGL - return glWindow.getHeight(); -#else DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1); return fUI->getHeight(); -#endif } bool isVisible() const noexcept { -#ifdef HAVE_DGL - return glWindow.isVisible(); -#else DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); return fUI->isRunning(); -#endif } - // ------------------------------------------------------------------- + intptr_t getWindowId() const noexcept + { + return 0; + } +#else + uint getWidth() const noexcept + { + return glWindow.getWidth(); + } + + uint getHeight() const noexcept + { + return glWindow.getHeight(); + } + + bool isVisible() const noexcept + { + return glWindow.isVisible(); + } intptr_t getWindowId() const noexcept { -#ifdef HAVE_DGL return glWindow.getWindowId(); -#else - return 0; -#endif } +#endif // ------------------------------------------------------------------- @@ -365,7 +379,39 @@ public: // ------------------------------------------------------------------- -#ifdef HAVE_DGL +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI + void exec(IdleCallback* const cb) + { + DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); + DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); + + fUI->setVisible(true); + cb->idleCallback(); + + while (fUI->isRunning()) + { + d_msleep(10); + cb->idleCallback(); + } + } + + void exec_idle() + { + } + + bool idle() + { + return true; + } + + void quit() + { + DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); + + fUI->setVisible(false); + fUI->terminateAndWaitForProcess(); + } +#else void exec(IdleCallback* const cb) { DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); @@ -381,48 +427,64 @@ public: if (glWindow.isReady()) fUI->uiIdle(); } -#endif bool idle() { DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); -#ifdef HAVE_DGL glApp.idle(); if (glWindow.isReady()) fUI->uiIdle(); return ! glApp.isQuiting(); -#else - return fUI->isRunning(); -#endif } void quit() { -#ifdef HAVE_DGL glWindow.close(); glApp.quit(); -#else - DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); - fUI->terminateAndWaitForProcess(); -#endif } +#endif // ------------------------------------------------------------------- +#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI void setWindowTitle(const char* const uiTitle) { -#ifdef HAVE_DGL - glWindow.setTitle(uiTitle); -#else DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); + fUI->setTitle(uiTitle); -#endif } -#ifdef HAVE_DGL + void setWindowSize(const uint width, const uint height, const bool = false) + { + DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); + + fUI->setSize(width, height); + } + + void setWindowTransientWinId(const uintptr_t winId) + { + DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); + + fUI->setTransientWinId(winId); + } + + bool setWindowVisible(const bool yesNo) + { + DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false); + + fUI->setVisible(yesNo); + + return fUI->isRunning(); + } +#else + void setWindowTitle(const char* const uiTitle) + { + glWindow.setTitle(uiTitle); + } + void setWindowSize(const uint width, const uint height, const bool updateUI = false) { DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); @@ -459,10 +521,6 @@ public: { return glWindow.handlePluginSpecial(press, key); } -#else - void setWindowSize(const uint, const uint, const bool = false) {} - void setWindowTransientWinId(const uintptr_t) {} - bool setWindowVisible(const bool) { return true; } #endif // ------------------------------------------------------------------- @@ -483,7 +541,7 @@ public: } private: -#ifdef HAVE_DGL +#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI // ------------------------------------------------------------------- // DGL Application and Window for this widget diff --git a/examples/ExternalUI/DistrhoPluginInfo.h b/examples/ExternalUI/DistrhoPluginInfo.h new file mode 100644 index 00000000..3163c2c3 --- /dev/null +++ b/examples/ExternalUI/DistrhoPluginInfo.h @@ -0,0 +1,36 @@ +/* + * DISTRHO Plugin Framework (DPF) + * 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 + * 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_PLUGIN_INFO_H_INCLUDED +#define DISTRHO_PLUGIN_INFO_H_INCLUDED + +#define DISTRHO_PLUGIN_BRAND "DISTRHO" +#define DISTRHO_PLUGIN_NAME "ExternalUI" +#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/examples/ExternalUI" + +#define DISTRHO_PLUGIN_HAS_UI 1 +#define DISTRHO_PLUGIN_HAS_EMBED_UI 0 +#define DISTRHO_PLUGIN_HAS_EXTERNAL_UI 1 +#define DISTRHO_PLUGIN_IS_RT_SAFE 1 +#define DISTRHO_PLUGIN_NUM_INPUTS 1 +#define DISTRHO_PLUGIN_NUM_OUTPUTS 1 + +enum Parameters { + kParameterLevel = 0, + kParameterCount +}; + +#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/examples/ExternalUI/ExternalExamplePlugin.cpp b/examples/ExternalUI/ExternalExamplePlugin.cpp new file mode 100644 index 00000000..dbecdcc6 --- /dev/null +++ b/examples/ExternalUI/ExternalExamplePlugin.cpp @@ -0,0 +1,188 @@ +/* + * DISTRHO Plugin Framework (DPF) + * 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 + * 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 "DistrhoPlugin.hpp" + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +/** + Plugin to show how to get some basic information sent to the UI. + */ +class ExternalExamplePlugin : public Plugin +{ +public: + ExternalExamplePlugin() + : Plugin(kParameterCount, 0, 0), + fValue(0.0f) + { + } + +protected: + /* -------------------------------------------------------------------------------------------------------- + * Information */ + + /** + Get the plugin label. + This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters. + */ + const char* getLabel() const override + { + return "ExternalUI"; + } + + /** + Get an extensive comment/description about the plugin. + */ + const char* getDescription() const override + { + return "Plugin to show how to use an external / remote UI."; + } + + /** + Get the plugin author/maker. + */ + const char* getMaker() const override + { + return "DISTRHO"; + } + + /** + Get the plugin homepage. + */ + const char* getHomePage() const override + { + return "https://github.com/DISTRHO/DPF"; + } + + /** + Get the plugin license name (a single line of text). + For commercial plugins this should return some short copyright information. + */ + const char* getLicense() const override + { + return "ISC"; + } + + /** + Get the plugin version, in hexadecimal. + */ + uint32_t getVersion() const override + { + return d_version(1, 0, 0); + } + + /** + Get the plugin unique Id. + This value is used by LADSPA, DSSI and VST plugin formats. + */ + int64_t getUniqueId() const override + { + return d_cconst('d', 'E', 'x', 't'); + } + + /* -------------------------------------------------------------------------------------------------------- + * Init */ + + /** + Initialize the parameter @a index. + This function will be called once, shortly after the plugin is created. + */ + void initParameter(uint32_t index, Parameter& parameter) override + { + if (index != 0) + return; + + parameter.hints = kParameterIsAutomable|kParameterIsInteger; + parameter.ranges.def = 0.0f; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 100.0f; + parameter.name = "Value"; + parameter.symbol = "value"; + } + + /* -------------------------------------------------------------------------------------------------------- + * Internal data */ + + /** + Get the current value of a parameter. + The host may call this function from any context, including realtime processing. + */ + float getParameterValue(uint32_t index) const override + { + if (index != 0) + return 0.0f; + + return fValue; + + } + + /** + Change a parameter value. + The host may call this function from any context, including realtime processing. + When a parameter is marked as automable, you must ensure no non-realtime operations are performed. + @note This function will only be called for parameter inputs. + */ + void setParameterValue(uint32_t index, float value) override + { + if (index != 0) + return; + + fValue = value; + } + + /* -------------------------------------------------------------------------------------------------------- + * Audio/MIDI Processing */ + + /** + Run/process function for plugins without MIDI input. + @note Some parameters might be null if there are no audio inputs or outputs. + */ + void run(const float** inputs, float** outputs, uint32_t frames) override + { + /** + This plugin does nothing, it just demonstrates information usage. + So here we directly copy inputs over outputs, leaving the audio untouched. + We need to be careful in case the host re-uses the same buffer for both ins and outs. + */ + if (outputs[0] != inputs[0]) + std::memcpy(outputs[0], inputs[0], sizeof(float)*frames); + } + + // ------------------------------------------------------------------------------------------------------- + +private: + // Parameters + float fValue; + + /** + Set our plugin class as non-copyable and add a leak detector just in case. + */ + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExternalExamplePlugin) +}; + +/* ------------------------------------------------------------------------------------------------------------ + * Plugin entry point, called by DPF to create a new plugin instance. */ + +Plugin* createPlugin() +{ + return new ExternalExamplePlugin(); +} + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/examples/ExternalUI/ExternalExampleUI.cpp b/examples/ExternalUI/ExternalExampleUI.cpp new file mode 100644 index 00000000..66cfc85b --- /dev/null +++ b/examples/ExternalUI/ExternalExampleUI.cpp @@ -0,0 +1,187 @@ +/* + * DISTRHO Plugin Framework (DPF) + * 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 + * 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 "DistrhoUI.hpp" + +// Extra includes for current path and fifo stuff +#include +#include +#include +#include + +START_NAMESPACE_DISTRHO + +// TODO: generate a random, not-yet-existing, filename +const char* const kFifoFilename = "/tmp/dpf-fifo-test"; + +// Helper to get current path of this plugin +static const char* getCurrentPluginFilename() +{ + Dl_info exeInfo; + void* localSymbol = (void*)kFifoFilename; + dladdr(localSymbol, &exeInfo); + return exeInfo.dli_fname; +} + +// Helper to check if a file exists +static bool fileExists(const char* const filename) +{ + return access(filename, F_OK) != -1; +} + +// Helper function to keep trying to write until it succeeds or really errors out +static ssize_t +writeRetry(int fd, const void* src, size_t size) +{ + ssize_t error; + + do { + error = write(fd, src, size); + } while (error == -1 && (errno == EINTR || errno == EPIPE)); + + return error; +} + +// ----------------------------------------------------------------------------------------------------------- + +class ExternalExampleUI : public UI +{ +public: + ExternalExampleUI() + : UI(405, 256, true), + fFifo(-1), + fValue(0.0f), + fExternalScript(getNextBundlePath()) + { + if (fExternalScript.isEmpty()) + { + fExternalScript = getCurrentPluginFilename(); + fExternalScript.truncate(fExternalScript.rfind('/')); + } + + fExternalScript += "/d_extui.sh"; + d_stdout("External script = %s", fExternalScript.buffer()); + } + +protected: + /* -------------------------------------------------------------------------------------------------------- + * DSP/Plugin Callbacks */ + + /** + A parameter has changed on the plugin side. + This is called by the host to inform the UI about parameter changes. + */ + void parameterChanged(uint32_t index, float value) override + { + if (index != 0) + return; + + fValue = value; + + if (fFifo == -1) + return; + + // NOTE: This is a terrible way to pass values, also locale might get in the way... + char valueStr[24]; + std::memset(valueStr, 0, sizeof(valueStr)); + std::snprintf(valueStr, 23, "%i\n", static_cast(value + 0.5f)); + + DISTRHO_SAFE_ASSERT(writeRetry(fFifo, valueStr, 24) == sizeof(valueStr)); + } + + /* -------------------------------------------------------------------------------------------------------- + * External Window overrides */ + + /** + Manage external process and IPC when UI is requested to be visible. + */ + void setVisible(const bool yesNo) override + { + if (yesNo) + { + DISTRHO_SAFE_ASSERT_RETURN(fileExists(fExternalScript),); + + mkfifo(kFifoFilename, 0666); + sync(); + + char winIdStr[24]; + std::memset(winIdStr, 0, sizeof(winIdStr)); + std::snprintf(winIdStr, 23, "%lu", getTransientWinId()); + + const char* args[] = { + fExternalScript.buffer(), + kFifoFilename, + "--progressbar", "External UI example", + "--title", getTitle(), + nullptr, + }; + DISTRHO_SAFE_ASSERT_RETURN(startExternalProcess(args),); + + // NOTE: this can lockup the current thread if the other side does not read the file! + fFifo = open(kFifoFilename, O_WRONLY); + DISTRHO_SAFE_ASSERT_RETURN(fFifo != -1,); + + parameterChanged(0, fValue); + } + else + { + if (fFifo != -1) + { + if (isRunning()) + { + DISTRHO_SAFE_ASSERT(writeRetry(fFifo, "quit\n", 5) == 5); + fsync(fFifo); + } + close(fFifo); + fFifo = -1; + } + + unlink(kFifoFilename); + terminateAndWaitForProcess(); + } + + UI::setVisible(yesNo); + } + + // ------------------------------------------------------------------------------------------------------- + +private: + // IPC Stuff + int fFifo; + + // Current value, cached for when UI becomes visible + float fValue; + + // Path to external ui script + String fExternalScript; + + /** + Set our UI class as non-copyable and add a leak detector just in case. + */ + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExternalExampleUI) +}; + +/* ------------------------------------------------------------------------------------------------------------ + * UI entry point, called by DPF to create a new UI instance. */ + +UI* createUI() +{ + return new ExternalExampleUI(); +} + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/examples/ExternalUI/ExternalLauncher.sh b/examples/ExternalUI/ExternalLauncher.sh new file mode 100755 index 00000000..1ca7c94c --- /dev/null +++ b/examples/ExternalUI/ExternalLauncher.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Read FIFO argument from CLI +FIFO=${1} +shift + +if [ ! -e "${FIFO}" ]; then + echo "Fifo file ${FIFO} does not exist, cannot run" + exit 1 +fi + +# Start kdialog with all other arguments and get dbus reference +dbusRef=$(kdialog "$@" 100) + +if [ $? -ne 0 ] || [ -z "${dbusRef}" ]; then + echo "Failed to start kdialog" + exit 1 +fi + +# Setup cancellation point for this script +quitfn() { + qdbus ${dbusRef} close 2>/dev/null +} + +trap quitfn SIGINT +trap quitfn SIGTERM + +# Read Fifo for new values or a quit message +while read line <"${FIFO}"; do + if echo "${line}" | grep -q "quit"; then + break + fi + if ! qdbus ${dbusRef} Set "" value "${line}"; then + break + fi +done + +# Cleanup +rm -f "${FIFO}" +quitfn diff --git a/examples/ExternalUI/Makefile b/examples/ExternalUI/Makefile new file mode 100644 index 00000000..ba1df228 --- /dev/null +++ b/examples/ExternalUI/Makefile @@ -0,0 +1,40 @@ +#!/usr/bin/make -f +# Makefile for DISTRHO Plugins # +# ---------------------------- # +# Created by falkTX +# + +# -------------------------------------------------------------- +# Project name, used for binaries + +NAME = d_extui + +# -------------------------------------------------------------- +# Files to build + +FILES_DSP = \ + ExternalExamplePlugin.cpp + +FILES_UI = \ + ExternalExampleUI.cpp + +# -------------------------------------------------------------- +# Do some magic + +include ../../Makefile.plugins.mk + +LINK_FLAGS += -ldl + +# -------------------------------------------------------------- +# Enable all possible plugin types + +ifeq ($(HAVE_JACK),true) +TARGETS += jack +endif + +TARGETS += dssi +TARGETS += lv2_sep + +all: $(TARGETS) + +# -------------------------------------------------------------- diff --git a/examples/ExternalUI/README.md b/examples/ExternalUI/README.md new file mode 100644 index 00000000..6fb4d3ea --- /dev/null +++ b/examples/ExternalUI/README.md @@ -0,0 +1,11 @@ +# External UI example + +This example will show how to use an external / remote UI together with DPF.
+ +The Plugin has a shell script that calls kdialog and uses qdbus for sending values to it.
+It is a very ugly way to show a remote UI (using a shell script!), but it is only to prove the point.
+ +Note that everything regarding external UIs is still a bit experimental in DPF.
+There is Unix-specific code in there.
+ +If this is something you are interested on using and contributing to, please let us know.
From 5e35de08724b3596db99c08cc04fa653b30ff9bd Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 30 Dec 2018 17:59:14 +0100 Subject: [PATCH 10/12] Remove leftover debug prints Signed-off-by: falkTX --- distrho/src/DistrhoUIDSSI.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/distrho/src/DistrhoUIDSSI.cpp b/distrho/src/DistrhoUIDSSI.cpp index 1ff4b47d..b11e1d0f 100644 --- a/distrho/src/DistrhoUIDSSI.cpp +++ b/distrho/src/DistrhoUIDSSI.cpp @@ -112,7 +112,6 @@ public: void exec() { - d_stdout("exec 1"); for (;;) { fOscData.idle(); @@ -122,7 +121,6 @@ public: d_msleep(30); } - d_stdout("exec 3"); } // ------------------------------------------------------------------- From 220ccd3c813a10d886ca1ce74bd0afc05595db67 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 30 Dec 2018 18:45:48 +0100 Subject: [PATCH 11/12] Dont build external UI example under windows Signed-off-by: falkTX --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cf1b0cbc..036f9c91 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,6 @@ ifeq ($(HAVE_DGL),true) endif examples: dgl - $(MAKE) all -C examples/ExternalUI $(MAKE) all -C examples/Info $(MAKE) all -C examples/Latency $(MAKE) all -C examples/Meters @@ -24,12 +23,15 @@ examples: dgl $(MAKE) all -C examples/Parameters $(MAKE) all -C examples/States - # ExternalUI launcher +ifneq ($(WIN32),true) + # ExternalUI does not work on Windows + $(MAKE) all -C examples/ExternalUI install -d bin/d_extui-dssi install -d bin/d_extui.lv2 install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui.sh install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui-dssi/d_extui.sh install -m 755 examples/ExternalUI/ExternalLauncher.sh bin/d_extui.lv2/d_extui.sh +endif ifneq ($(CROSS_COMPILING),true) gen: examples utils/lv2_ttl_generator From bbd99943b5e884132dd7542cab6fef5cc3033057 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 30 Dec 2018 19:11:31 +0100 Subject: [PATCH 12/12] Also dont build external-ui for macOS, for now Signed-off-by: falkTX --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 036f9c91..e14bbfd2 100644 --- a/Makefile +++ b/Makefile @@ -23,8 +23,8 @@ examples: dgl $(MAKE) all -C examples/Parameters $(MAKE) all -C examples/States -ifneq ($(WIN32),true) - # ExternalUI does not work on Windows +ifneq ($(MACOS_OR_WIN32),true) + # ExternalUI is WIP $(MAKE) all -C examples/ExternalUI install -d bin/d_extui-dssi install -d bin/d_extui.lv2