Browse Source

Move some common code to new header files

tags/22.02
falkTX 4 years ago
parent
commit
6bbdf9a63d
13 changed files with 563 additions and 553 deletions
  1. +11
    -40
      plugins/Cardinal/src/Carla.cpp
  2. +22
    -330
      plugins/Cardinal/src/HostAudio.cpp
  3. +9
    -37
      plugins/Cardinal/src/HostCV.cpp
  4. +1
    -0
      plugins/Cardinal/src/HostMIDI-CC.cpp
  5. +1
    -0
      plugins/Cardinal/src/HostMIDI-Gate.cpp
  6. +1
    -0
      plugins/Cardinal/src/HostMIDI-Map.cpp
  7. +27
    -55
      plugins/Cardinal/src/HostMIDI.cpp
  8. +1
    -1
      plugins/Cardinal/src/HostTime.cpp
  9. +1
    -1
      plugins/Cardinal/src/ImGuiWidget.hpp
  10. +90
    -0
      plugins/Cardinal/src/ModuleWidgets.hpp
  11. +398
    -0
      plugins/Cardinal/src/Widgets.hpp
  12. +1
    -0
      plugins/Cardinal/src/glBars.cpp
  13. +0
    -89
      plugins/Cardinal/src/plugin.hpp

+ 11
- 40
plugins/Cardinal/src/Carla.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Cardinal Plugin
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* 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
@@ -16,6 +16,7 @@
*/

#include "plugincontext.hpp"
#include "ModuleWidgets.hpp"

#include "CarlaNativePlugin.h"
#include "CarlaBackendUtils.hpp"
@@ -442,34 +443,23 @@ static intptr_t host_dispatcher(const NativeHostHandle handle, const NativeHostD
// --------------------------------------------------------------------------------------------------------------------

#ifndef HEADLESS
struct CarlaModuleWidget : ModuleWidget, IdleCallback {
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.35f;

struct CarlaModuleWidget : ModuleWidgetWith9HP, IdleCallback {
CarlaModule* const module;
bool idleCallbackActive = false;
bool visible = false;

CarlaModuleWidget(CarlaModule* const m)
: ModuleWidget(),
module(m)
: module(m)
{
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Carla.svg")));

addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
setSideScrews();

for (uint i=0; i<CarlaModule::NUM_INPUTS; ++i)
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), module, i));
createAndAddInput(i);

for (uint i=0; i<CarlaModule::NUM_OUTPUTS; ++i)
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * i), module, i));
createAndAddOutput(i);
}

~CarlaModuleWidget() override
@@ -565,30 +555,11 @@ struct CarlaModuleWidget : ModuleWidget, IdleCallback {
module->fCarlaPluginDescriptor->ui_idle(module->fCarlaPluginHandle);
}

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);

nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * CarlaModule::NUM_INPUTS, 4);
nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0));
nvgFill(args.vg);
drawBackground(args.vg);
drawOutputJacksArea(args.vg, CarlaModule::NUM_INPUTS);
setupTextLines(args.vg);

drawTextLine(args.vg, 0, "Audio 1");
drawTextLine(args.vg, 1, "Audio 2");
@@ -601,7 +572,7 @@ struct CarlaModuleWidget : ModuleWidget, IdleCallback {
drawTextLine(args.vg, 8, "CV 7");
drawTextLine(args.vg, 9, "CV 8");

ModuleWidget::draw(args);
ModuleWidgetWith9HP::draw(args);
}

void showUI()


+ 22
- 330
plugins/Cardinal/src/HostAudio.cpp View File

@@ -16,192 +16,13 @@
*/

#include "plugincontext.hpp"
#include "ModuleWidgets.hpp"
#include "Widgets.hpp"

// -----------------------------------------------------------------------------------------------------------

USE_NAMESPACE_DISTRHO;

struct NanoKnob : Knob {
static const int ringSize = 4;

std::string displayLabel = "Level";
std::string displayString = "0 dB";
float normalizedValue = 0.5f;

NanoKnob()
{
box.size = Vec(100, 100);
}

void drawLayer(const DrawArgs& args, int layer) override
{
if (layer != 1)
return Knob::drawLayer(args, layer);

const float w = box.size.x;
const float h = box.size.y;

const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize;

const int knobStartX = w / 2 - knobSize / 2;
const int knobStartY = ringSize;
const int knobCenterX = knobStartX + knobSize / 2;
const int knobCenterY = knobStartY + knobSize / 2;

const NVGcolor testing = nvgRGBf(0.76f, 0.11f, 0.22f);

nvgLineCap(args.vg, NVG_ROUND);

// outer ring value
nvgBeginPath(args.vg);
nvgArc(args.vg,
knobCenterX,
knobCenterY,
knobSize / 2 + ringSize / 2 + 1,
nvgDegToRad(135.0f),
nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue),
NVG_CW);
nvgStrokeWidth(args.vg, ringSize);
nvgStrokeColor(args.vg, testing);
nvgStroke(args.vg);

// simulate color bleeding
nvgBeginPath(args.vg);
nvgArc(args.vg,
knobCenterX,
knobCenterY,
knobSize / 2 - 3,
nvgDegToRad(135.0f),
nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue),
NVG_CW);
nvgStrokeWidth(args.vg, 5);
nvgStrokeColor(args.vg, nvgRGBAf(testing.r, testing.g, testing.b, 0.1f));
nvgStroke(args.vg);

