Signed-off-by: falkTX <falktx@falktx.com>48-params
| @@ -74,11 +74,13 @@ endif | |||
| endif | |||
| ifeq ($(HEADLESS),true) | |||
| ifneq ($(STATIC_BUILD),true) | |||
| ifneq ($(shell $(PKG_CONFIG) --exists liblo && echo true),true) | |||
| $(error liblo dependency not installed/available) | |||
| endif | |||
| endif | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| @@ -201,6 +203,9 @@ plugins: deps | |||
| resources: | |||
| $(MAKE) resources -C plugins | |||
| loader-resources: | |||
| $(MAKE) loader-resources -C plugins | |||
| mini-plugins: deps | |||
| $(MAKE) mini -C plugins | |||
| @@ -211,10 +216,14 @@ ifneq ($(CROSS_COMPILING),true) | |||
| gen: cardinal resources dpf/utils/lv2_ttl_generator | |||
| @$(CURDIR)/dpf/utils/generate-ttl.sh | |||
| loader-gen: loader loader-resources dpf/utils/lv2_ttl_generator | |||
| @$(CURDIR)/dpf/utils/generate-ttl.sh | |||
| dpf/utils/lv2_ttl_generator: | |||
| $(MAKE) -C dpf/utils/lv2-ttl-generator | |||
| else | |||
| gen: | |||
| loader-gen: | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| @@ -253,6 +262,15 @@ vst3: carla deps dgl plugins resources | |||
| modgui: | |||
| $(MAKE) modgui -C src/CardinalMiniSep | |||
| ifeq ($(HEADLESS)$(STATIC_BUILD),truetrue) | |||
| loader: deps dgl plugins loader-gen | |||
| $(MAKE) loader -C src $(CARLA_EXTRA_ARGS) | |||
| @$(CURDIR)/dpf/utils/generate-ttl.sh | |||
| else | |||
| loader: | |||
| $(MAKE) loader HEADLESS=true STATIC_BUILD=true | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| # Packaging standalone for CI | |||
| @@ -46,22 +46,19 @@ class UI; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Base DGL classes | |||
| #ifndef DGL_BASE_HPP_INCLUDED | |||
| namespace CardinalDGL { | |||
| #ifndef DGL_BASE_HPP_INCLUDED | |||
| class TopLevelWidget; | |||
| template <class BaseWidget> class NanoBaseWidget; | |||
| typedef NanoBaseWidget<TopLevelWidget> NanoTopLevelWidget; | |||
| struct IdleCallback { | |||
| virtual ~IdleCallback() {} | |||
| virtual void idleCallback() = 0; | |||
| }; | |||
| } | |||
| #endif | |||
| #ifndef DGL_NANO_WIDGET_HPP_INCLUDED | |||
| template <class BaseWidget> class NanoBaseWidget; | |||
| typedef NanoBaseWidget<TopLevelWidget> NanoTopLevelWidget; | |||
| #endif | |||
| } | |||
| using CardinalDGL::IdleCallback; | |||
| @@ -71,9 +68,10 @@ using CardinalDGL::IdleCallback; | |||
| static constexpr const uint32_t kModuleParameterCount = 48; | |||
| enum CardinalVariant { | |||
| kCardinalVariantFX, | |||
| kCardinalVariantLoader, | |||
| kCardinalVariantMain, | |||
| kCardinalVariantMini, | |||
| kCardinalVariantFX, | |||
| kCardinalVariantNative, | |||
| kCardinalVariantSynth, | |||
| }; | |||
| @@ -255,7 +255,7 @@ PLUGIN_FILES += Cardinal/src/glBars.cpp | |||
| endif | |||
| endif | |||
| ifneq ($(MOD_BUILD),true) | |||
| ifneq ($(STATIC_BUILD),true) | |||
| PLUGIN_FILES += Cardinal/src/AudioFile.cpp | |||
| ifneq ($(WASM),true) | |||
| PLUGIN_FILES += Cardinal/src/Carla.cpp | |||
| @@ -1896,8 +1896,13 @@ VST3_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalSynth.vst3/Contents/Resource | |||
| endif | |||
| LOADER_RESOURCES = $(PLUGIN_LIST:%=../bin/CardinalLoader.lv2/resources/PluginManifests/%.json) | |||
| LOADER_RESOURCES += $(RESOURCE_FILES:%=../bin/CardinalLoader.lv2/resources/%) | |||
| resources: $(JACK_RESOURCES) $(LV2_RESOURCES) $(VST2_RESOURCES) $(VST3_RESOURCES) $(CLAP_RESOURCES) | |||
| loader-resources: $(LOADER_RESOURCES) | |||
| mini-resources: $(MINI_RESOURCES) | |||
| ../bin/Cardinal.lv2/resources/%: % | |||
| @@ -1908,6 +1913,10 @@ mini-resources: $(MINI_RESOURCES) | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| ../bin/CardinalLoader.lv2/resources/%: % | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| ../bin/CardinalMini.lv2/resources/%: % | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| @@ -1934,6 +1943,10 @@ ifeq ($(MOD_BUILD),true) | |||
| $(SILENT)python3 ../deps/svg2stub.py $< $@ | |||
| endif | |||
| ../bin/CardinalLoader.lv2/resources/%.svg: %.svg ../deps/svg2stub.py | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)python3 ../deps/svg2stub.py $< $@ | |||
| ../bin/Cardinal.lv2/resources/PluginManifests/%.json: %/plugin.json | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| @@ -1942,6 +1955,10 @@ endif | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| ../bin/CardinalLoader.lv2/resources/PluginManifests/%.json: %/plugin.json | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| ../bin/CardinalMini.lv2/resources/PluginManifests/%.json: %/plugin.json | |||
| -@mkdir -p "$(shell dirname $@)" | |||
| $(SILENT)ln -sf $(abspath $<) $@ | |||
| @@ -1164,12 +1164,12 @@ static void initStatic__Cardinal() | |||
| #else | |||
| spl.removeModule("glBars"); | |||
| #endif | |||
| #ifndef __MOD_DEVICES__ | |||
| #ifndef STATIC_BUILD | |||
| p->addModel(modelAudioFile); | |||
| #else | |||
| spl.removeModule("AudioFile"); | |||
| #endif | |||
| #if !(defined(DISTRHO_OS_WASM) || defined(__MOD_DEVICES__)) | |||
| #if !(defined(DISTRHO_OS_WASM) || defined(STATIC_BUILD)) | |||
| p->addModel(modelCarla); | |||
| p->addModel(modelIldaeil); | |||
| #else | |||
| @@ -2601,7 +2601,7 @@ static void initStatic__JW() | |||
| p->addModel(modelCoolBreeze); | |||
| p->addModel(modelPete); | |||
| p->addModel(modelTimer); | |||
| #ifndef __MOD_DEVICES__ | |||
| #ifndef STATIC_BUILD | |||
| p->addModel(modelStr1ker); | |||
| #else | |||
| spl.removeModule("Str1ker"); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -18,9 +18,10 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_LOADER 0 | |||
| #define CARDINAL_VARIANT_MAIN 1 | |||
| #define CARDINAL_VARIANT_MINI 0 | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_NATIVE 0 | |||
| #define CARDINAL_VARIANT_SYNTH 0 | |||
| @@ -36,7 +36,7 @@ | |||
| # error wrong build | |||
| #endif | |||
| #if (defined(STATIC_BUILD) && !defined(__MOD_DEVICES__)) || CARDINAL_VARIANT_MINI | |||
| #if (defined(STATIC_BUILD) && !defined(__MOD_DEVICES__)) || CARDINAL_VARIANT_LOADER || CARDINAL_VARIANT_MINI | |||
| # undef CARDINAL_INIT_OSC_THREAD | |||
| #endif | |||
| @@ -70,6 +70,8 @@ | |||
| #if CARDINAL_VARIANT_FX | |||
| # define CARDINAL_VARIANT_NAME "fx" | |||
| #elif CARDINAL_VARIANT_LOADER | |||
| # define CARDINAL_VARIANT_NAME "loader" | |||
| #elif CARDINAL_VARIANT_MINI | |||
| # define CARDINAL_VARIANT_NAME "mini" | |||
| #elif CARDINAL_VARIANT_NATIVE | |||
| @@ -128,12 +130,14 @@ CardinalPluginContext::CardinalPluginContext(Plugin* const p) | |||
| : bufferSize(p != nullptr ? p->getBufferSize() : 0), | |||
| processCounter(0), | |||
| sampleRate(p != nullptr ? p->getSampleRate() : 0.0), | |||
| #if CARDINAL_VARIANT_MAIN | |||
| #if CARDINAL_VARIANT_FX | |||
| variant(kCardinalVariantFX), | |||
| #elif CARDINAL_VARIANT_LOADER | |||
| variant(kCardinalVariantLoader), | |||
| #elif CARDINAL_VARIANT_MAIN | |||
| variant(kCardinalVariantMain), | |||
| #elif CARDINAL_VARIANT_MINI | |||
| variant(kCardinalVariantMini), | |||
| #elif CARDINAL_VARIANT_FX | |||
| variant(kCardinalVariantFX), | |||
| #elif CARDINAL_VARIANT_NATIVE | |||
| variant(kCardinalVariantNative), | |||
| #elif CARDINAL_VARIANT_SYNTH | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -18,9 +18,10 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 1 | |||
| #define CARDINAL_VARIANT_LOADER 0 | |||
| #define CARDINAL_VARIANT_MAIN 0 | |||
| #define CARDINAL_VARIANT_MINI 0 | |||
| #define CARDINAL_VARIANT_FX 1 | |||
| #define CARDINAL_VARIANT_NATIVE 0 | |||
| #define CARDINAL_VARIANT_SYNTH 0 | |||
| @@ -0,0 +1,19 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 3 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the LICENSE file. | |||
| */ | |||
| #define CARDINAL_COMMON_DSP_ONLY | |||
| #include "../CardinalCommon.cpp" | |||
| @@ -0,0 +1,510 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * SPDX-License-Identifier: GPL-3.0-or-later | |||
| */ | |||
| #include <library.hpp> | |||
| #include <midi.hpp> | |||
| #include <patch.hpp> | |||
| #include <plugin.hpp> | |||
| #include <settings.hpp> | |||
| #include <system.hpp> | |||
| #include <app/Scene.hpp> | |||
| #include <engine/Engine.hpp> | |||
| #ifdef NDEBUG | |||
| # undef DEBUG | |||
| #endif | |||
| #if defined(HAVE_LIBLO) && defined(HEADLESS) | |||
| # include <lo/lo.h> | |||
| # include "extra/Thread.hpp" | |||
| #endif | |||
| #include <cfloat> | |||
| #include <list> | |||
| #include "CardinalCommon.hpp" | |||
| #include "DistrhoPluginUtils.hpp" | |||
| #include "CardinalPluginContext.hpp" | |||
| #include "extra/ScopedDenormalDisable.hpp" | |||
| #include "extra/ScopedSafeLocale.hpp" | |||
| #ifdef DISTRHO_OS_WASM | |||
| # include <emscripten/emscripten.h> | |||
| #else | |||
| # include "extra/SharedResourcePointer.hpp" | |||
| #endif | |||
| namespace rack { | |||
| namespace app { | |||
| rack::widget::Widget* createMenuBar() { return new rack::widget::Widget; } | |||
| } | |||
| namespace engine { | |||
| void Engine_setAboutToClose(Engine*); | |||
| } | |||
| } | |||
| START_NAMESPACE_DISTRHO | |||
| template<typename T> | |||
| static inline | |||
| bool d_isDiffHigherThanLimit(const T& v1, const T& v2, const T& limit) | |||
| { | |||
| return v1 != v2 ? (v1 > v2 ? v1 - v2 : v2 - v1) > limit : false; | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| struct ScopedContext { | |||
| ScopedContext(const CardinalBasePlugin* const plugin) | |||
| { | |||
| rack::contextSet(plugin->context); | |||
| } | |||
| ~ScopedContext() | |||
| { | |||
| rack::contextSet(nullptr); | |||
| } | |||
| }; | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| class CardinalPlugin : public CardinalBasePlugin | |||
| { | |||
| #ifdef DISTRHO_OS_WASM | |||
| ScopedPointer<Initializer> fInitializer; | |||
| #else | |||
| SharedResourcePointer<Initializer> fInitializer; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
| /* If host audio ins == outs we can get issues for inplace processing. | |||
| * So allocate a float array that will serve as safe copy for those cases. | |||
| */ | |||
| float** fAudioBufferCopy; | |||
| #endif | |||
| std::string fAutosavePath; | |||
| uint64_t fNextExpectedFrame; | |||
| // bypass handling | |||
| bool fWasBypassed; | |||
| MidiEvent bypassMidiEvents[16]; | |||
| static constexpr const uint16_t fNumActiveInputs = DISTRHO_PLUGIN_NUM_INPUTS; | |||
| static constexpr const uint16_t fNumActiveOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS; | |||
| public: | |||
| CardinalPlugin() | |||
| : CardinalBasePlugin(kCardinalParameterCount, 0, kCardinalStateCount), | |||
| #ifdef DISTRHO_OS_WASM | |||
| fInitializer(new Initializer(this, static_cast<const CardinalBaseUI*>(nullptr))), | |||
| #else | |||
| fInitializer(this, static_cast<const CardinalBaseUI*>(nullptr)), | |||
| #endif | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
| fAudioBufferCopy(nullptr), | |||
| #endif | |||
| fNextExpectedFrame(0), | |||
| fWasBypassed(false) | |||
| { | |||
| // check if first time loading a real instance | |||
| if (!fInitializer->shouldSaveSettings && !isDummyInstance()) | |||
| fInitializer->loadSettings(true); | |||
| // create unique temporary path for this instance | |||
| try { | |||
| char uidBuf[24]; | |||
| const std::string tmp = rack::system::getTempDirectory(); | |||
| for (int i=1;; ++i) | |||
| { | |||
| std::snprintf(uidBuf, sizeof(uidBuf), "Cardinal.%04d", i); | |||
| const std::string trypath = rack::system::join(tmp, uidBuf); | |||
| if (! rack::system::exists(trypath)) | |||
| { | |||
| if (rack::system::createDirectories(trypath)) | |||
| fAutosavePath = trypath; | |||
| break; | |||
| } | |||
| } | |||
| } DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||
| // initialize midi events used when entering bypassed state | |||
| std::memset(bypassMidiEvents, 0, sizeof(bypassMidiEvents)); | |||
| for (uint8_t i=0; i<16; ++i) | |||
| { | |||
| bypassMidiEvents[i].size = 3; | |||
| bypassMidiEvents[i].data[0] = 0xB0 + i; | |||
| bypassMidiEvents[i].data[1] = 0x7B; | |||
| } | |||
| const float sampleRate = getSampleRate(); | |||
| rack::settings::sampleRate = sampleRate; | |||
| context->bufferSize = getBufferSize(); | |||
| context->sampleRate = sampleRate; | |||
| const ScopedContext sc(this); | |||
| context->engine = new rack::engine::Engine; | |||
| context->engine->setSampleRate(sampleRate); | |||
| context->history = new rack::history::State; | |||
| context->patch = new rack::patch::Manager; | |||
| context->patch->autosavePath = fAutosavePath; | |||
| context->patch->templatePath = fInitializer->templatePath; | |||
| context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath; | |||
| context->event = new rack::widget::EventState; | |||
| context->scene = new rack::app::Scene; | |||
| context->event->rootWidget = context->scene; | |||
| if (! isDummyInstance()) | |||
| context->window = new rack::window::Window; | |||
| context->patch->clear(); | |||
| context->scene->rackScroll->reset(); | |||
| } | |||
| ~CardinalPlugin() override | |||
| { | |||
| { | |||
| const ScopedContext sc(this); | |||
| context->patch->clear(); | |||
| Engine_setAboutToClose(context->engine); | |||
| delete context; | |||
| } | |||
| if (! fAutosavePath.empty()) | |||
| rack::system::removeRecursively(fAutosavePath); | |||
| } | |||
| CardinalPluginContext* getRackContext() const noexcept | |||
| { | |||
| return context; | |||
| } | |||
| protected: | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Information */ | |||
| const char* getLabel() const override | |||
| { | |||
| return DISTRHO_PLUGIN_LABEL; | |||
| } | |||
| const char* getDescription() const override | |||
| { | |||
| return "" | |||
| "Cardinal is a free and open-source virtual modular synthesizer plugin.\n" | |||
| "It is based on the popular VCV Rack but with a focus on being a fully self-contained plugin version.\n" | |||
| "It is not an official VCV project, and it is not affiliated with it in any way.\n" | |||
| "\n" | |||
| "Cardinal contains Rack, some 3rd-party modules and a few internal utilities.\n" | |||
| "It does not load external modules and does not connect to the official Rack library/store.\n"; | |||
| } | |||
| const char* getMaker() const override | |||
| { | |||
| return "DISTRHO"; | |||
| } | |||
| const char* getHomePage() const override | |||
| { | |||
| return "https://github.com/DISTRHO/Cardinal"; | |||
| } | |||
| const char* getLicense() const override | |||
| { | |||
| return "GPLv3+"; | |||
| } | |||
| uint32_t getVersion() const override | |||
| { | |||
| return d_version(0, 26, 1); | |||
| } | |||
| int64_t getUniqueId() const override | |||
| { | |||
| return d_cconst('d', 'C', 'd', 'C'); | |||
| } | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Init */ | |||
| void initParameter(const uint32_t index, Parameter& parameter) override | |||
| { | |||
| if (index < kCardinalParameterCountAtModules) | |||
| { | |||
| parameter.name = "Parameter "; | |||
| parameter.name += String(index + 1); | |||
| parameter.symbol = "param_"; | |||
| parameter.symbol += String(index + 1); | |||
| parameter.unit = "v"; | |||
| parameter.hints = kParameterIsAutomatable; | |||
| parameter.ranges.def = 0.0f; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 10.0f; | |||
| return; | |||
| } | |||
| if (index == kCardinalParameterBypass) | |||
| { | |||
| parameter.initDesignation(kParameterDesignationBypass); | |||
| return; | |||
| } | |||
| } | |||
| void initState(const uint32_t index, State& state) override | |||
| { | |||
| switch (index) | |||
| { | |||
| case kCardinalStatePatch: | |||
| state.hints = kStateIsFilenamePath; | |||
| state.key = "patch"; | |||
| state.label = "Patch"; | |||
| break; | |||
| } | |||
| } | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Internal data */ | |||
| float getParameterValue(uint32_t index) const override | |||
| { | |||
| // host mapped parameters | |||
| if (index < kCardinalParameterCountAtModules) | |||
| return context->parameters[index]; | |||
| // bypass | |||
| if (index == kCardinalParameterBypass) | |||
| return context->bypassed ? 1.0f : 0.0f; | |||
| return 0.0f; | |||
| } | |||
| void setParameterValue(uint32_t index, float value) override | |||
| { | |||
| // host mapped parameters | |||
| if (index < kCardinalParameterCountAtModules) | |||
| { | |||
| context->parameters[index] = value; | |||
| return; | |||
| } | |||
| // bypass | |||
| if (index == kCardinalParameterBypass) | |||
| { | |||
| context->bypassed = value > 0.5f; | |||
| return; | |||
| } | |||
| } | |||
| void setState(const char* const key, const char* const value) override | |||
| { | |||
| if (std::strcmp(key, "param") == 0) | |||
| { | |||
| long long moduleId = 0; | |||
| int paramId = 0; | |||
| float paramValue = 0.f; | |||
| { | |||
| const ScopedSafeLocale cssl; | |||
| std::sscanf(value, "%lld:%d:%f", &moduleId, ¶mId, ¶mValue); | |||
| } | |||
| rack::engine::Module* const module = context->engine->getModule(moduleId); | |||
| DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); | |||
| context->engine->setParamValue(module, paramId, paramValue); | |||
| return; | |||
| } | |||
| if (std::strcmp(key, "patch") == 0) | |||
| { | |||
| const ScopedContext sc(this); | |||
| try { | |||
| context->patch->load(value); | |||
| } catch (rack::Exception& e) { | |||
| d_stderr(e.what()); | |||
| return; | |||
| } DISTRHO_SAFE_EXCEPTION("setState patch load"); | |||
| return; | |||
| } | |||
| } | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Process */ | |||
| void activate() override | |||
| { | |||
| context->bufferSize = getBufferSize(); | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
| fAudioBufferCopy = new float*[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i) | |||
| { | |||
| fAudioBufferCopy[i] = new float[context->bufferSize]; | |||
| std::memset(fAudioBufferCopy[i], 0, sizeof(float) * context->bufferSize); | |||
| } | |||
| #endif | |||
| fNextExpectedFrame = 0; | |||
| } | |||
| void deactivate() override | |||
| { | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
| if (fAudioBufferCopy != nullptr) | |||
| { | |||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i) | |||
| delete[] fAudioBufferCopy[i]; | |||
| delete[] fAudioBufferCopy; | |||
| fAudioBufferCopy = nullptr; | |||
| } | |||
| #endif | |||
| } | |||
| void run(const float** const inputs, float** const outputs, const uint32_t frames, | |||
| const MidiEvent* const midiEvents, const uint32_t midiEventCount) override | |||
| { | |||
| const ScopedDenormalDisable sdd; | |||
| rack::contextSet(context); | |||
| const bool bypassed = context->bypassed; | |||
| { | |||
| const TimePosition& timePos(getTimePosition()); | |||
| bool reset = timePos.playing && (timePos.frame == 0 || d_isDiffHigherThanLimit(fNextExpectedFrame, timePos.frame, (uint64_t)2)); | |||
| // ignore hosts which cannot supply time frame position | |||
| if (context->playing == timePos.playing && timePos.frame == 0 && context->frame == 0) | |||
| reset = false; | |||
| context->playing = timePos.playing; | |||
| context->bbtValid = timePos.bbt.valid; | |||
| context->frame = timePos.frame; | |||
| if (timePos.bbt.valid) | |||
| { | |||
| const double samplesPerTick = 60.0 * getSampleRate() | |||
| / timePos.bbt.beatsPerMinute | |||
| / timePos.bbt.ticksPerBeat; | |||
| context->bar = timePos.bbt.bar; | |||
| context->beat = timePos.bbt.beat; | |||
| context->beatsPerBar = timePos.bbt.beatsPerBar; | |||
| context->beatType = timePos.bbt.beatType; | |||
| context->barStartTick = timePos.bbt.barStartTick; | |||
| context->beatsPerMinute = timePos.bbt.beatsPerMinute; | |||
| context->tick = timePos.bbt.tick; | |||
| context->ticksPerBeat = timePos.bbt.ticksPerBeat; | |||
| context->ticksPerClock = timePos.bbt.ticksPerBeat / timePos.bbt.beatType; | |||
| context->ticksPerFrame = 1.0 / samplesPerTick; | |||
| context->tickClock = std::fmod(timePos.bbt.tick, context->ticksPerClock); | |||
| } | |||
| context->reset = reset; | |||
| fNextExpectedFrame = timePos.playing ? timePos.frame + frames : 0; | |||
| } | |||
| // separate buffers, use them | |||
| if (inputs != outputs && (inputs == nullptr || inputs[0] != outputs[0])) | |||
| { | |||
| context->dataIns = inputs; | |||
| context->dataOuts = outputs; | |||
| } | |||
| // inline processing, use a safe copy | |||
| else | |||
| { | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
| for (int i=0; i<fNumActiveInputs; ++i) | |||
| { | |||
| #if CARDINAL_VARIANT_MAIN || CARDINAL_VARIANT_MINI | |||
| // can be null on main and mini variants | |||
| if (inputs[i] != nullptr) | |||
| #endif | |||
| std::memcpy(fAudioBufferCopy[i], inputs[i], sizeof(float)*frames); | |||
| } | |||
| context->dataIns = fAudioBufferCopy; | |||
| #else | |||
| context->dataIns = nullptr; | |||
| #endif | |||
| context->dataOuts = outputs; | |||
| } | |||
| for (int i=0; i<fNumActiveOutputs; ++i) | |||
| { | |||
| #if CARDINAL_VARIANT_MAIN || CARDINAL_VARIANT_MINI | |||
| // can be null on main and mini variants | |||
| if (outputs[i] != nullptr) | |||
| #endif | |||
| std::memset(outputs[i], 0, sizeof(float)*frames); | |||
| } | |||
| if (bypassed) | |||
| { | |||
| if (fWasBypassed != bypassed) | |||
| { | |||
| context->midiEvents = bypassMidiEvents; | |||
| context->midiEventCount = 16; | |||
| } | |||
| else | |||
| { | |||
| context->midiEvents = nullptr; | |||
| context->midiEventCount = 0; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| context->midiEvents = midiEvents; | |||
| context->midiEventCount = midiEventCount; | |||
| } | |||
| ++context->processCounter; | |||
| context->engine->stepBlock(frames); | |||
| fWasBypassed = bypassed; | |||
| } | |||
| void sampleRateChanged(const double newSampleRate) override | |||
| { | |||
| rack::contextSet(context); | |||
| rack::settings::sampleRate = newSampleRate; | |||
| context->sampleRate = newSampleRate; | |||
| context->engine->setSampleRate(newSampleRate); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------- | |||
| private: | |||
| /** | |||
| Set our plugin class as non-copyable and add a leak detector just in case. | |||
| */ | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalPlugin) | |||
| }; | |||
| CardinalPluginContext* getRackContextFromPlugin(void* const ptr) | |||
| { | |||
| return static_cast<CardinalPlugin*>(ptr)->getRackContext(); | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Plugin entry point, called by DPF to create a new plugin instance. */ | |||
| Plugin* createPlugin() | |||
| { | |||
| return new CardinalPlugin(); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1 @@ | |||
| ../CardinalRemote.cpp | |||
| @@ -0,0 +1,60 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 3 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the LICENSE file. | |||
| */ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_LOADER 1 | |||
| #define CARDINAL_VARIANT_MAIN 0 | |||
| #define CARDINAL_VARIANT_MINI 0 | |||
| #define CARDINAL_VARIANT_NATIVE 0 | |||
| #define CARDINAL_VARIANT_SYNTH 0 | |||
| #define CARDINAL_NUM_AUDIO_INPUTS 2 | |||
| #define CARDINAL_NUM_AUDIO_OUTPUTS 2 | |||
| #define DISTRHO_PLUGIN_BRAND "DISTRHO" | |||
| #define DISTRHO_PLUGIN_URI "https://distrho.kx.studio/plugins/cardinal#loader" | |||
| #define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.cardinal#loader" | |||
| #define DISTRHO_PLUGIN_AU_TYPE aumf | |||
| #define DISTRHO_PLUGIN_BRAND_ID Dstr | |||
| #define DISTRHO_PLUGIN_UNIQUE_ID DcnC | |||
| #define DISTRHO_PLUGIN_NAME "Cardinal Loader" | |||
| #define DISTRHO_PLUGIN_LABEL "CardinalLoader" | |||
| #define DISTRHO_PLUGIN_HAS_UI 0 | |||
| #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0 | |||
| #define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS CARDINAL_NUM_AUDIO_INPUTS | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS CARDINAL_NUM_AUDIO_OUTPUTS | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 1 | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1 | |||
| #define DISTRHO_PLUGIN_WANT_FULL_STATE 0 | |||
| #define DISTRHO_PLUGIN_WANT_STATE 1 | |||
| #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | |||
| #define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 0 | |||
| #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:UtilityPlugin" | |||
| #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Generator" | |||
| #define DPF_VST3_DONT_USE_BRAND_ID | |||
| #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| @@ -0,0 +1,9 @@ | |||
| #!/usr/bin/make -f | |||
| # Makefile for DISTRHO Plugins # | |||
| # ---------------------------- # | |||
| # Created by falkTX | |||
| # | |||
| NAME = CardinalLoader | |||
| CARDINAL_VARIANT = loader | |||
| include ../Makefile.cardinal.mk | |||
| @@ -0,0 +1 @@ | |||
| ../custom/RemoteNanoVG.cpp | |||
| @@ -0,0 +1 @@ | |||
| ../custom/RemoteWindow.cpp | |||
| @@ -0,0 +1 @@ | |||
| ../override/common.cpp | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -18,9 +18,10 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_LOADER 0 | |||
| #define CARDINAL_VARIANT_MAIN 0 | |||
| #define CARDINAL_VARIANT_MINI 1 | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_NATIVE 0 | |||
| #define CARDINAL_VARIANT_SYNTH 0 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -18,9 +18,10 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_LOADER 0 | |||
| #define CARDINAL_VARIANT_MAIN 0 | |||
| #define CARDINAL_VARIANT_MINI 1 | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_NATIVE 0 | |||
| #define CARDINAL_VARIANT_SYNTH 0 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -18,9 +18,10 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_LOADER 0 | |||
| #define CARDINAL_VARIANT_MAIN 0 | |||
| #define CARDINAL_VARIANT_MINI 0 | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_NATIVE 1 | |||
| #define CARDINAL_VARIANT_SYNTH 0 | |||
| @@ -47,7 +47,9 @@ START_NAMESPACE_DISTRHO | |||
| enum CardinalParameters { | |||
| kCardinalParameterCountAtModules = kModuleParameterCount, | |||
| kCardinalParameterBypass = kCardinalParameterCountAtModules, | |||
| #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
| #if CARDINAL_VARIANT_LOADER | |||
| kCardinalParameterCount = kCardinalParameterBypass | |||
| #elif CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
| kCardinalParameterStartWindow, | |||
| kCardinalParameterCountAtWindow = kCardinalParameterStartWindow + kWindowParameterCount, | |||
| #if CARDINAL_VARIANT_MINI | |||
| @@ -85,6 +87,7 @@ enum CardinalParameters { | |||
| enum CardinalStates { | |||
| kCardinalStatePatch, | |||
| #if ! CARDINAL_VARIANT_LOADER | |||
| kCardinalStateScreenshot, | |||
| kCardinalStateComment, | |||
| #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
| @@ -93,11 +96,13 @@ enum CardinalStates { | |||
| #if CARDINAL_VARIANT_MINI | |||
| kCardinalStateParamChange, | |||
| #endif | |||
| #endif | |||
| kCardinalStateCount | |||
| }; | |||
| static_assert(kCardinalParameterBypass == kModuleParameterCount, "valid parameter indexes"); | |||
| #if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
| #if CARDINAL_VARIANT_LOADER | |||
| #elif CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
| static_assert(kCardinalParameterStartWindow == kModuleParameterCount + 1, "valid parameter indexes"); | |||
| static_assert(kCardinalParameterStartWindow == kCardinalParameterBypass + 1, "valid parameter indexes"); | |||
| static_assert(kCardinalParameterCountAtWindow == kModuleParameterCount + kWindowParameterCount + 1, "valid parameter indexes"); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Cardinal Plugin | |||
| * Copyright (C) 2021-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2026 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -18,9 +18,10 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_LOADER 0 | |||
| #define CARDINAL_VARIANT_MAIN 0 | |||
| #define CARDINAL_VARIANT_MINI 0 | |||
| #define CARDINAL_VARIANT_FX 0 | |||
| #define CARDINAL_VARIANT_NATIVE 0 | |||
| #define CARDINAL_VARIANT_SYNTH 1 | |||
| @@ -139,6 +139,10 @@ jack: $(TARGETS) | |||
| native: $(TARGETS) | |||
| $(MAKE) jack -C CardinalNative | |||
| loader: $(TARGETS) | |||
| $(MAKE) lv2_dsp -C CardinalLoader | |||
| $(MAKE) mapi -C CardinalLoader | |||
| mini: $(TARGETS) | |||
| $(MAKE) jack -C CardinalMini | |||
| $(MAKE) lv2_sep -C CardinalMiniSep | |||