@@ -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. | 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. | 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. | 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. | 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/distrho/ | ||||
../../dpf-widgets/generic | ../../dpf-widgets/generic | ||||
../../dpf-widgets/opengl | ../../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 "CarlaNativePlugin.h" | ||||
#include "CarlaEngine.hpp" | |||||
#include "water/streams/MemoryOutputStream.h" | |||||
#include "water/xml/XmlDocument.h" | |||||
#include "DistrhoPlugin.hpp" | #include "DistrhoPlugin.hpp" | ||||
@@ -52,11 +55,13 @@ public: | |||||
#endif | #endif | ||||
mutable NativeTimeInfo fCarlaTimeInfo; | mutable NativeTimeInfo fCarlaTimeInfo; | ||||
mutable water::MemoryOutputStream fLastProjectState; | |||||
uint32_t fLastLatencyValue; | |||||
void* fUI; | void* fUI; | ||||
IldaeilPlugin() | IldaeilPlugin() | ||||
: Plugin(0, 0, 0), | |||||
: Plugin(0, 0, 1), | |||||
fCarlaPluginDescriptor(nullptr), | fCarlaPluginDescriptor(nullptr), | ||||
fCarlaPluginHandle(nullptr), | fCarlaPluginHandle(nullptr), | ||||
fCarlaHostHandle(nullptr), | fCarlaHostHandle(nullptr), | ||||
@@ -65,6 +70,7 @@ public: | |||||
fMidiEventCount(0), | fMidiEventCount(0), | ||||
fDummyBuffer(nullptr), | fDummyBuffer(nullptr), | ||||
#endif | #endif | ||||
fLastLatencyValue(0), | |||||
fUI(nullptr) | fUI(nullptr) | ||||
{ | { | ||||
fCarlaPluginDescriptor = carla_get_native_rack_plugin(); | fCarlaPluginDescriptor = carla_get_native_rack_plugin(); | ||||
@@ -246,16 +252,72 @@ protected: | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* Init */ | * 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 */ | * 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 */ | * 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 | void activate() override | ||||
{ | { | ||||
if (fCarlaPluginHandle != nullptr) | if (fCarlaPluginHandle != nullptr) | ||||
fCarlaPluginDescriptor->activate(fCarlaPluginHandle); | fCarlaPluginDescriptor->activate(fCarlaPluginHandle); | ||||
checkLatencyChanged(); | |||||
} | } | ||||
void deactivate() override | void deactivate() override | ||||
@@ -305,6 +367,8 @@ protected: | |||||
#else | #else | ||||
fCarlaPluginDescriptor->process(fCarlaPluginHandle, (float**)inputs, outputs, frames, nullptr, 0); | fCarlaPluginDescriptor->process(fCarlaPluginHandle, (float**)inputs, outputs, frames, nullptr, 0); | ||||
#endif | #endif | ||||
checkLatencyChanged(); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -59,7 +59,8 @@ class IldaeilUI : public UI, | |||||
kDrawingLoading, | kDrawingLoading, | ||||
kDrawingPluginList, | kDrawingPluginList, | ||||
kDrawingPluginCustomUI, | kDrawingPluginCustomUI, | ||||
kDrawingPluginGenericUI | |||||
kDrawingPluginGenericUI, | |||||
kDrawingPluginPendingFromInit | |||||
} fDrawingState; | } fDrawingState; | ||||
struct PluginInfoCache { | struct PluginInfoCache { | ||||
@@ -130,22 +131,16 @@ public: | |||||
carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_UI_SCALE, getScaleFactor()*1000, nullptr); | carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_UI_SCALE, getScaleFactor()*1000, nullptr); | ||||
if (carla_get_current_plugin_count(handle) != 0) | if (carla_get_current_plugin_count(handle) != 0) | ||||
{ | |||||
showPluginUI(handle); | |||||
startThread(); | |||||
return; | |||||
} | |||||
fDrawingState = kDrawingPluginPendingFromInit; | |||||
} | } | ||||
~IldaeilUI() override | ~IldaeilUI() override | ||||
{ | { | ||||
if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr) | |||||
return; | |||||
stopThread(-1); | |||||
if (isThreadRunning()) | |||||
stopThread(-1); | |||||
// fPlugin->fUI = nullptr; | // fPlugin->fUI = nullptr; | ||||
hidePluginUI(fPlugin->fCarlaHostHandle); | |||||
hidePluginUI(); | |||||
delete[] fPlugins; | delete[] fPlugins; | ||||
} | } | ||||
@@ -161,19 +156,23 @@ public: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
fDrawingState = kDrawingPluginGenericUI; | |||||
// TODO query parameter information and store it | // TODO query parameter information and store it | ||||
const double scaleFactor = getScaleFactor(); | const double scaleFactor = getScaleFactor(); | ||||
setSize(kGenericWidth * scaleFactor, (kGenericHeight + kExtraHeight) * scaleFactor); | setSize(kGenericWidth * scaleFactor, (kGenericHeight + kExtraHeight) * scaleFactor); | ||||
fDrawingState = kDrawingPluginGenericUI; | |||||
} | } | ||||
repaint(); | repaint(); | ||||
} | } | ||||
void hidePluginUI(const CarlaHostHandle handle) | |||||
void hidePluginUI() | |||||
{ | { | ||||
if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr) | |||||
return; | |||||
if (fDrawingState == kDrawingPluginGenericUI || fDrawingState == kDrawingPluginCustomUI) | if (fDrawingState == kDrawingPluginGenericUI || fDrawingState == kDrawingPluginCustomUI) | ||||
carla_show_custom_ui(handle, 0, false); | |||||
carla_show_custom_ui(fPlugin->fCarlaHostHandle, 0, false); | |||||
fPluginHostWindow.hide(); | fPluginHostWindow.hide(); | ||||
} | } | ||||
@@ -194,6 +193,11 @@ protected: | |||||
repaint(); | repaint(); | ||||
break; | break; | ||||
case kDrawingPluginPendingFromInit: | |||||
showPluginUI(fPlugin->fCarlaHostHandle); | |||||
startThread(); | |||||
break; | |||||
case kDrawingPluginCustomUI: | case kDrawingPluginCustomUI: | ||||
fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle); | fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle); | ||||
fPluginHostWindow.idle(); | fPluginHostWindow.idle(); | ||||
@@ -254,6 +258,9 @@ protected: | |||||
switch (fDrawingState) | switch (fDrawingState) | ||||
{ | { | ||||
case kDrawingInit: | case kDrawingInit: | ||||
case kDrawingLoading: | |||||
case kDrawingPluginPendingFromInit: | |||||
drawLoading(); | |||||
break; | break; | ||||
case kDrawingPluginList: | case kDrawingPluginList: | ||||
drawPluginList(); | drawPluginList(); | ||||
@@ -261,9 +268,6 @@ protected: | |||||
case kDrawingError: | case kDrawingError: | ||||
// TODO display error message | // TODO display error message | ||||
break; | break; | ||||
case kDrawingLoading: | |||||
drawLoading(); | |||||
break; | |||||
case kDrawingPluginGenericUI: | case kDrawingPluginGenericUI: | ||||
drawGenericUI(); | drawGenericUI(); | ||||
// fall-through | // fall-through | ||||
@@ -282,7 +286,7 @@ protected: | |||||
{ | { | ||||
if (ImGui::Button("Pick Another...")) | if (ImGui::Button("Pick Another...")) | ||||
{ | { | ||||
hidePluginUI(fPlugin->fCarlaHostHandle); | |||||
hidePluginUI(); | |||||
fDrawingState = kDrawingPluginList; | fDrawingState = kDrawingPluginList; | ||||
const double scaleFactor = getScaleFactor(); | const double scaleFactor = getScaleFactor(); | ||||
@@ -362,7 +366,7 @@ protected: | |||||
{ | { | ||||
if (pluginIsRunning) | if (pluginIsRunning) | ||||
{ | { | ||||
hidePluginUI(handle); | |||||
hidePluginUI(); | |||||
carla_replace_plugin(handle, 0); | carla_replace_plugin(handle, 0); | ||||
} | } | ||||
@@ -450,14 +454,16 @@ protected: | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* DSP/Plugin Callbacks */ | * 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 parameterChanged(uint32_t, float) override | ||||
{ | { | ||||
} | } | ||||
void stateChanged(const char* const key, const char* const) override | |||||
{ | |||||
if (std::strcmp(key, "project") == 0) | |||||
hidePluginUI(); | |||||
} | |||||
// ------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------- | ||||
private: | private: | ||||
@@ -67,6 +67,8 @@ BUILD_CXX_FLAGS += -I../../dpf-widgets/opengl | |||||
BUILD_CXX_FLAGS += -DREAL_BUILD | BUILD_CXX_FLAGS += -DREAL_BUILD | ||||
BUILD_CXX_FLAGS += -I../../carla/source/backend | BUILD_CXX_FLAGS += -I../../carla/source/backend | ||||
BUILD_CXX_FLAGS += -I../../carla/source/includes | 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) | LINK_FLAGS += $(STATIC_CARLA_PLUGIN_LIBS) | ||||
@@ -3,5 +3,7 @@ | |||||
../../dpf/distrho/ | ../../dpf/distrho/ | ||||
../../dpf-widgets/generic | ../../dpf-widgets/generic | ||||
../../dpf-widgets/opengl | ../../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_INPUTS 2 | ||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | ||||
#define DISTRHO_PLUGIN_WANT_LATENCY 1 | #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_INPUT 0 | ||||
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | ||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | ||||
@@ -27,6 +27,8 @@ | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 0 | #define DISTRHO_PLUGIN_NUM_INPUTS 0 | ||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 0 | #define DISTRHO_PLUGIN_NUM_OUTPUTS 0 | ||||
#define DISTRHO_PLUGIN_WANT_LATENCY 1 | #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_INPUT 1 | ||||
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 | #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 | ||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | ||||
@@ -27,6 +27,8 @@ | |||||
#define DISTRHO_PLUGIN_NUM_INPUTS 0 | #define DISTRHO_PLUGIN_NUM_INPUTS 0 | ||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | #define DISTRHO_PLUGIN_NUM_OUTPUTS 2 | ||||
#define DISTRHO_PLUGIN_WANT_LATENCY 1 | #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_INPUT 1 | ||||
#define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | ||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | ||||