// line indicator
nvgStrokeWidth(args.vg, 2);
nvgSave(args.vg);
nvgTranslate(args.vg, knobCenterX, knobCenterY);
nvgRotate(args.vg, nvgDegToRad(45.0f) + normalizedValue * nvgDegToRad(270.0f));
nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, -2, knobSize / 2 - 9, 2, 6, 1);
nvgClosePath(args.vg);
nvgFillColor(args.vg, nvgRGBf(1.0f, 1.0f, 1.0f));
nvgFill(args.vg);
nvgRestore(args.vg);

// adjusted from VCVRack's LightWidget.cpp
if (const float halo = settings::haloBrightness)
{
float radius = knobSize * 0.5f;
float oradius = radius + std::min(radius * 4.f, 15.f);

NVGcolor icol = color::mult(nvgRGBAf(testing.r, testing.g, testing.b, 0.2f), halo);
NVGcolor ocol = nvgRGBA(0, 0, 0, 0);
NVGpaint paint = nvgRadialGradient(args.vg, knobCenterX, knobCenterY, radius, oradius, icol, ocol);

nvgBeginPath(args.vg);
nvgRect(args.vg, knobCenterX - oradius, knobCenterY - oradius, 2 * oradius, 2 * oradius);
nvgFillPaint(args.vg, paint);
nvgFill(args.vg);
}

// bottom label (value)
bndIconLabelValue(args.vg, 0, knobSize + ringSize, w, BND_WIDGET_HEIGHT, -1,
testing, BND_CENTER,
BND_LABEL_FONT_SIZE, displayString.c_str(), nullptr);

Knob::drawLayer(args, layer);
}

void draw(const DrawArgs& args) override
{
if (engine::ParamQuantity* const pq = getParamQuantity())
normalizedValue = pq->getScaledValue();

const float w = box.size.x;
const float h = box.size.y;

const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize;

const int knobStartX = w / 2 - knobSize / 2;
const int knobStartY = ringSize;
const int knobCenterX = knobStartX + knobSize / 2;
const int knobCenterY = knobStartY + knobSize / 2;

// knob
NVGcolor shade_top;
NVGcolor shade_down;
BNDwidgetState state;
if (APP->event->getDraggedWidget() == this)
state = BND_ACTIVE;
else if (APP->event->getHoveredWidget() == this)
state = BND_HOVER;
else
state = BND_DEFAULT;
bndInnerColors(&shade_top, &shade_down, &bndGetTheme()->optionTheme, state, 0);

// inner fill
nvgBeginPath(args.vg);
nvgCircle(args.vg, knobCenterX, knobCenterY, knobSize / 2);
nvgFillPaint(args.vg, nvgLinearGradient(args.vg,
knobStartX,
knobStartY,
knobStartX,
knobStartY + knobSize,
shade_top,
shade_down));
nvgFill(args.vg);

// inner fill border (inner)
nvgBeginPath(args.vg);
nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2 - 1, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW);
nvgClosePath(args.vg);
nvgStrokeWidth(args.vg, 1);
nvgStrokeColor(args.vg, nvgRGBAf(0.5f, 0.5f, 0.5f, 0.4f));
nvgStroke(args.vg);

// inner fill border (outer)
nvgBeginPath(args.vg);
nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW);
nvgClosePath(args.vg);
nvgStrokeWidth(args.vg, 1);
nvgStrokeColor(args.vg, nvgRGBAf(0.0f, 0.0f, 0.0f, 0.4f));
nvgStroke(args.vg);

nvgLineCap(args.vg, NVG_ROUND);

// outer ring background
nvgBeginPath(args.vg);
nvgArc(args.vg,
knobCenterX,
knobCenterY,
knobSize / 2 + ringSize / 2 + 1,
nvgDegToRad(135.0f),
nvgDegToRad(45.0f),
NVG_CW);
nvgStrokeWidth(args.vg, ringSize);
nvgStrokeColor(args.vg, nvgRGBf(0.5f, 0.5f, 0.5f));
nvgStroke(args.vg);

// bottom label (name)
bndIconLabelValue(args.vg, 0, knobStartY + knobSize + BND_WIDGET_HEIGHT * 0.75f, w, BND_WIDGET_HEIGHT, -1,
SCHEME_WHITE, BND_CENTER,
BND_LABEL_FONT_SIZE, displayLabel.c_str(), nullptr);

Knob::draw(args);
}

