| @@ -7,7 +7,7 @@ THIS IS CURRENTLY A WORK IN PROGRESS RESEARCH PROJECT. | |||
| It is not known yet how well this can work, mostly testing waters here. | |||
| Currently the plugin will link against an internal [Carla](https://github.com/falkTX/Carla) for the plugin host part, embeding UIs if possible. | |||
| Audio, MIDI and Time information works, but there is no latency, parameters or state handled right now. | |||
| Audio, MIDI, Latency and Time information and State save/loading works, but there are no parameters right now. | |||
| Also, only LV2 hosting is enabled at the moment. | |||
| Ildaeil basically works as a mini-wrapper around Carla, leveraging it for all its host support. | |||
| @@ -1 +1 @@ | |||
| Subproject commit a310640e0fcb1aef53fe7d15771cccebdc9731c8 | |||
| Subproject commit f93784ef1ad549a85f01dc4715920b9485303e0a | |||
| @@ -2,5 +2,7 @@ | |||
| ../../dpf/distrho/ | |||
| ../../dpf-widgets/generic | |||
| ../../dpf-widgets/opengl | |||
| /usr/include/carla | |||
| /usr/include/carla/includes | |||
| ../../carla/source/backend | |||
| ../../carla/source/includes | |||
| ../../carla/source/modules | |||
| ../../carla/source/utils | |||
| @@ -16,6 +16,9 @@ | |||
| */ | |||
| #include "CarlaNativePlugin.h" | |||
| #include "CarlaEngine.hpp" | |||
| #include "water/streams/MemoryOutputStream.h" | |||
| #include "water/xml/XmlDocument.h" | |||
| #include "DistrhoPlugin.hpp" | |||
| @@ -52,11 +55,13 @@ public: | |||
| #endif | |||
| mutable NativeTimeInfo fCarlaTimeInfo; | |||
| mutable water::MemoryOutputStream fLastProjectState; | |||
| uint32_t fLastLatencyValue; | |||
| void* fUI; | |||
| IldaeilPlugin() | |||
| : Plugin(0, 0, 0), | |||
| : Plugin(0, 0, 1), | |||
| fCarlaPluginDescriptor(nullptr), | |||
| fCarlaPluginHandle(nullptr), | |||
| fCarlaHostHandle(nullptr), | |||
| @@ -65,6 +70,7 @@ public: | |||
| fMidiEventCount(0), | |||
| fDummyBuffer(nullptr), | |||
| #endif | |||
| fLastLatencyValue(0), | |||
| fUI(nullptr) | |||
| { | |||
| fCarlaPluginDescriptor = carla_get_native_rack_plugin(); | |||
| @@ -246,16 +252,72 @@ protected: | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Init */ | |||
| void initState(const uint32_t index, String& stateKey, String& defaultStateValue) override | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(index == 0,); | |||
| stateKey = "project"; | |||
| defaultStateValue = "" | |||
| "<?xml version='1.0' encoding='UTF-8'?>\n" | |||
| "<!DOCTYPE CARLA-PROJECT>\n" | |||
| "<CARLA-PROJECT VERSION='" CARLA_VERSION_STRMIN "'>\n" | |||
| "</CARLA-PROJECT>\n"; | |||
| } | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Internal data */ | |||
| String getState(const char* const key) const override | |||
| { | |||
| if (std::strcmp(key, "project") == 0) | |||
| { | |||
| CarlaEngine* const engine = carla_get_engine_from_handle(fCarlaHostHandle); | |||
| fLastProjectState.reset(); | |||
| engine->saveProjectInternal(fLastProjectState); | |||
| return String(static_cast<char*>(fLastProjectState.getDataAndRelease()), false); | |||
| } | |||
| return String(); | |||
| } | |||
| void setState(const char* const key, const char* const value) override | |||
| { | |||
| if (std::strcmp(key, "project") == 0) | |||
| { | |||
| CarlaEngine* const engine = carla_get_engine_from_handle(fCarlaHostHandle); | |||
| water::XmlDocument xml(value); | |||
| engine->loadProjectInternal(xml, true); | |||
| } | |||
| } | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Process */ | |||
| void checkLatencyChanged() | |||
| { | |||
| if (fCarlaHostHandle == nullptr) | |||
| return; | |||
| uint32_t latency = 0; | |||
| for (uint32_t i=0; i < carla_get_current_plugin_count(fCarlaHostHandle); ++i) | |||
| latency += carla_get_plugin_latency(fCarlaHostHandle, i); | |||
| if (fLastLatencyValue != latency) | |||
| { | |||
| fLastLatencyValue = latency; | |||
| setLatency(latency); | |||
| } | |||
| } | |||
| void activate() override | |||
| { | |||
| if (fCarlaPluginHandle != nullptr) | |||
| fCarlaPluginDescriptor->activate(fCarlaPluginHandle); | |||
| checkLatencyChanged(); | |||
| } | |||
| void deactivate() override | |||
| @@ -305,6 +367,8 @@ protected: | |||
| #else | |||
| fCarlaPluginDescriptor->process(fCarlaPluginHandle, (float**)inputs, outputs, frames, nullptr, 0); | |||
| #endif | |||
| checkLatencyChanged(); | |||
| } | |||
| else | |||
| { | |||
| @@ -59,7 +59,8 @@ class IldaeilUI : public UI, | |||
| kDrawingLoading, | |||
| kDrawingPluginList, | |||
| kDrawingPluginCustomUI, | |||
| kDrawingPluginGenericUI | |||
| kDrawingPluginGenericUI, | |||
| kDrawingPluginPendingFromInit | |||
| } fDrawingState; | |||
| struct PluginInfoCache { | |||
| @@ -130,22 +131,16 @@ public: | |||
| carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_UI_SCALE, getScaleFactor()*1000, nullptr); | |||
| if (carla_get_current_plugin_count(handle) != 0) | |||
| { | |||
| showPluginUI(handle); | |||
| startThread(); | |||
| return; | |||
| } | |||
| fDrawingState = kDrawingPluginPendingFromInit; | |||
| } | |||
| ~IldaeilUI() override | |||
| { | |||
| if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr) | |||
| return; | |||
| stopThread(-1); | |||
| if (isThreadRunning()) | |||
| stopThread(-1); | |||
| // fPlugin->fUI = nullptr; | |||
| hidePluginUI(fPlugin->fCarlaHostHandle); | |||
| hidePluginUI(); | |||
| delete[] fPlugins; | |||
| } | |||
| @@ -161,19 +156,23 @@ public: | |||
| } | |||
| else | |||
| { | |||
| fDrawingState = kDrawingPluginGenericUI; | |||
| // TODO query parameter information and store it | |||
| const double scaleFactor = getScaleFactor(); | |||
| setSize(kGenericWidth * scaleFactor, (kGenericHeight + kExtraHeight) * scaleFactor); | |||
| fDrawingState = kDrawingPluginGenericUI; | |||
| } | |||
| repaint(); | |||
| } | |||
| void hidePluginUI(const CarlaHostHandle handle) | |||
| void hidePluginUI() | |||
| { | |||
| if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr) | |||
| return; | |||
| if (fDrawingState == kDrawingPluginGenericUI || fDrawingState == kDrawingPluginCustomUI) | |||
| carla_show_custom_ui(handle, 0, false); | |||
| carla_show_custom_ui(fPlugin->fCarlaHostHandle, 0, false); | |||
| fPluginHostWindow.hide(); | |||
| } | |||
| @@ -194,6 +193,11 @@ protected: | |||
| repaint(); | |||
| break; | |||
| case kDrawingPluginPendingFromInit: | |||
| showPluginUI(fPlugin->fCarlaHostHandle); | |||
| startThread(); | |||
| break; | |||
| case kDrawingPluginCustomUI: | |||
| fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle); | |||
| fPluginHostWindow.idle(); | |||
| @@ -254,6 +258,9 @@ protected: | |||
| switch (fDrawingState) | |||
| { | |||
| case kDrawingInit: | |||
| case kDrawingLoading: | |||
| case kDrawingPluginPendingFromInit: | |||
| drawLoading(); | |||
| break; | |||
| case kDrawingPluginList: | |||
| drawPluginList(); | |||
| @@ -261,9 +268,6 @@ protected: | |||
| case kDrawingError: | |||
| // TODO display error message | |||
| break; | |||
| case kDrawingLoading: | |||
| drawLoading(); | |||
| break; | |||
| case kDrawingPluginGenericUI: | |||
| drawGenericUI(); | |||
| // fall-through | |||
| @@ -282,7 +286,7 @@ protected: | |||
| { | |||
| if (ImGui::Button("Pick Another...")) | |||
| { | |||
| hidePluginUI(fPlugin->fCarlaHostHandle); | |||
| hidePluginUI(); | |||
| fDrawingState = kDrawingPluginList; | |||
| const double scaleFactor = getScaleFactor(); | |||
| @@ -362,7 +366,7 @@ protected: | |||
| { | |||
| if (pluginIsRunning) | |||
| { | |||
| hidePluginUI(handle); | |||
| hidePluginUI(); | |||
| carla_replace_plugin(handle, 0); | |||
| } | |||
| @@ -450,14 +454,16 @@ 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, float) override | |||
| { | |||
| } | |||
| void stateChanged(const char* const key, const char* const) override | |||
| { | |||
| if (std::strcmp(key, "project") == 0) | |||
| hidePluginUI(); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------- | |||
| private: | |||
| @@ -67,6 +67,8 @@ BUILD_CXX_FLAGS += -I../../dpf-widgets/opengl | |||
| BUILD_CXX_FLAGS += -DREAL_BUILD | |||
| BUILD_CXX_FLAGS += -I../../carla/source/backend | |||
| BUILD_CXX_FLAGS += -I../../carla/source/includes | |||
| BUILD_CXX_FLAGS += -I../../carla/source/modules | |||
| BUILD_CXX_FLAGS += -I../../carla/source/utils | |||
| LINK_FLAGS += $(STATIC_CARLA_PLUGIN_LIBS) | |||
| @@ -3,5 +3,7 @@ | |||
| ../../dpf/distrho/ | |||
| ../../dpf-widgets/generic | |||
| ../../dpf-widgets/opengl | |||
| /usr/include/carla | |||
| /usr/include/carla/includes | |||
| ../../carla/source/backend | |||
| ../../carla/source/includes | |||
| ../../carla/source/modules | |||
| ../../carla/source/utils | |||
| @@ -27,6 +27,8 @@ | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 2 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 0 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | |||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
| @@ -27,6 +27,8 @@ | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 0 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 0 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 | |||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
| @@ -27,6 +27,8 @@ | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 0 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | |||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||