diff --git a/plugins/Cardinal/orig/HostCV.svg b/plugins/Cardinal/orig/HostCV.svg
new file mode 100644
index 0000000..4ec0f2b
--- /dev/null
+++ b/plugins/Cardinal/orig/HostCV.svg
@@ -0,0 +1,153 @@
+
+
+
+
diff --git a/plugins/Cardinal/plugin.json b/plugins/Cardinal/plugin.json
index 894d497..fcb8397 100644
--- a/plugins/Cardinal/plugin.json
+++ b/plugins/Cardinal/plugin.json
@@ -13,11 +13,20 @@
"changelogUrl": "",
"modules":
[
+ {
+ "slug": "HostCV",
+ "disabled": false,
+ "name": "Host CV",
+ "description": "Exposes host-provided CV ports in a module",
+ "tags": [
+ "Utility"
+ ]
+ },
{
"slug": "HostParameters",
"disabled": false,
"name": "Host Parameters",
- "description": "Exposes host-controlled plugin parameters as module",
+ "description": "Exposes host-controlled plugin parameters in a module",
"tags": [
"Utility"
]
@@ -26,7 +35,7 @@
"slug": "HostTime",
"disabled": false,
"name": "Host Time",
- "description": "Exposes host-provided timing information as module",
+ "description": "Exposes host-provided time/transport information in a module",
"tags": [
"Utility"
]
@@ -53,7 +62,7 @@
"slug": "Ildaeil",
"disabled": false,
"name": "Ildaeil Plugin Host",
- "description": "A plugin host within Cardinal for loading any FX",
+ "description": "A mini plugin host within Cardinal for loading any FX",
"tags": [
"Utility"
]
diff --git a/plugins/Cardinal/res/HostCV.svg b/plugins/Cardinal/res/HostCV.svg
new file mode 100644
index 0000000..0ca8180
--- /dev/null
+++ b/plugins/Cardinal/res/HostCV.svg
@@ -0,0 +1,170 @@
+
+
+
+
diff --git a/plugins/Cardinal/src/Carla.cpp b/plugins/Cardinal/src/Carla.cpp
index 3bbcd83..dd47ce0 100644
--- a/plugins/Cardinal/src/Carla.cpp
+++ b/plugins/Cardinal/src/Carla.cpp
@@ -424,14 +424,6 @@ struct CarlaModuleWidget : ModuleWidget {
}
}
- void drawTextLine(NVGcontext* const vg, const uint offset, const char* const text)
- {
- const float y = startY + offset * padding;
- nvgBeginPath(vg);
- nvgFillColor(vg, color::WHITE);
- nvgText(vg, middleX, y + 16, text, nullptr);
- }
-
void onContextCreate(const ContextCreateEvent& e) override
{
ModuleWidget::onContextCreate(e);
@@ -456,6 +448,14 @@ struct CarlaModuleWidget : ModuleWidget {
ModuleWidget::onContextDestroy(e);
}
+ void drawTextLine(NVGcontext* const vg, const uint offset, const char* const text)
+ {
+ const float y = startY + offset * padding;
+ nvgBeginPath(vg);
+ nvgFillColor(vg, color::WHITE);
+ nvgText(vg, middleX, y + 16, text, nullptr);
+ }
+
void draw(const DrawArgs& args) override
{
nvgBeginPath(args.vg);
@@ -511,18 +511,18 @@ struct CarlaModuleWidget : ModuleWidget {
[=]() {showUI();}
));
- menu->addChild(createCheckMenuItem("Bipolar Inputs", "",
+ menu->addChild(createCheckMenuItem("Bipolar CV Inputs", "",
[=]() {return module->params[CarlaModule::BIPOLAR_INPUTS].getValue() > 0.1f;},
[=]() {module->params[CarlaModule::BIPOLAR_INPUTS].setValue(1.0f - module->params[CarlaModule::BIPOLAR_INPUTS].getValue());}
));
- menu->addChild(createCheckMenuItem("Bipolar Outputs", "",
+ menu->addChild(createCheckMenuItem("Bipolar CV Outputs", "",
[=]() {return module->params[CarlaModule::BIPOLAR_OUTPUTS].getValue() > 0.1f;},
[=]() {module->params[CarlaModule::BIPOLAR_OUTPUTS].setValue(1.0f - module->params[CarlaModule::BIPOLAR_OUTPUTS].getValue());}
));
}
- void onDoubleClick(const DoubleClickEvent& e)
+ void onDoubleClick(const DoubleClickEvent& e) override
{
e.consume(this);
showUI();
diff --git a/plugins/Cardinal/src/HostCV.cpp b/plugins/Cardinal/src/HostCV.cpp
new file mode 100644
index 0000000..cb98370
--- /dev/null
+++ b/plugins/Cardinal/src/HostCV.cpp
@@ -0,0 +1,172 @@
+/*
+ * DISTRHO Cardinal Plugin
+ * Copyright (C) 2021 Filipe Coelho
+ *
+ * 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.
+ */
+
+#include "plugincontext.hpp"
+
+// -----------------------------------------------------------------------------------------------------------
+
+USE_NAMESPACE_DISTRHO;
+
+struct HostCV : Module {
+ enum ParamIds {
+ BIPOLAR_INPUTS,
+ BIPOLAR_OUTPUTS,
+ NUM_PARAMS
+ };
+ enum InputIds {
+ NUM_INPUTS = 10
+ };
+ enum OutputIds {
+ NUM_OUTPUTS = 10
+ };
+ enum LightIds {
+ NUM_LIGHTS
+ };
+
+ HostCV()
+ {
+ config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
+ configParam(BIPOLAR_INPUTS, 0.f, 1.f, 1.f, "Bipolar Inputs")->randomizeEnabled = false;
+ configParam(BIPOLAR_OUTPUTS, 0.f, 1.f, 1.f, "Bipolar Outputs")->randomizeEnabled = false;
+
+ CardinalPluginContext* const pcontext = reinterpret_cast(APP);
+
+ if (pcontext == nullptr)
+ throw rack::Exception("Plugin context is null.");
+
+ if (pcontext->loadedHostCV)
+ throw rack::Exception("Another instance of a Host CV module is already loaded, only one can be used at a time.");
+
+ pcontext->loadedHostCV = true;
+ }
+
+ ~HostCV() override
+ {
+ CardinalPluginContext* const pcontext = reinterpret_cast(APP);
+ DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,);
+
+ pcontext->loadedHostCV = false;
+ }
+
+ void process(const ProcessArgs&) override
+ {
+ if (CardinalPluginContext* const pcontext = reinterpret_cast(APP))
+ {
+ const float** dataIns = pcontext->dataIns;
+ float** dataOuts = pcontext->dataOuts;
+
+ if (dataIns == nullptr || dataOuts == nullptr)
+ return;
+
+ const uint32_t dataFrame = pcontext->dataFrame++;
+ const float inputOffset = params[BIPOLAR_INPUTS].getValue() > 0.1f ? 5.0f : 0.0f;
+ const float outputOffset = params[BIPOLAR_OUTPUTS].getValue() > 0.1f ? 5.0f : 0.0f;
+
+ for (int i=0; i<10; ++i)
+ {
+ outputs[i].setVoltage(dataIns[i+2][dataFrame] - inputOffset);
+ dataOuts[i+2][dataFrame] = inputs[i].getVoltage() + outputOffset;
+ }
+ }
+ }
+};
+
+struct HostCVWidget : ModuleWidget {
+ static constexpr const float startX_In = 14.0f;
+ static constexpr const float startX_Out = 96.0f;
+ static constexpr const float startY = 74.0f;
+ static constexpr const float padding = 29.0f;
+ static constexpr const float middleX = startX_In + (startX_Out - startX_In) * 0.5f + padding * 0.25f;
+
+ HostCVWidget(HostCV* const module)
+ {
+ setModule(module);
+ setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostCV.svg")));
+
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
+ addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+ addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
+
+ for (uint i=0; i(Vec(startX_In, startY + padding * i), module, i));
+
+ for (uint i=0; i(Vec(startX_Out, startY + padding * i), module, i));
+ }
+
+ void drawTextLine(NVGcontext* const vg, const uint offset, const char* const text)
+ {
+ const float y = startY + offset * padding;
+ nvgBeginPath(vg);
+ nvgFillColor(vg, color::WHITE);
+ nvgText(vg, middleX, y + 16, text, nullptr);
+ }
+
+ void draw(const DrawArgs& args) override
+ {
+ nvgBeginPath(args.vg);
+ nvgRect(args.vg, 0, 0, box.size.x, box.size.y);
+ nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, 0, 0, box.size.y,
+ nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
+ nvgFill(args.vg);
+
+ nvgFontFaceId(args.vg, 0);
+ nvgFontSize(args.vg, 11);
+ nvgTextAlign(args.vg, NVG_ALIGN_CENTER);
+ // nvgTextBounds(vg, 0, 0, text, nullptr, nullptr);
+
+ nvgBeginPath(args.vg);
+ nvgRoundedRect(args.vg, startX_Out - 4.0f, startY - 2.0f, padding, padding * HostCV::NUM_INPUTS, 4);
+ nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0));
+ nvgFill(args.vg);
+
+ drawTextLine(args.vg, 0, "CV 1");
+ drawTextLine(args.vg, 1, "CV 2");
+ drawTextLine(args.vg, 2, "CV 3");
+ drawTextLine(args.vg, 3, "CV 4");
+ drawTextLine(args.vg, 4, "CV 5");
+ drawTextLine(args.vg, 5, "CV 6");
+ drawTextLine(args.vg, 6, "CV 7");
+ drawTextLine(args.vg, 7, "CV 8");
+ drawTextLine(args.vg, 8, "CV 9");
+ drawTextLine(args.vg, 9, "CV 10");
+
+ ModuleWidget::draw(args);
+ }
+
+ void appendContextMenu(ui::Menu* const menu) override
+ {
+ menu->addChild(new ui::MenuSeparator);
+
+ menu->addChild(createCheckMenuItem("Bipolar Inputs", "",
+ [=]() {return module->params[HostCV::BIPOLAR_INPUTS].getValue() > 0.1f;},
+ [=]() {module->params[HostCV::BIPOLAR_INPUTS].setValue(1.0f - module->params[HostCV::BIPOLAR_INPUTS].getValue());}
+ ));
+
+ menu->addChild(createCheckMenuItem("Bipolar Outputs", "",
+ [=]() {return module->params[HostCV::BIPOLAR_OUTPUTS].getValue() > 0.1f;},
+ [=]() {module->params[HostCV::BIPOLAR_OUTPUTS].setValue(1.0f - module->params[HostCV::BIPOLAR_OUTPUTS].getValue());}
+ ));
+ }
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
+Model* modelHostCV = createModel("HostCV");
+
+// --------------------------------------------------------------------------------------------------------------------
diff --git a/plugins/Cardinal/src/plugin.hpp b/plugins/Cardinal/src/plugin.hpp
index f54146a..f6ed020 100644
--- a/plugins/Cardinal/src/plugin.hpp
+++ b/plugins/Cardinal/src/plugin.hpp
@@ -29,6 +29,7 @@ extern Plugin* pluginInstance;
extern Model* modelCarla;
extern Model* modelGlBars;
-extern Model* modelIldaeil;
+extern Model* modelHostCV;
extern Model* modelHostParameters;
extern Model* modelHostTime;
+extern Model* modelIldaeil;
diff --git a/plugins/Cardinal/src/plugincontext.hpp b/plugins/Cardinal/src/plugincontext.hpp
index 339f285..cc952e0 100644
--- a/plugins/Cardinal/src/plugincontext.hpp
+++ b/plugins/Cardinal/src/plugincontext.hpp
@@ -33,12 +33,15 @@ struct CardinalPluginContext : rack::Context {
uint32_t bufferSize;
double sampleRate;
float parameters[kModuleParameters];
- bool playing, reset, bbtValid;
+ bool playing, reset, bbtValid, loadedHostCV;
int32_t bar, beat, beatsPerBar, beatType;
uint64_t frame;
double barStartTick, beatsPerMinute;
double tick, tickClock, ticksPerBeat, ticksPerClock, ticksPerFrame;
uintptr_t nativeWindowId;
+ uint32_t dataFrame;
+ const float** dataIns;
+ float** dataOuts;
Plugin* const plugin;
CardinalPluginContext(Plugin* const p);
};
diff --git a/plugins/Makefile b/plugins/Makefile
index d4233b2..68695ed 100644
--- a/plugins/Makefile
+++ b/plugins/Makefile
@@ -179,6 +179,7 @@ PLUGIN_FILES = plugins.cpp
PLUGIN_FILES += Cardinal/src/Carla.cpp
PLUGIN_FILES += Cardinal/src/glBars.cpp
+PLUGIN_FILES += Cardinal/src/HostCV.cpp
PLUGIN_FILES += Cardinal/src/HostParameters.cpp
PLUGIN_FILES += Cardinal/src/HostTime.cpp
PLUGIN_FILES += Cardinal/src/Ildaeil.cpp
diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp
index 49d9f93..27c0c45 100644
--- a/plugins/plugins.cpp
+++ b/plugins/plugins.cpp
@@ -407,9 +407,10 @@ static void initStatic__Cardinal()
{
p->addModel(modelCarla);
p->addModel(modelGlBars);
- p->addModel(modelIldaeil);
+ p->addModel(modelHostCV);
p->addModel(modelHostParameters);
p->addModel(modelHostTime);
+ p->addModel(modelIldaeil);
}
}
diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp
index 8ff62f0..9346ded 100644
--- a/src/CardinalPlugin.cpp
+++ b/src/CardinalPlugin.cpp
@@ -875,6 +875,12 @@ protected:
#endif
}
+#if DISTRHO_PLUGIN_NUM_OUTPUTS != 2
+ context->dataFrame = 0;
+ context->dataIns = inputs;
+ context->dataOuts = outputs;
+#endif
+
context->engine->stepBlock(frames);
if (fCurrentAudioDevice != nullptr)
diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp
index e34d684..453db61 100644
--- a/src/PluginContext.hpp
+++ b/src/PluginContext.hpp
@@ -40,12 +40,15 @@ struct CardinalPluginContext : rack::Context {
uint32_t bufferSize;
double sampleRate;
float parameters[kModuleParameters];
- bool playing, reset, bbtValid;
+ bool playing, reset, bbtValid, loadedHostCV;
int32_t bar, beat, beatsPerBar, beatType;
uint64_t frame;
double barStartTick, beatsPerMinute;
double tick, tickClock, ticksPerBeat, ticksPerClock, ticksPerFrame;
uintptr_t nativeWindowId;
+ uint32_t dataFrame;
+ const float** dataIns;
+ float** dataOuts;
Plugin* const plugin;
CardinalPluginContext(Plugin* const p)
@@ -54,6 +57,7 @@ struct CardinalPluginContext : rack::Context {
playing(false),
reset(false),
bbtValid(false),
+ loadedHostCV(false),
bar(1),
beat(1),
beatsPerBar(4),
@@ -67,6 +71,9 @@ struct CardinalPluginContext : rack::Context {
ticksPerClock(0.0),
ticksPerFrame(0.0),
nativeWindowId(0),
+ dataFrame(0),
+ dataIns(nullptr),
+ dataOuts(nullptr),
plugin(p)
{
std::memset(parameters, 0, sizeof(parameters));