void onChange(const ChangeEvent&) override
{
engine::ParamQuantity* const pq = getParamQuantity();
DISTRHO_SAFE_ASSERT_RETURN(pq != nullptr,);

displayLabel = pq->getLabel();
displayString = pq->getDisplayValueString() + pq->getUnit();
}
};

/*
* Find the highest absolute and normalized value within a float array.
*/
@@ -365,132 +186,26 @@ struct HostAudio : Module {
};

template<int numIO>
struct NanoMeter : Widget {
struct HostAudioNanoMeter : NanoMeter {
HostAudio<numIO>* const module;
float gainMeterL = 0.0f;
float gainMeterR = 0.0f;

NanoMeter(HostAudio<numIO>* const m)
: module(m)
{
box.size = Vec(100, 100);
}
HostAudioNanoMeter(HostAudio<numIO>* const m)
: module(m) {}

void drawLayer(const DrawArgs& args, int layer) override
void updateMeters() override
{
if (layer != 1)
if (module == nullptr || module->resetMeters)
return;

const float usableHeight = box.size.y - 10.0f;

// draw background
nvgBeginPath(args.vg);
nvgRect(args.vg,
0,
0,
box.size.x,
usableHeight);
nvgFillColor(args.vg, nvgRGB(26, 26, 26));
nvgFill(args.vg);

nvgFillColor(args.vg, nvgRGBAf(0.76f, 0.11f, 0.22f, 0.5f));
nvgStrokeColor(args.vg, nvgRGBf(0.76f, 0.11f, 0.22f));

if (module != nullptr)
{
// Only fetch new values once DSP side is updated
if (! module->resetMeters)
{
gainMeterL = module->gainMeterL;
gainMeterR = module->gainMeterR;
module->resetMeters = true;
}

const float heightL = 1.0f + std::sqrt(gainMeterL) * (usableHeight - 1.0f);
nvgBeginPath(args.vg);
nvgRect(args.vg, 0.0f, usableHeight - heightL, box.size.x * 0.5f - 1.0f, heightL);
nvgFill(args.vg);
nvgStroke(args.vg);

const float heightR = 1.0f + std::sqrt(gainMeterR) * (usableHeight - 1.0f);
nvgBeginPath(args.vg);
nvgRect(args.vg, box.size.x * 0.5f + 1.0f, usableHeight - heightR, box.size.x * 0.5f - 2.0f, heightR);
nvgFill(args.vg);
nvgStroke(args.vg);
}

nvgLineCap(args.vg, NVG_ROUND);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 2.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 11.0f, usableHeight + 2.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 4.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 16.0f, usableHeight + 4.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 6.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 19.0f, usableHeight + 6.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 8.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 22.0f, usableHeight + 8.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 10.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 24.0f, usableHeight + 10.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 12.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 26.0f, usableHeight + 12.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 10.0f, usableHeight + 2.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 2.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 15.0f, usableHeight + 4.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 4.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 18.0f, usableHeight + 6.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 6.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 20.0f, usableHeight + 8.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 8.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 22.0f, usableHeight + 10.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 10.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 24.0f, usableHeight + 12.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 12.0f);
nvgStroke(args.vg);
// Only fetch new values once DSP side is updated
gainMeterL = module->gainMeterL;
gainMeterR = module->gainMeterR;
module->resetMeters = true;
}
};

template<int numIO>
struct HostAudioWidget : ModuleWidget {
static constexpr const float startX_In = 14.0f;
static constexpr const float startX_Out = 81.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.35f;

struct HostAudioWidget : ModuleWidgetWith8HP {
HostAudio<numIO>* const module;

HostAudioWidget(HostAudio<numIO>* const m)
@@ -498,53 +213,30 @@ struct HostAudioWidget : ModuleWidget {
{
setModule(m);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostAudio.svg")));

addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
setSideScrews();

for (uint i=0; i<numIO; ++i)
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), m, i));
for (uint i=0; i<numIO; ++i)
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * i), m, i));
{
createAndAddInput(i);
createAndAddOutput(i);
}

if (numIO == 2)
{
addParam(createParamCentered<NanoKnob>(Vec(middleX, 310.0f), m, 0));

NanoMeter<numIO>* const meter = new NanoMeter<numIO>(m);
HostAudioNanoMeter<numIO>* const meter = new HostAudioNanoMeter<numIO>(m);
meter->box.pos = Vec(middleX - padding + 2.75f, startY + padding * 2);
meter->box.size = Vec(padding * 2.0f - 4.0f, 136.0f);
addChild(meter);
}
}

void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text)
{
const float y = startY + posY * 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);

nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * numIO, 4);
nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0));
nvgFill(args.vg);
drawBackground(args.vg);
drawOutputJacksArea(args.vg, numIO);
setupTextLines(args.vg);

if (numIO == 2)
{
@@ -560,7 +252,7 @@ struct HostAudioWidget : ModuleWidget {
}
}

