From 6f595ea7227fe8597ea4fc45366bb4752868400e Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 30 Dec 2014 13:03:19 +0000 Subject: [PATCH] Experimental code for lv2-idle via worker --- source/plugin/carla-lv2-export.cpp | 32 ++++----- source/plugin/carla-lv2.cpp | 107 ++++++++++++++++++++++++----- source/plugin/carla-vst.cpp | 9 +-- 3 files changed, 105 insertions(+), 43 deletions(-) diff --git a/source/plugin/carla-lv2-export.cpp b/source/plugin/carla-lv2-export.cpp index d297c0c92..5f3485d7d 100644 --- a/source/plugin/carla-lv2-export.cpp +++ b/source/plugin/carla-lv2-export.cpp @@ -31,6 +31,7 @@ #include "lv2/ui.h" #include "lv2/units.h" #include "lv2/urid.h" +#include "lv2/worker.h" #include "lv2/lv2_external_ui.h" #include "lv2/lv2_programs.h" @@ -246,14 +247,19 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) // ------------------------------------------------------------------- // Features + // optional if (pluginDesc->hints & NATIVE_PLUGIN_IS_RTSAFE) text += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ;\n\n"; + // required text += " lv2:requiredFeature <" LV2_BUF_SIZE__boundedBlockLength "> ,\n"; if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) text += " <" LV2_BUF_SIZE__fixedBlockLength "> ,\n"; + if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_DSP_IDLE) + text += " <" LV2_WORKER__schedule "> ,\n"; + text += " <" LV2_OPTIONS__options "> ,\n"; text += " <" LV2_URID__map "> ;\n"; text += "\n"; @@ -261,28 +267,16 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) // ------------------------------------------------------------------- // Extensions - text += " lv2:extensionData <" LV2_OPTIONS__interface ">"; + text += " lv2:extensionData <" LV2_OPTIONS__interface "> ;"; if (pluginDesc->hints & NATIVE_PLUGIN_USES_STATE) - { - text += " ,\n"; - text += " <" LV2_STATE__interface ">"; + text += " lv2:extensionData <" LV2_STATE__interface "> ;"; - if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) - { - text += " ,\n"; - text += " <" LV2_PROGRAMS__Interface "> ;\n"; - } - else - text += " ;\n"; - } - else if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) - { - text += " ,\n"; - text += " <" LV2_PROGRAMS__Interface "> ;\n"; - } - else - text += " ;\n"; + if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_DSP_IDLE) + text += " lv2:extensionData <" LV2_WORKER__interface "> ;"; + + if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) + text += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n"; text += "\n"; diff --git a/source/plugin/carla-lv2.cpp b/source/plugin/carla-lv2.cpp index e5f2dccda..00ce57268 100644 --- a/source/plugin/carla-lv2.cpp +++ b/source/plugin/carla-lv2.cpp @@ -46,7 +46,7 @@ typedef struct _LV2_External_UI_Widget_Compat { void (*show)(struct _LV2_External_UI_Widget_Compat*); void (*hide)(struct _LV2_External_UI_Widget_Compat*); - _LV2_External_UI_Widget_Compat() + _LV2_External_UI_Widget_Compat() noexcept : run(nullptr), show(nullptr), hide(nullptr) {} } LV2_External_UI_Widget_Compat; @@ -83,10 +83,12 @@ public: fMidiEventCount(0), fTimeInfo(), fLastTimeSpeed(0.0), + fIsFirstRun(true), fIsProcessing(false), fBufferSize(0), fSampleRate(sampleRate), fUridMap(nullptr), + fWorker(nullptr), fURIs(), fUI(), fPorts(), @@ -121,9 +123,10 @@ public: fHost.ui_save_file = host_ui_save_file; fHost.dispatcher = host_dispatcher; - const LV2_Options_Option* options = nullptr; - const LV2_URID_Map* uridMap = nullptr; - const LV2_URID_Unmap* uridUnmap = nullptr; + const LV2_Options_Option* options = nullptr; + const LV2_URID_Map* uridMap = nullptr; + const LV2_URID_Unmap* uridUnmap = nullptr; + const LV2_Worker_Schedule* worker = nullptr; for (int i=0; features[i] != nullptr; ++i) { @@ -133,11 +136,18 @@ public: uridMap = (const LV2_URID_Map*)features[i]->data; else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0) uridUnmap = (const LV2_URID_Unmap*)features[i]->data; + else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0) + worker = (const LV2_Worker_Schedule*)features[i]->data; } if (options == nullptr || uridMap == nullptr) { - carla_stderr("Host doesn't provides option or urid-map features"); + carla_stderr("Host doesn't provide option or urid-map features"); + return; + } + if (worker == nullptr && (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_DSP_IDLE) != 0) + { + carla_stderr("Host doesn't provide worker feature"); return; } @@ -165,6 +175,7 @@ public: } fUridMap = uridMap; + fWorker = worker; if (fDescriptor->midiIns > 0) fUI.portOffset += desc->midiIns; @@ -190,6 +201,11 @@ public: bool init() { + if (fUI.portOffset == 0) + { + // host is missing features + return false; + } if (fDescriptor->instantiate == nullptr || fDescriptor->process == nullptr) { carla_stderr("Plugin is missing something..."); @@ -229,6 +245,8 @@ public: fDescriptor->activate(fHandle); carla_zeroStruct(fTimeInfo); + + fIsFirstRun = true; } void lv2_deactivate() @@ -525,6 +543,17 @@ public: // TODO - midi out updateParameterOutputs(); + + if (! fIsFirstRun) + return; + + fIsFirstRun = false; + + if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_DSP_IDLE) + { + CARLA_SAFE_ASSERT_RETURN(fWorker != nullptr,); + fWorker->schedule_work(fWorker->handle, 5, "idle"); + } } // ------------------------------------------------------------------- @@ -629,7 +658,7 @@ public: size_t size = 0; uint32_t type = 0; - const void* data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags); + const void* const data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags); if (size == 0) return LV2_STATE_ERR_UNKNOWN; @@ -645,6 +674,38 @@ public: return LV2_STATE_SUCCESS; } + // This is called from the LV2 worker thread (non-RT), as requested from the "run()" function. + LV2_Worker_Status lv2_work(const LV2_Worker_Respond_Function respond, const LV2_Worker_Respond_Handle handle, const uint32_t size, const void* const data) + { + CARLA_SAFE_ASSERT_RETURN(size == 5, LV2_WORKER_ERR_UNKNOWN); + CARLA_SAFE_ASSERT_RETURN(data != nullptr, LV2_WORKER_ERR_UNKNOWN); + CARLA_SAFE_ASSERT_RETURN(respond != nullptr, LV2_WORKER_ERR_UNKNOWN); + + const char* const msg((const char*)data); + CARLA_SAFE_ASSERT_RETURN(std::strcmp(msg, "idle") == 0, LV2_WORKER_ERR_UNKNOWN); + + if (fDescriptor->idle != nullptr) + fDescriptor->idle(fHandle); + + respond(handle, 6, "idled"); + + return LV2_WORKER_SUCCESS; + } + + // This is called from the LV2 process thread (RT) + LV2_Worker_Status lv2_work_response(const uint32_t size, const void* const body) + { + CARLA_SAFE_ASSERT_RETURN(size == 6, LV2_WORKER_ERR_UNKNOWN); + CARLA_SAFE_ASSERT_RETURN(body != nullptr, LV2_WORKER_ERR_UNKNOWN); + + const char* const msg((const char*)body); + CARLA_SAFE_ASSERT_RETURN(std::strcmp(msg, "idled") == 0, LV2_WORKER_ERR_UNKNOWN); + + fWorker->schedule_work(fWorker->handle, 5, "idle"); + + return LV2_WORKER_SUCCESS; + } + // ------------------------------------------------------------------- void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, LV2UI_Widget* widget, const LV2_Feature* const* features) @@ -714,6 +775,9 @@ public: void lv2ui_cleanup() { + if (fUI.isVisible) + handleUiHide(); + fUI.host = nullptr; fUI.writeFunction = nullptr; fUI.controller = nullptr; @@ -723,14 +787,6 @@ public: delete[] fHost.uiName; fHost.uiName = nullptr; } - - if (! fUI.isVisible) - return; - - if (fDescriptor->ui_show != nullptr) - fDescriptor->ui_show(fHandle, false); - - fUI.isVisible = false; } // ------------------------------------------------------------------- @@ -752,9 +808,7 @@ public: if (! fUI.isVisible) return 1; - if (fDescriptor->ui_idle != nullptr) - fDescriptor->ui_idle(fHandle); - + handleUiRun(); return 0; } @@ -933,13 +987,15 @@ private: NativeTimeInfo fTimeInfo; double fLastTimeSpeed; + bool fIsFirstRun; // first run after activate bool fIsProcessing; // Lv2 host data uint32_t fBufferSize; double fSampleRate; - const LV2_URID_Map* fUridMap; + const LV2_URID_Map* fUridMap; + const LV2_Worker_Schedule* fWorker; struct URIDs { LV2_URID atomBlank; @@ -1411,6 +1467,18 @@ static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Func return instancePtr->lv2_restore(retrieve, handle, flags, features); } +static LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle, uint32_t size, const void* data) +{ + carla_debug("lv2_work(%p, %p, %p, %i, %p)", instance, respond, handle, size, data); + return instancePtr->lv2_work(respond, handle, size, data); +} + +static LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const void* body) +{ + carla_debug("lv2_work_response(%p, %i, %p)", instance, size, body); + return instancePtr->lv2_work_response(size, body); +} + static const void* lv2_extension_data(const char* uri) { carla_debug("lv2_extension_data(\"%s\")", uri); @@ -1418,6 +1486,7 @@ static const void* lv2_extension_data(const char* uri) static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program }; static const LV2_State_Interface state = { lv2_save, lv2_restore }; + static const LV2_Worker_Interface worker = { lv2_work, lv2_work_response, nullptr }; if (std::strcmp(uri, LV2_OPTIONS__interface) == 0) return &options; @@ -1425,6 +1494,8 @@ static const void* lv2_extension_data(const char* uri) return &programs; if (std::strcmp(uri, LV2_STATE__interface) == 0) return &state; + if (std::strcmp(uri, LV2_WORKER__interface) == 0) + return &worker; return nullptr; } diff --git a/source/plugin/carla-vst.cpp b/source/plugin/carla-vst.cpp index 09aa22333..7ae5bd924 100644 --- a/source/plugin/carla-vst.cpp +++ b/source/plugin/carla-vst.cpp @@ -44,6 +44,7 @@ namespace juce { #define effGetChunk 23 #define effSetChunk 24 #define effGetPlugCategory 35 +#define effIdle 53 #define kPlugCategEffect 1 #define kPlugCategSynth 2 #define kVstVersion 2400 @@ -305,10 +306,8 @@ public: if (! fIsActive) { // host has not activated the plugin yet, nasty! + vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); fIsActive = true; - - if (fDescriptor->activate != nullptr) - fDescriptor->activate(fHandle); } if (const VstEvents* const events = (const VstEvents*)ptr) @@ -376,10 +375,8 @@ public: if (! fIsActive) { // host has not activated the plugin yet, nasty! + vst_dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); fIsActive = true; - - if (fDescriptor->activate != nullptr) - fDescriptor->activate(fHandle); } static const int kWantVstTimeFlags(kVstTransportPlaying|kVstPpqPosValid|kVstTempoValid|kVstTimeSigValid);