diff --git a/source/plugin/Makefile b/source/plugin/Makefile index b479390ad..03dbf7fbb 100644 --- a/source/plugin/Makefile +++ b/source/plugin/Makefile @@ -45,10 +45,8 @@ endif # -------------------------------------------------------------- # Native -DGL_LIBS = -lX11 -lXext - ifeq ($(HAVE_OPENGL),true) -LINK_FLAGS += $(shell pkg-config --libs gl) $(DGL_LIBS) +LINK_FLAGS += $(shell pkg-config --libs gl) endif ifeq ($(HAVE_AF_DEPS),true) @@ -69,7 +67,15 @@ LINK_FLAGS += $(shell pkg-config --libs ntk_images ntk) -lfreetype # FIXME endif endif -LINK_FLAGS += $(EXTRA_LIBS) +# -------------------------------------------------------------- +# Juce + +LINK_FLAGS += $(JUCE_AUDIO_BASICS_LIBS) +LINK_FLAGS += $(JUCE_CORE_LIBS) +LINK_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) +LINK_FLAGS += $(JUCE_EVENTS_LIBS) +LINK_FLAGS += $(JUCE_GRAPHICS_LIBS) +LINK_FLAGS += $(JUCE_GUI_BASICS_LIBS) # -------------------------------------------------------------- @@ -147,7 +153,7 @@ carla-native-lv2-export.exe: carla-native-lv2-export.cpp.o $(LIBS) # -------------------------------------------------------------- .FORCE: -.PHONY: .FORCE carla-native-lv2-export carla-native-lv2-export.exe +.PHONY: .FORCE ../modules/%.a: .FORCE $(MAKE) -C ../modules $* diff --git a/source/plugin/carla-native-lv2-export.cpp b/source/plugin/carla-native-lv2-export.cpp index 2965b23d7..72eaf4df0 100644 --- a/source/plugin/carla-native-lv2-export.cpp +++ b/source/plugin/carla-native-lv2-export.cpp @@ -133,7 +133,7 @@ void writeManifestFile() // ------------------------------------------------------------------- // UI - text += "\n"; + text += "\n"; text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; text += " ui:binary ;\n"; text += " lv2:extensionData <" LV2_PROGRAMS__UIInterface "> ;\n"; @@ -242,6 +242,8 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) break; } + text += "\n"; + // ------------------------------------------------------------------- // Features @@ -290,7 +292,7 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) if (pluginDesc->hints & PLUGIN_HAS_GUI) { - text += " ui:ui ;\n"; + text += " ui:ui ;\n"; text += "\n"; } diff --git a/source/plugin/carla-native-lv2.cpp b/source/plugin/carla-native-lv2.cpp index 5c161582a..ef2993cd2 100644 --- a/source/plugin/carla-native-lv2.cpp +++ b/source/plugin/carla-native-lv2.cpp @@ -19,6 +19,7 @@ #include "carla-native-base.cpp" #include "juce_audio_basics.h" +#include "juce_gui_basics.h" #include "CarlaString.hpp" @@ -35,7 +36,52 @@ #include "lv2/lv2_external_ui.h" #include "lv2/lv2_programs.h" -using juce::FloatVectorOperations; +using namespace juce; + +// ----------------------------------------------------------------------- +// Juce Message Thread + +class JuceMessageThread : public Thread +{ +public: + JuceMessageThread() + : Thread("JuceMessageThread"), + fInitialised(false) + { + startThread(7); + + while (! fInitialised) + sleep(1); + } + + ~JuceMessageThread() + { + signalThreadShouldExit(); + JUCEApplication::quit(); + waitForThreadToExit(5000); + clearSingletonInstance(); + } + + void run() + { + initialiseJuce_GUI(); + fInitialised = true; + + MessageManager::getInstance()->setCurrentThreadAsMessageThread(); + + while ((! threadShouldExit()) && MessageManager::getInstance()->runDispatchLoopUntil(250)) + {} + } + + juce_DeclareSingleton(JuceMessageThread, false); + +private: + bool fInitialised; +}; + +juce_ImplementSingleton(JuceMessageThread) + +static Array gActivePlugins; // ----------------------------------------------------------------------- // LV2 descriptor functions @@ -49,6 +95,7 @@ public: : fHandle(nullptr), fDescriptor(desc), fMidiEventCount(0), + fUiWasShown(false), fIsProcessing(false), fVolume(1.0f), fDryWet(1.0f), @@ -142,6 +189,7 @@ public: ~NativePlugin() { CARLA_ASSERT(fHandle == nullptr); + CARLA_ASSERT(! fUiWasShown); if (fHost.resourceDir != nullptr) { @@ -205,7 +253,27 @@ public: { if (fDescriptor->cleanup != nullptr) fDescriptor->cleanup(fHandle); + fHandle = nullptr; + + if (fUiWasShown) + { + CARLA_SAFE_ASSERT_RETURN(gActivePlugins.contains(this),); + + gActivePlugins.removeFirstMatchingValue(this); + + JUCE_AUTORELEASEPOOL + + MessageManagerLock mmLock; + + if (gActivePlugins.size() == 0) + { + JuceMessageThread::deleteInstance(); + shutdownJuce_GUI(); + } + + fUiWasShown = false; + } } void lv2_run(const uint32_t frames) @@ -573,7 +641,26 @@ protected: void handleUiShow() { if (fDescriptor->ui_show != nullptr) - fDescriptor->ui_show(fHandle, true); + { + if (fDescriptor->hints & PLUGIN_NEEDS_UI_JUCE) + { + JUCE_AUTORELEASEPOOL + + if (gActivePlugins.size() == 0) + { + initialiseJuce_GUI(); + JuceMessageThread::getInstance(); + } + + MessageManagerLock mmLock; + fDescriptor->ui_show(fHandle, true); + + fUiWasShown = true; + gActivePlugins.add(this); + } + else + fDescriptor->ui_show(fHandle, true); + } fUI.isVisible = true; } @@ -737,6 +824,7 @@ private: MidiEvent fMidiEvents[kMaxMidiEvents*2]; TimeInfo fTimeInfo; + bool fUiWasShown; bool fIsProcessing; float fVolume; float fDryWet; @@ -1095,7 +1183,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sa if (std::strncmp(lv2Descriptor->URI, "http://kxstudio.sf.net/carla/plugins/", 37) == 0) pluginLabel = lv2Descriptor->URI+37; else if (std::strcmp(lv2Descriptor->URI, "http://kxstudio.sf.net/carla") == 0) - pluginLabel = lv2Descriptor->URI+23; + pluginLabel = "carla"; if (pluginLabel == nullptr) { @@ -1346,7 +1434,7 @@ const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) carla_debug("lv2ui_descriptor(%i)", index); static const LV2UI_Descriptor lv2UiDesc = { - /* URI */ "http://kxstudio.sf.net/carla#UI", + /* URI */ "http://kxstudio.sf.net/carla/ui", /* instantiate */ lv2ui_instantiate, /* cleanup */ lv2ui_cleanup, /* port_event */ lv2ui_port_event,