ModuleWidget::draw(args);
ModuleWidgetWith8HP::draw(args);
}

void appendContextMenu(Menu* const menu) override {


+ 9
- 37
plugins/Cardinal/src/HostCV.cpp View File

@@ -16,6 +16,7 @@
*/

#include "plugincontext.hpp"
#include "ModuleWidgets.hpp"

#define CARDINAL_AUDIO_IO_OFFSET 8

@@ -98,54 +99,25 @@ struct HostCV : Module {
}
};

struct HostCVWidget : ModuleWidget {
static constexpr const float startX_In = 14.0f;
static constexpr const float startX_Out = 81.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.35f;

struct HostCVWidget : ModuleWidgetWith8HP {
HostCVWidget(HostCV* const module)
{
setModule(module);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostCV.svg")));

addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
setSideScrews();

for (uint i=0; i<HostCV::NUM_INPUTS; ++i)
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * i), module, i));
createAndAddInput(i);

for (uint i=0; i<HostCV::NUM_OUTPUTS; ++i)
addOutput(createOutput<PJ301MPort>(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);
createAndAddOutput(i);
}

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);

nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * HostCV::NUM_INPUTS, 4);
nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0));
nvgFill(args.vg);
drawBackground(args.vg);
drawOutputJacksArea(args.vg, HostCV::NUM_INPUTS);
setupTextLines(args.vg);

drawTextLine(args.vg, 0, "CV 1");
drawTextLine(args.vg, 1, "CV 2");
@@ -158,7 +130,7 @@ struct HostCVWidget : ModuleWidget {
drawTextLine(args.vg, 8, "CV 9");
drawTextLine(args.vg, 9, "CV 10");

ModuleWidget::draw(args);
ModuleWidgetWith8HP::draw(args);
}

void appendContextMenu(ui::Menu* const menu) override


+ 1
- 0
plugins/Cardinal/src/HostMIDI-CC.cpp View File

@@ -26,6 +26,7 @@
*/

#include "plugincontext.hpp"
#include "Widgets.hpp"

#include <algorithm>



+ 1
- 0
plugins/Cardinal/src/HostMIDI-Gate.cpp View File

@@ -26,6 +26,7 @@
*/

#include "plugincontext.hpp"
#include "Widgets.hpp"

#include <algorithm>



+ 1
- 0
plugins/Cardinal/src/HostMIDI-Map.cpp View File

@@ -26,6 +26,7 @@
*/

#include "plugincontext.hpp"
#include "Widgets.hpp"

#include <algorithm>



+ 27
- 55
plugins/Cardinal/src/HostMIDI.cpp View File

@@ -26,6 +26,7 @@
*/

#include "plugincontext.hpp"
#include "ModuleWidgets.hpp"

#include <algorithm>

@@ -661,13 +662,7 @@ struct HostMIDI : Module {

// --------------------------------------------------------------------------------------------------------------------

struct HostMIDIWidget : 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.35f;

struct HostMIDIWidget : ModuleWidgetWith9HP {
HostMIDI* const module;

HostMIDIWidget(HostMIDI* const m)
@@ -675,57 +670,34 @@ struct HostMIDIWidget : ModuleWidget {
{
setModule(m);
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/HostMIDI.svg")));

addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));

addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 0), m, HostMIDI::PITCH_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 1), m, HostMIDI::GATE_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 2), m, HostMIDI::VELOCITY_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 3), m, HostMIDI::AFTERTOUCH_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 4), m, HostMIDI::PITCHBEND_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 5), m, HostMIDI::MODWHEEL_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 6), m, HostMIDI::START_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 7), m, HostMIDI::STOP_INPUT));
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * 8), m, HostMIDI::CONTINUE_INPUT));

addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 0), m, HostMIDI::PITCH_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 1), m, HostMIDI::GATE_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 2), m, HostMIDI::VELOCITY_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 3), m, HostMIDI::AFTERTOUCH_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 4), m, HostMIDI::PITCHBEND_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 5), m, HostMIDI::MODWHEEL_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 6), m, HostMIDI::START_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 7), m, HostMIDI::STOP_OUTPUT));
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * 8), m, HostMIDI::CONTINUE_OUTPUT));
}

