From 9abb529dec9d29cef4f3e00b7e21f4fd72fd0a77 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 8 Oct 2022 17:49:34 +0100 Subject: [PATCH] Implement CLAP state Signed-off-by: falkTX --- source/backend/plugin/CarlaPlugin.cpp | 33 ++++--- source/backend/plugin/CarlaPluginCLAP.cpp | 103 +++++++++++++++------- source/utils/CarlaClapUtils.hpp | 67 +++++++++++++- source/utils/CarlaStateUtils.cpp | 13 ++- 4 files changed, 170 insertions(+), 46 deletions(-) diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index 58eae8963..60c84b30c 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -521,7 +521,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) prepareForSave(true); } - const PluginType pluginType(getType()); + const PluginType pluginType = getType(); char strBuf[STR_MAX+1]; carla_zeroChars(strBuf, STR_MAX+1); @@ -567,7 +567,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) if (pData->options & PLUGIN_OPTION_USE_CHUNKS) { void* data = nullptr; - const std::size_t dataSize(getChunkData(&data)); + const std::size_t dataSize = getChunkData(&data); if (data != nullptr && dataSize > 0) { @@ -601,7 +601,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) // --------------------------------------------------------------- // Parameters - const float sampleRate(static_cast(pData->engine->getSampleRate())); + const float sampleRate = static_cast(pData->engine->getSampleRate()); for (uint32_t i=0; i < pData->param.count; ++i) { @@ -683,8 +683,8 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) { - const bool usesMultiProgs(pData->hints & PLUGIN_USES_MULTI_PROGS); - const PluginType pluginType(getType()); + const bool usesMultiProgs = pData->hints & PLUGIN_USES_MULTI_PROGS; + const PluginType pluginType = getType(); char strBuf[STR_MAX+1]; carla_zeroChars(strBuf, STR_MAX+1); @@ -753,7 +753,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) LinkedList paramSymbols; - if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2) + if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2 || pluginType == PLUGIN_CLAP) { for (uint32_t i=0; i < pData->param.count; ++i) { @@ -771,7 +771,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) // --------------------------------------------------------------- // Part 4b - set parameter values (carefully) - const float sampleRate(static_cast(pData->engine->getSampleRate())); + const float sampleRate = static_cast(pData->engine->getSampleRate()); for (CarlaStateSave::ParameterItenerator it = stateSave.parameters.begin2(); it.valid(); it.next()) { @@ -805,7 +805,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) index = stateParameter->index; } } - else if (pluginType == PLUGIN_LV2) + else if (pluginType == PLUGIN_LV2 || pluginType == PLUGIN_CLAP) { // Symbol only if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') @@ -823,12 +823,21 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) } } if (index == -1) - carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'", - stateParameter->symbol, pData->name); + { + if (pluginType == PLUGIN_LV2) + carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'", + stateParameter->symbol, pData->name); + else + carla_stderr("Failed to find CLAP parameter id '%s' for '%s'", + stateParameter->symbol, pData->name); + } } else { - carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name); + if (pluginType == PLUGIN_LV2) + carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name); + else + carla_stderr("CLAP Plugin parameter '%s' has no id", stateParameter->name); } } else @@ -941,7 +950,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) // --------------------------------------------------------------- // Part 6 - set internal stuff - const uint availOptions(getOptionsAvailable()); + const uint availOptions = getOptionsAvailable(); for (uint i=0; i<10; ++i) // FIXME - get this value somehow... { diff --git a/source/backend/plugin/CarlaPluginCLAP.cpp b/source/backend/plugin/CarlaPluginCLAP.cpp index 1152ad3e8..3cb85dbce 100644 --- a/source/backend/plugin/CarlaPluginCLAP.cpp +++ b/source/backend/plugin/CarlaPluginCLAP.cpp @@ -132,6 +132,7 @@ struct carla_clap_host : clap_host_t { virtual void clapRequestRestart() = 0; virtual void clapRequestProcess() = 0; virtual void clapRequestCallback() = 0; + virtual void clapMarkDirty() = 0; #ifdef CLAP_WINDOW_API_NATIVE // gui virtual void clapGuiResizeHintsChanged() = 0; @@ -147,6 +148,7 @@ struct carla_clap_host : clap_host_t { Callbacks* const hostCallbacks; + clap_host_state_t state; #ifdef CLAP_WINDOW_API_NATIVE clap_host_gui_t gui; clap_host_timer_support_t timer; @@ -167,12 +169,15 @@ struct carla_clap_host : clap_host_t { request_process = carla_request_process; request_callback = carla_request_callback; + state.mark_dirty = carla_mark_dirty; + #ifdef CLAP_WINDOW_API_NATIVE gui.resize_hints_changed = carla_resize_hints_changed; gui.request_resize = carla_request_resize; gui.request_show = carla_request_show; gui.request_hide = carla_request_hide; gui.closed = carla_closed; + timer.register_timer = carla_register_timer; timer.unregister_timer = carla_unregister_timer; #endif @@ -213,6 +218,11 @@ struct carla_clap_host : clap_host_t { static_cast(host->host_data)->hostCallbacks->clapRequestCallback(); } + static void carla_mark_dirty(const clap_host_t* const host) + { + static_cast(host->host_data)->hostCallbacks->clapMarkDirty(); + } + #ifdef CLAP_WINDOW_API_NATIVE static void carla_resize_hints_changed(const clap_host_t* const host) { @@ -571,10 +581,11 @@ public: fInputAudioBuffers(), fOutputAudioBuffers(), fInputEvents(), - fOutputEvents() + fOutputEvents(), #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - , fAudioOutBuffers(nullptr) + fAudioOutBuffers(nullptr), #endif + fLastChunk(nullptr) { carla_debug("CarlaPluginCLAP::CarlaPluginCLAP(%p, %i)", engine, id); } @@ -607,6 +618,12 @@ public: fPlugin = nullptr; } + if (fLastChunk != nullptr) + { + std::free(fLastChunk); + fLastChunk = nullptr; + } + clearBuffers(); if (fPluginEntry != nullptr) @@ -692,11 +709,19 @@ public: CARLA_SAFE_ASSERT_RETURN(fExtensions.state != nullptr, 0); CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0); - *dataPtr = nullptr; - - // TODO + std::free(fLastChunk); - return 0; + clap_ostream_impl stream; + if (fExtensions.state->save(fPlugin, &stream)) + { + *dataPtr = fLastChunk = stream.buffer; + return stream.size; + } + else + { + *dataPtr = fLastChunk = nullptr; + return 0; + } } // ------------------------------------------------------------------- @@ -877,9 +902,9 @@ public: CARLA_SAFE_ASSERT_RETURN(data != nullptr,); CARLA_SAFE_ASSERT_RETURN(dataSize > 0,); - // TODO - - pData->updateParameterValues(this, true, true, false); + const clap_istream_impl stream(data, dataSize); + if (fExtensions.state->load(fPlugin, &stream)) + pData->updateParameterValues(this, true, true, false); } // ------------------------------------------------------------------- @@ -1048,7 +1073,10 @@ public: HostTimerDetails& timer(it.getValue(kTimerFallbackNC)); if (currentTimeInMs > timer.lastCallTimeInMs + timer.periodInMs) + { + timer.lastCallTimeInMs = currentTimeInMs; fExtensions.timer->on_timer(fPlugin, timer.clapId); + } } CarlaPlugin::uiIdle(); @@ -1363,7 +1391,7 @@ public: continue; pData->param.data[j].index = j; - pData->param.data[j].rindex = paramInfo.id; + pData->param.data[j].rindex = static_cast(paramInfo.id); double min, max, def, step, stepSmall, stepLarge; @@ -2189,7 +2217,7 @@ public: case CLAP_EVENT_PARAM_VALUE: for (uint32_t j=0; jparam.count; ++j) { - if (pData->param.data[j].rindex != ev.param.param_id) + if (pData->param.data[j].rindex != static_cast(ev.param.param_id)) continue; pData->postponeParameterChangeRtEvent(true, static_cast(j), ev.param.value); break; @@ -2328,6 +2356,12 @@ protected: // ------------------------------------------------------------------- + void clapMarkDirty() override + { + } + + // ------------------------------------------------------------------- + #ifdef CLAP_WINDOW_API_NATIVE void clapGuiResizeHintsChanged() override { @@ -2431,12 +2465,6 @@ public: return false; } - if (id == nullptr || id[0] == '\0') - { - pData->engine->setLastError("null label/id"); - return false; - } - // --------------------------------------------------------------- const clap_plugin_entry_t* entry; @@ -2512,16 +2540,36 @@ public: if (const uint32_t count = factory->get_plugin_count(factory)) { - for (uint32_t i=0; iget_plugin_descriptor(factory, i); - CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr); - CARLA_SAFE_ASSERT_CONTINUE(desc->id != nullptr); + fPluginDescriptor = factory->get_plugin_descriptor(factory, 0); - if (std::strcmp(desc->id, id) == 0) + if (fPluginDescriptor == nullptr) { - fPluginDescriptor = desc; - break; + pData->engine->setLastError("Plugin library does not contain a valid first plugin"); + return false; + } + } + else + { + for (uint32_t i=0; iget_plugin_descriptor(factory, i); + CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr); + CARLA_SAFE_ASSERT_CONTINUE(desc->id != nullptr); + + if (std::strcmp(desc->id, id) == 0) + { + fPluginDescriptor = desc; + break; + } + } + + if (fPluginDescriptor == nullptr) + { + pData->engine->setLastError("Plugin library does not contain the requested plugin"); + return false; } } } @@ -2531,12 +2579,6 @@ public: return false; } - if (fPluginDescriptor == nullptr) - { - pData->engine->setLastError("Plugin library does not contain the requested plugin"); - return false; - } - // --------------------------------------------------------------- fPlugin = factory->create_plugin(factory, &fHost, fPluginDescriptor->id); @@ -2679,6 +2721,7 @@ private: #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH float** fAudioOutBuffers; #endif + void* fLastChunk; #ifdef CARLA_OS_MAC BundleLoader fBundleLoader; diff --git a/source/utils/CarlaClapUtils.hpp b/source/utils/CarlaClapUtils.hpp index 426658b71..291542eb4 100644 --- a/source/utils/CarlaClapUtils.hpp +++ b/source/utils/CarlaClapUtils.hpp @@ -148,7 +148,6 @@ bool clapFeaturesContainInstrument(const char* const* const features) noexcept if (features == nullptr) return false; - // 1st pass for main categories for (uint32_t i=0; features[i] != nullptr; ++i) { if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_INSTRUMENT) == 0) @@ -160,6 +159,72 @@ bool clapFeaturesContainInstrument(const char* const* const features) noexcept // -------------------------------------------------------------------------------------------------------------------- +struct clap_istream_impl : clap_istream_t { + const void* buffer; + const uint64_t size; + uint64_t readPos; + + clap_istream_impl(const void* const buf, const uint64_t bufsize) noexcept + : buffer(buf), + size(bufsize), + readPos(0) + { + ctx = this; + read = read_impl; + } + + static int64_t read_impl(const clap_istream_t* const stream, void* const buffer, const uint64_t size) noexcept + { + clap_istream_impl* const self = static_cast(stream->ctx); + + if (const uint64_t bytesRead = std::min(self->size - self->readPos, size)) + { + std::memcpy(buffer, static_cast(self->buffer) + self->readPos, bytesRead); + self->readPos += bytesRead; + return bytesRead; + } + + return 0; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +struct clap_ostream_impl : clap_ostream_t { + void* buffer; + uint64_t size; + + clap_ostream_impl() noexcept + : buffer(nullptr), + size(0) + { + ctx = this; + write = write_impl; + } + + static int64_t write_impl(const clap_ostream* const stream, const void* const buffer, const uint64_t size) noexcept + { + CARLA_SAFE_ASSERT_RETURN(size != 0, 0); + + clap_ostream_impl* const self = static_cast(stream->ctx); + + void* const oldBuffer = self->buffer; + self->buffer = std::realloc(self->buffer, self->size + size); + + if (self->buffer == nullptr) + { + std::free(oldBuffer); + return -1; + } + + std::memcpy(static_cast(self->buffer) + self->size, buffer, size); + self->size += size; + return size; + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + CARLA_BACKEND_END_NAMESPACE #endif // CARLA_CLAP_UTILS_HPP_INCLUDED diff --git a/source/utils/CarlaStateUtils.cpp b/source/utils/CarlaStateUtils.cpp index 071662f2a..fed5481e9 100644 --- a/source/utils/CarlaStateUtils.cpp +++ b/source/utils/CarlaStateUtils.cpp @@ -429,7 +429,7 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) { stateParameter->name = xmlSafeStringCharDup(pText, false); } - else if (pTag == "Symbol") + else if (pTag == "Symbol" || pTag == "Identifier") { stateParameter->symbol = xmlSafeStringCharDup(pText, false); } @@ -559,6 +559,8 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const { + const PluginType pluginType = getPluginTypeFromString(type); + { MemoryOutputStream infoXml; @@ -566,7 +568,7 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const infoXml << " " << String(type != nullptr ? type : "") << "\n"; infoXml << " " << xmlSafeString(name, true) << "\n"; - switch (getPluginTypeFromString(type)) + switch (pluginType) { case PLUGIN_NONE: break; @@ -666,7 +668,12 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const parameterXml << " " << xmlSafeString(stateParameter->name, true) << "\n"; if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') - parameterXml << " " << xmlSafeString(stateParameter->symbol, true) << "\n"; + { + if (pluginType == PLUGIN_CLAP) + parameterXml << " " << xmlSafeString(stateParameter->symbol, true) << "\n"; + else + parameterXml << " " << xmlSafeString(stateParameter->symbol, true) << "\n"; + } #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH if (stateParameter->mappedControlIndex > CONTROL_INDEX_NONE && stateParameter->mappedControlIndex <= CONTROL_INDEX_MAX_ALLOWED)