void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text)
{
const float y = startY + posY * padding;
nvgBeginPath(vg);
nvgFillColor(vg, color::WHITE);
nvgText(vg, middleX, y + 16, text, nullptr);
setSideScrews();

createAndAddInput(0, HostMIDI::PITCH_INPUT);
createAndAddInput(1, HostMIDI::GATE_INPUT);
createAndAddInput(2, HostMIDI::VELOCITY_INPUT);
createAndAddInput(3, HostMIDI::AFTERTOUCH_INPUT);
createAndAddInput(4, HostMIDI::PITCHBEND_INPUT);
createAndAddInput(5, HostMIDI::MODWHEEL_INPUT);
createAndAddInput(6, HostMIDI::START_INPUT);
createAndAddInput(7, HostMIDI::STOP_INPUT);
createAndAddInput(8, HostMIDI::CONTINUE_INPUT);

createAndAddOutput(0, HostMIDI::PITCH_OUTPUT);
createAndAddOutput(1, HostMIDI::GATE_OUTPUT);
createAndAddOutput(2, HostMIDI::VELOCITY_OUTPUT);
createAndAddOutput(3, HostMIDI::AFTERTOUCH_OUTPUT);
createAndAddOutput(4, HostMIDI::PITCHBEND_OUTPUT);
createAndAddOutput(5, HostMIDI::MODWHEEL_OUTPUT);
createAndAddOutput(6, HostMIDI::START_OUTPUT);
createAndAddOutput(7, HostMIDI::STOP_OUTPUT);
createAndAddOutput(8, HostMIDI::CONTINUE_OUTPUT);
}

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);

nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * 9, 4);
nvgFillColor(args.vg, nvgRGB(0xd0, 0xd0, 0xd0));
nvgFill(args.vg);
drawBackground(args.vg);
drawOutputJacksArea(args.vg, 9);
setupTextLines(args.vg);

drawTextLine(args.vg, 0, "V/Oct");
drawTextLine(args.vg, 1, "Gate");
@@ -737,7 +709,7 @@ struct HostMIDIWidget : ModuleWidget {
drawTextLine(args.vg, 7, "Stop");
drawTextLine(args.vg, 8, "Cont");

ModuleWidget::draw(args);
ModuleWidgetWith9HP::draw(args);
}

void appendContextMenu(Menu* const menu) override


+ 1
- 1
plugins/Cardinal/src/HostTime.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Cardinal Plugin
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* 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


+ 1
- 1
plugins/Cardinal/src/ImGuiWidget.hpp View File

@@ -17,7 +17,7 @@

#pragma once

#include "plugin.hpp"
#include "Widgets.hpp"
#include "DearImGui/imgui.h"

struct ImGuiWidget : OpenGlWidgetWithBrowserPreview {


+ 90
- 0
plugins/Cardinal/src/ModuleWidgets.hpp View File

@@ -0,0 +1,90 @@
/*
* 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.
*/

#pragma once

#include "rack.hpp"

#ifdef NDEBUG
# undef DEBUG
#endif

using namespace rack;

template<int startX_Out>
struct ModuleWidgetWithSideScrews : ModuleWidget {
static constexpr const float startX_In = 14.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.35f;

void setSideScrews() {
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewBlack>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
}

void setupTextLines(NVGcontext* const vg) {
nvgBeginPath(vg);
nvgRect(vg, startX_Out - 2.5f, startY - 2.0f, padding, padding);
nvgFontFaceId(vg, 0);
nvgFontSize(vg, 11);
nvgTextAlign(vg, NVG_ALIGN_CENTER);
}

void createAndAddInput(const uint paramId) {
createAndAddInput(paramId, paramId);
}

void createAndAddInput(const uint posY, const uint paramId) {
addInput(createInput<PJ301MPort>(Vec(startX_In, startY + padding * posY), module, paramId));
}

void createAndAddOutput(const uint paramId) {
createAndAddOutput(paramId, paramId);
}

void createAndAddOutput(const uint posY, const uint paramId) {
addOutput(createOutput<PJ301MPort>(Vec(startX_Out, startY + padding * posY), module, paramId));
}

void drawBackground(NVGcontext* const vg) {
nvgBeginPath(vg);
nvgRect(vg, 0, 0, box.size.x, box.size.y);
nvgFillPaint(vg, nvgLinearGradient(vg, 0, 0, 0, box.size.y,
nvgRGB(0x18, 0x19, 0x19), nvgRGB(0x21, 0x22, 0x22)));
nvgFill(vg);
}

void drawOutputJacksArea(NVGcontext* const vg, const int numOutputs) {
nvgBeginPath(vg);
nvgRoundedRect(vg, startX_Out - 2.5f, startY - 2.0f, padding, padding * numOutputs, 4);
nvgFillColor(vg, nvgRGB(0xd0, 0xd0, 0xd0));
nvgFill(vg);
}

void drawTextLine(NVGcontext* const vg, const uint posY, const char* const text) {
const float y = startY + posY * padding;
nvgBeginPath(vg);
nvgFillColor(vg, color::WHITE);
nvgText(vg, middleX, y + 16, text, nullptr);
}
};

typedef ModuleWidgetWithSideScrews<81> ModuleWidgetWith8HP;
typedef ModuleWidgetWithSideScrews<96> ModuleWidgetWith9HP;

+ 398
- 0
plugins/Cardinal/src/Widgets.hpp View File

@@ -0,0 +1,398 @@
/*
* 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.
*/

#pragma once

#include "rack.hpp"

#ifdef NDEBUG
# undef DEBUG
#endif

using namespace rack;

struct CardinalLedDisplayChoice : LedDisplayChoice {
bool alignTextCenter = true;

CardinalLedDisplayChoice(const char* const label = nullptr)
{
color = nvgRGBf(0.76f, 0.11f, 0.22f);
textOffset.y -= 4;

if (label != nullptr)
text = label;
}

void drawLayer(const DrawArgs& args, const int layer) override
{
if (layer == 1)
{
nvgFillColor(args.vg, color);
nvgTextLetterSpacing(args.vg, 0.0f);

if (alignTextCenter)
{
nvgTextAlign(args.vg, NVG_ALIGN_CENTER);
nvgText(args.vg, box.size.x * 0.5f, textOffset.y, text.c_str(), nullptr);
}
else
{
nvgTextAlign(args.vg, NVG_ALIGN_LEFT);
nvgText(args.vg, textOffset.x, textOffset.y, text.c_str(), nullptr);
}
}

Widget::drawLayer(args, layer);
}
};

struct NanoKnob : Knob {
static const int ringSize = 4;

std::string displayLabel = "Level";
std::string displayString = "0 dB";
float normalizedValue = 0.5f;

NanoKnob()
{
box.size = Vec(100, 100);
}

void drawLayer(const DrawArgs& args, int layer) override
{
if (layer != 1)
return Knob::drawLayer(args, layer);

const float w = box.size.x;
const float h = box.size.y;

const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize;

const int knobStartX = w / 2 - knobSize / 2;
const int knobStartY = ringSize;
const int knobCenterX = knobStartX + knobSize / 2;
const int knobCenterY = knobStartY + knobSize / 2;

const NVGcolor testing = nvgRGBf(0.76f, 0.11f, 0.22f);

nvgLineCap(args.vg, NVG_ROUND);

// outer ring value
nvgBeginPath(args.vg);
nvgArc(args.vg,
knobCenterX,
knobCenterY,
knobSize / 2 + ringSize / 2 + 1,
nvgDegToRad(135.0f),
nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue),
NVG_CW);
nvgStrokeWidth(args.vg, ringSize);
nvgStrokeColor(args.vg, testing);
nvgStroke(args.vg);

// simulate color bleeding
nvgBeginPath(args.vg);
nvgArc(args.vg,
knobCenterX,
knobCenterY,
knobSize / 2 - 3,
nvgDegToRad(135.0f),
nvgDegToRad(135.0f) + nvgDegToRad(270.0f * normalizedValue),
NVG_CW);
nvgStrokeWidth(args.vg, 5);
nvgStrokeColor(args.vg, nvgRGBAf(testing.r, testing.g, testing.b, 0.1f));
nvgStroke(args.vg);

// line indicator
nvgStrokeWidth(args.vg, 2);
nvgSave(args.vg);
nvgTranslate(args.vg, knobCenterX, knobCenterY);
nvgRotate(args.vg, nvgDegToRad(45.0f) + normalizedValue * nvgDegToRad(270.0f));
nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, -2, knobSize / 2 - 9, 2, 6, 1);
nvgClosePath(args.vg);
nvgFillColor(args.vg, nvgRGBf(1.0f, 1.0f, 1.0f));
nvgFill(args.vg);
nvgRestore(args.vg);

// adjusted from VCVRack's LightWidget.cpp
if (const float halo = settings::haloBrightness)
{
float radius = knobSize * 0.5f;
float oradius = radius + std::min(radius * 4.f, 15.f);

NVGcolor icol = color::mult(nvgRGBAf(testing.r, testing.g, testing.b, 0.2f), halo);
NVGcolor ocol = nvgRGBA(0, 0, 0, 0);
NVGpaint paint = nvgRadialGradient(args.vg, knobCenterX, knobCenterY, radius, oradius, icol, ocol);

nvgBeginPath(args.vg);
nvgRect(args.vg, knobCenterX - oradius, knobCenterY - oradius, 2 * oradius, 2 * oradius);
nvgFillPaint(args.vg, paint);
nvgFill(args.vg);
}

// bottom label (value)
bndIconLabelValue(args.vg, 0, knobSize + ringSize, w, BND_WIDGET_HEIGHT, -1,
testing, BND_CENTER,
BND_LABEL_FONT_SIZE, displayString.c_str(), nullptr);

Knob::drawLayer(args, layer);
}

void draw(const DrawArgs& args) override
{
if (engine::ParamQuantity* const pq = getParamQuantity())
normalizedValue = pq->getScaledValue();

const float w = box.size.x;
const float h = box.size.y;

const int knobSize = std::min(w, h - BND_WIDGET_HEIGHT * 2) - ringSize;

const int knobStartX = w / 2 - knobSize / 2;
const int knobStartY = ringSize;
const int knobCenterX = knobStartX + knobSize / 2;
const int knobCenterY = knobStartY + knobSize / 2;

// knob
NVGcolor shade_top;
NVGcolor shade_down;
BNDwidgetState state;
if (APP->event->getDraggedWidget() == this)
state = BND_ACTIVE;
else if (APP->event->getHoveredWidget() == this)
state = BND_HOVER;
else
state = BND_DEFAULT;
bndInnerColors(&shade_top, &shade_down, &bndGetTheme()->optionTheme, state, 0);

// inner fill
nvgBeginPath(args.vg);
nvgCircle(args.vg, knobCenterX, knobCenterY, knobSize / 2);
nvgFillPaint(args.vg, nvgLinearGradient(args.vg,
knobStartX,
knobStartY,
knobStartX,
knobStartY + knobSize,
shade_top,
shade_down));
nvgFill(args.vg);

// inner fill border (inner)
nvgBeginPath(args.vg);
nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2 - 1, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW);
nvgClosePath(args.vg);
nvgStrokeWidth(args.vg, 1);
nvgStrokeColor(args.vg, nvgRGBAf(0.5f, 0.5f, 0.5f, 0.4f));
nvgStroke(args.vg);

// inner fill border (outer)
nvgBeginPath(args.vg);
nvgArc(args.vg, knobCenterX, knobCenterY, knobSize / 2, nvgDegToRad(0.0f), nvgDegToRad(360.0f), NVG_CCW);
nvgClosePath(args.vg);
nvgStrokeWidth(args.vg, 1);
nvgStrokeColor(args.vg, nvgRGBAf(0.0f, 0.0f, 0.0f, 0.4f));
nvgStroke(args.vg);

nvgLineCap(args.vg, NVG_ROUND);

// outer ring background
nvgBeginPath(args.vg);
nvgArc(args.vg,
knobCenterX,
knobCenterY,
knobSize / 2 + ringSize / 2 + 1,
nvgDegToRad(135.0f),
nvgDegToRad(45.0f),
NVG_CW);
nvgStrokeWidth(args.vg, ringSize);
nvgStrokeColor(args.vg, nvgRGBf(0.5f, 0.5f, 0.5f));
nvgStroke(args.vg);

// bottom label (name)
bndIconLabelValue(args.vg, 0, knobStartY + knobSize + BND_WIDGET_HEIGHT * 0.75f, w, BND_WIDGET_HEIGHT, -1,
SCHEME_WHITE, BND_CENTER,
BND_LABEL_FONT_SIZE, displayLabel.c_str(), nullptr);

Knob::draw(args);
}

void onChange(const ChangeEvent&) override
{
engine::ParamQuantity* const pq = getParamQuantity();
DISTRHO_SAFE_ASSERT_RETURN(pq != nullptr,);

displayLabel = pq->getLabel();
displayString = pq->getDisplayValueString() + pq->getUnit();
}
};

struct NanoMeter : Widget {
float gainMeterL = 0.0f;
float gainMeterR = 0.0f;

virtual void updateMeters() = 0;

void drawLayer(const DrawArgs& args, int layer) override
{
if (layer != 1)
return;

const float usableHeight = box.size.y - 10.0f;

// draw background
nvgBeginPath(args.vg);
nvgRect(args.vg,
0,
0,
box.size.x,
usableHeight);
nvgFillColor(args.vg, nvgRGB(26, 26, 26));
nvgFill(args.vg);

nvgFillColor(args.vg, nvgRGBAf(0.76f, 0.11f, 0.22f, 0.5f));
nvgStrokeColor(args.vg, nvgRGBf(0.76f, 0.11f, 0.22f));

updateMeters();

const float heightL = 1.0f + std::sqrt(gainMeterL) * (usableHeight - 1.0f);
nvgBeginPath(args.vg);
nvgRect(args.vg, 0.0f, usableHeight - heightL, box.size.x * 0.5f - 1.0f, heightL);
nvgFill(args.vg);
nvgStroke(args.vg);

const float heightR = 1.0f + std::sqrt(gainMeterR) * (usableHeight - 1.0f);
nvgBeginPath(args.vg);
nvgRect(args.vg, box.size.x * 0.5f + 1.0f, usableHeight - heightR, box.size.x * 0.5f - 2.0f, heightR);
nvgFill(args.vg);
nvgStroke(args.vg);

nvgLineCap(args.vg, NVG_ROUND);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 2.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 11.0f, usableHeight + 2.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 4.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 16.0f, usableHeight + 4.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 6.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 19.0f, usableHeight + 6.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 8.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 22.0f, usableHeight + 8.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 10.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 24.0f, usableHeight + 10.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, 0.0f, usableHeight + 12.0f);
nvgLineTo(args.vg, box.size.x * 0.5f - 26.0f, usableHeight + 12.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 10.0f, usableHeight + 2.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 2.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 15.0f, usableHeight + 4.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 4.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 18.0f, usableHeight + 6.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 6.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 20.0f, usableHeight + 8.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 8.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 22.0f, usableHeight + 10.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 10.0f);
nvgStroke(args.vg);

nvgBeginPath(args.vg);
nvgMoveTo(args.vg, box.size.x * 0.5f + 24.0f, usableHeight + 12.0f);
nvgLineTo(args.vg, box.size.x - 1.0f, usableHeight + 12.0f);
nvgStroke(args.vg);
}
};

struct OpenGlWidgetWithBrowserPreview : OpenGlWidget {
NVGLUframebuffer* fb = nullptr;

void draw(const DrawArgs& args) override
{
if (args.fb == nullptr)
return OpenGlWidget::draw(args);

// set oversample to current scale
float trans[6];
nvgCurrentTransform(args.vg, trans);
oversample = std::max(1.0f, trans[0]);

// recreate framebuffer
deleteFramebuffer();
fb = nvgluCreateFramebuffer(args.vg, box.size.x * oversample, box.size.y * oversample, 0);
DISTRHO_SAFE_ASSERT_RETURN(fb != nullptr,);

// draw our special framebuffer
nvgluBindFramebuffer(fb);
drawFramebufferForBrowserPreview();

// reset to regular framebuffer
nvgluBindFramebuffer(args.fb);

// render image generated by our framebuffer
nvgBeginPath(args.vg);
nvgRect(args.vg, 0.0f, 0.0f, box.size.x, box.size.y);
NVGpaint paint = nvgImagePattern(args.vg,
0.0f, 0.0f, box.size.x, box.size.y,
0.0f, fb->image, 1.0f);
nvgFillPaint(args.vg, paint);
nvgFill(args.vg);
}

void onContextDestroy(const ContextDestroyEvent& e) override
{
deleteFramebuffer();
OpenGlWidget::onContextDestroy(e);
}

void deleteFramebuffer()
{
if (fb == nullptr)
return;
nvgluDeleteFramebuffer(fb);
fb = nullptr;
}

virtual void drawFramebufferForBrowserPreview() = 0;
};

+ 1
- 0
plugins/Cardinal/src/glBars.cpp View File

@@ -17,6 +17,7 @@

#ifndef HEADLESS
# include "glBars.hpp"
# include "Widgets.hpp"
#else
# include "plugin.hpp"
#endif


+ 0
- 89
plugins/Cardinal/src/plugin.hpp View File

@@ -25,95 +25,6 @@

using namespace rack;

#ifndef HEADLESS
struct CardinalLedDisplayChoice : LedDisplayChoice {
bool alignTextCenter = true;

CardinalLedDisplayChoice(const char* const label = nullptr)
{
color = nvgRGBf(0.76f, 0.11f, 0.22f);
textOffset.y -= 4;

if (label != nullptr)
text = label;
}

void drawLayer(const DrawArgs& args, const int layer) override
{
if (layer == 1)
{
nvgFillColor(args.vg, color);
nvgTextLetterSpacing(args.vg, 0.0f);

if (alignTextCenter)
{
nvgTextAlign(args.vg, NVG_ALIGN_CENTER);
nvgText(args.vg, box.size.x * 0.5f, textOffset.y, text.c_str(), nullptr);
}
else
{
nvgTextAlign(args.vg, NVG_ALIGN_LEFT);
nvgText(args.vg, textOffset.x, textOffset.y, text.c_str(), nullptr);
}
}

Widget::drawLayer(args, layer);
}
};

struct OpenGlWidgetWithBrowserPreview : OpenGlWidget {
NVGLUframebuffer* fb = nullptr;

void draw(const DrawArgs& args) override
{
if (args.fb == nullptr)
return OpenGlWidget::draw(args);

// set oversample to current scale
float trans[6];
nvgCurrentTransform(args.vg, trans);
oversample = std::max(1.0f, trans[0]);

// recreate framebuffer
deleteFramebuffer();
fb = nvgluCreateFramebuffer(args.vg, box.size.x * oversample, box.size.y * oversample, 0);
DISTRHO_SAFE_ASSERT_RETURN(fb != nullptr,);

// draw our special framebuffer
nvgluBindFramebuffer(fb);
drawFramebufferForBrowserPreview();

// reset to regular framebuffer
nvgluBindFramebuffer(args.fb);

// render image generated by our framebuffer
nvgBeginPath(args.vg);
nvgRect(args.vg, 0.0f, 0.0f, box.size.x, box.size.y);
NVGpaint paint = nvgImagePattern(args.vg,
0.0f, 0.0f, box.size.x, box.size.y,
0.0f, fb->image, 1.0f);
nvgFillPaint(args.vg, paint);
nvgFill(args.vg);
}

void onContextDestroy(const ContextDestroyEvent& e) override
{
deleteFramebuffer();
OpenGlWidget::onContextDestroy(e);
}

void deleteFramebuffer()
{
if (fb == nullptr)
return;
nvgluDeleteFramebuffer(fb);
fb = nullptr;
}

virtual void drawFramebufferForBrowserPreview() = 0;
};
#endif

extern Plugin* pluginInstance;

extern Model* modelAudioFile;


Loading…
Cancel
Save