Skip to content

Commit

Permalink
Panic Menu Item; Input and Output Attenuators (#32)
Browse files Browse the repository at this point in the history
1. Add a "Panic Reset" menu item which resets the effect
   to blank
2. Add input and output attenuators

Addresses #16
  • Loading branch information
baconpaul authored Apr 24, 2024
1 parent f4b0efe commit 96384fe
Showing 1 changed file with 134 additions and 31 deletions.
165 changes: 134 additions & 31 deletions src/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne

std::unique_ptr<Airwin2RackBase> airwin{}, airwin_display{};
std::array<std::unique_ptr<Airwin2RackBase>, MAX_POLY> poly_airwin;
std::atomic<int32_t> forceSelect{-1}, resetCount{0};
std::atomic<int32_t> forceSelect{-1}, resetCount{0}, selectedIdx{-1};
std::atomic<bool> panicReset;
std::string selectedFX{}, selectedWhat{}, selectedCat{};

struct AWParamQuantity : public rack::ParamQuantity
Expand Down Expand Up @@ -84,7 +85,10 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
PARAM_0,
MAX_PARAMS_USED_TO_BE_11_DONT_BREAK_FOLKS = PARAM_0 + maxParams,
ATTENUVERTER_0,
NUM_PARAMS = ATTENUVERTER_0 + maxParams
MAX_PARAMS_USED_TO_BE_11_DONT_BREAK_ATTENS = ATTENUVERTER_0 + maxParams,
IN_LEVEL,
OUT_LEVEL,
NUM_PARAMS
};

enum InputIds
Expand Down Expand Up @@ -136,6 +140,10 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
configBypass(INPUT_R, OUTPUT_R);

configParam(MAX_PARAMS_USED_TO_BE_11_DONT_BREAK_FOLKS, 0, 1, 0, "Unused");
configParam(MAX_PARAMS_USED_TO_BE_11_DONT_BREAK_ATTENS, 0, 1, 0, "Unused");

configParam(IN_LEVEL, 0, 1, 1, "Input Gain", "%", 0, 100);
configParam(OUT_LEVEL, 0, 1, 1, "Output Gain", "%", 0, 100);

for (int i = 0; i < maxParams; ++i)
{
Expand Down Expand Up @@ -176,6 +184,7 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne

void resetAirwindowTo(int registryIdx, bool resetValues = true)
{
selectedIdx = registryIdx;
selectedFX = AirwinRegistry::registry[registryIdx].name;
selectedCat = AirwinRegistry::registry[registryIdx].category;
selectedWhat = AirwinRegistry::registry[registryIdx].whatText;
Expand Down Expand Up @@ -242,10 +251,7 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
p->setSampleRate(sr);
}

void onSampleRateChange(const SampleRateChangeEvent &e) override
{
updateSampleRates();
}
void onSampleRateChange(const SampleRateChangeEvent &e) override { updateSampleRates(); }

json_t *dataToJson() override
{
Expand Down Expand Up @@ -353,6 +359,11 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
resetAirwindowTo(forceSelect);
forceSelect = -1;
}
if (panicReset && selectedIdx >= 0)
{
resetAirwindowTo(selectedIdx, false);
panicReset = false;
}
if (forceBlockSize != -1)
{
blockSize = forceBlockSize;
Expand Down Expand Up @@ -389,25 +400,29 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
void processMono(const ProcessArgs &args, bool inputIsMixmaster)
{
auto rc = inputs[INPUT_R].isConnected() ? INPUT_R : INPUT_L;

auto ig = params[IN_LEVEL].getValue();
auto og = params[OUT_LEVEL].getValue();

if (inputIsMixmaster)
{
monoIO.in[0][monoIO.inPos] = 0;
monoIO.in[1][monoIO.inPos] = 0;
for (int c = 0; c < inputs[INPUT_L].getChannels(); c += 2)
{
monoIO.in[0][monoIO.inPos] += inputs[INPUT_L].getVoltage(c) * 0.2;
monoIO.in[1][monoIO.inPos] += inputs[INPUT_L].getVoltage(c + 1) * 0.2;
monoIO.in[0][monoIO.inPos] += inputs[INPUT_L].getVoltage(c) * 0.2 * ig;
monoIO.in[1][monoIO.inPos] += inputs[INPUT_L].getVoltage(c + 1) * 0.2 * ig;
}
for (int c = 0; c < inputs[INPUT_R].getChannels(); c += 2)
{
monoIO.in[0][monoIO.inPos] += inputs[INPUT_R].getVoltage(c) * 0.2;
monoIO.in[1][monoIO.inPos] += inputs[INPUT_R].getVoltage(c + 1) * 0.2;
monoIO.in[0][monoIO.inPos] += inputs[INPUT_R].getVoltage(c) * 0.2 * ig;
monoIO.in[1][monoIO.inPos] += inputs[INPUT_R].getVoltage(c + 1) * 0.2 * ig;
}
}
else
{
monoIO.in[0][monoIO.inPos] = inputs[INPUT_L].getVoltageSum() * 0.2;
monoIO.in[1][monoIO.inPos] = inputs[rc].getVoltageSum() * 0.2;
monoIO.in[0][monoIO.inPos] = inputs[INPUT_L].getVoltageSum() * 0.2 * ig;
monoIO.in[1][monoIO.inPos] = inputs[rc].getVoltageSum() * 0.2 * ig;
}
monoIO.inPos++;
if (monoIO.inPos >= blockSize)
Expand All @@ -428,8 +443,8 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
monoIO.inPos = 0;
}

outputs[OUTPUT_L].setVoltage(monoIO.out[0][monoIO.outPos] * 5);
outputs[OUTPUT_R].setVoltage(monoIO.out[1][monoIO.outPos] * 5);
outputs[OUTPUT_L].setVoltage(monoIO.out[0][monoIO.outPos] * 5 * og);
outputs[OUTPUT_R].setVoltage(monoIO.out[1][monoIO.outPos] * 5 * og);
monoIO.outPos++;
}

Expand All @@ -439,6 +454,9 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
outputs[OUTPUT_L].setChannels(chanCt);
outputs[OUTPUT_R].setChannels(chanCt);

auto ig = params[IN_LEVEL].getValue();
auto og = params[OUT_LEVEL].getValue();

auto rc = inputs[INPUT_R].isConnected() ? INPUT_R : INPUT_L;

float sv[maxParams];
Expand All @@ -455,21 +473,22 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
{
if (c < 8)
{
polyIO[c].in[0][polyIO[c].inPos] = inputs[INPUT_L].getVoltage(c * 2) * 0.2;
polyIO[c].in[1][polyIO[c].inPos] = inputs[INPUT_L].getVoltage(c * 2 + 1) * 0.2;
polyIO[c].in[0][polyIO[c].inPos] = inputs[INPUT_L].getVoltage(c * 2) * 0.2 * ig;
polyIO[c].in[1][polyIO[c].inPos] =
inputs[INPUT_L].getVoltage(c * 2 + 1) * 0.2 * ig;
}
else
{
polyIO[c].in[0][polyIO[c].inPos] =
inputs[INPUT_R].getVoltage((c - 8) * 2) * 0.2;
inputs[INPUT_R].getVoltage((c - 8) * 2) * 0.2 * ig;
polyIO[c].in[1][polyIO[c].inPos] =
inputs[INPUT_R].getVoltage((c - 8) * 2 + 1) * 0.2;
inputs[INPUT_R].getVoltage((c - 8) * 2 + 1) * 0.2 * ig;
}
}
else
{
polyIO[c].in[0][polyIO[c].inPos] = inputs[INPUT_L].getVoltage(c) * 0.2;
polyIO[c].in[1][polyIO[c].inPos] = inputs[rc].getVoltage(c) * 0.2;
polyIO[c].in[0][polyIO[c].inPos] = inputs[INPUT_L].getVoltage(c) * 0.2 * ig;
polyIO[c].in[1][polyIO[c].inPos] = inputs[rc].getVoltage(c) * 0.2 * ig;
}
polyIO[c].inPos++;
if (polyIO[c].inPos >= blockSize)
Expand All @@ -495,21 +514,23 @@ struct AW2RModule : virtual rack::Module, sst::rackhelpers::module_connector::Ne
{
if (c < 8)
{
outputs[OUTPUT_L].setVoltage(polyIO[c].out[0][polyIO[c].outPos] * 5, c * 2);
outputs[OUTPUT_L].setVoltage(polyIO[c].out[1][polyIO[c].outPos] * 5, c * 2 + 1);
outputs[OUTPUT_L].setVoltage(polyIO[c].out[0][polyIO[c].outPos] * 5 * og,
c * 2);
outputs[OUTPUT_L].setVoltage(polyIO[c].out[1][polyIO[c].outPos] * 5 * og,
c * 2 + 1);
}
else
{
outputs[OUTPUT_R].setVoltage(polyIO[c].out[0][polyIO[c].outPos] * 5,
outputs[OUTPUT_R].setVoltage(polyIO[c].out[0][polyIO[c].outPos] * 5 * og,
(c - 8) * 2);
outputs[OUTPUT_R].setVoltage(polyIO[c].out[1][polyIO[c].outPos] * 5,
outputs[OUTPUT_R].setVoltage(polyIO[c].out[1][polyIO[c].outPos] * 5 * og,
(c - 8) * 2 + 1);
}
}
else
{
outputs[OUTPUT_L].setVoltage(polyIO[c].out[0][polyIO[c].outPos] * 5, c);
outputs[OUTPUT_R].setVoltage(polyIO[c].out[1][polyIO[c].outPos] * 5, c);
outputs[OUTPUT_L].setVoltage(polyIO[c].out[0][polyIO[c].outPos] * 5 * og, c);
outputs[OUTPUT_R].setVoltage(polyIO[c].out[1][polyIO[c].outPos] * 5 * og, c);
}
polyIO[c].outPos++;
}
Expand Down Expand Up @@ -842,6 +863,72 @@ template <int px, bool bipolar = false> struct PixelKnob : rack::Knob
}
};

struct AttenSlider : rack::Knob
{
sst::rackhelpers::ui::BufferedDrawFunctionWidget *bdw{nullptr};
AttenSlider() {}

static AttenSlider *create(const rack::Vec &pos, int w, AW2RModule *module, int paramId)
{
auto res = new AttenSlider();
res->module = module;
res->paramId = paramId;
res->box.size = rack::Vec(w, 6);
res->box.pos = pos;
res->bdw = new sst::rackhelpers::ui::BufferedDrawFunctionWidget(
rack::Vec(0, 0), res->box.size, [res](auto vg) { res->drawSlider(vg); });
res->addChild(res->bdw);
return res;
}

void drawSlider(NVGcontext *vg)
{
nvgBeginPath(vg);
nvgFillColor(vg, awSkin.knobCenter());
nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 2);
nvgFill(vg);

float val{1.f};
if (getParamQuantity())
val = std::clamp(getParamQuantity()->getValue(), 0.f, 1.f);
nvgSave(vg);
nvgScissor(vg, 0, 0, box.size.x * val, box.size.y);
nvgBeginPath(vg);
nvgFillColor(vg, awSkin.knobValueFill());
nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 2);
nvgFill(vg);
nvgRestore(vg);

nvgBeginPath(vg);
nvgStrokeColor(vg, awSkin.knobStroke());
nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 2);
nvgStroke(vg);
}

AWSkin::Skin lastSkin{AWSkin::DARK};
float lastVal{0.f};
void step() override
{
bool dirty{false};
if (lastSkin != awSkin.skin)
dirty = true;
lastSkin = awSkin.skin;

auto pq = getParamQuantity();
if (pq)
{
if (lastVal != pq->getValue())
dirty = true;
lastVal = pq->getValue();
}

if (bdw && dirty)
bdw->dirty = dirty;

rack::Knob::step();
}
};

struct AWLabel : rack::Widget
{
float px{11};
Expand Down Expand Up @@ -1537,7 +1624,7 @@ struct AW2RModuleWidget : rack::ModuleWidget
pPos += dPP;
}

auto q = RACK_HEIGHT - 42;
auto q = RACK_HEIGHT - 42 - 9;
auto c1 = box.size.x * 0.25;
auto dc = box.size.x * 0.11;
auto c2 = box.size.x * 0.75;
Expand All @@ -1562,6 +1649,15 @@ struct AW2RModuleWidget : rack::ModuleWidget
addInput(inr);
addOutput(outl);
addOutput(outr);

auto w = box.size.x * 0.5 - 16;
auto inAt = AttenSlider::create(rack::Vec(8, q + 24), w, m, M::IN_LEVEL);
addParam(inAt);
auto outAt =
AttenSlider::create(rack::Vec(8 + box.size.x * 0.5, q + 24), w, m, M::OUT_LEVEL);
addParam(outAt);

// Add sliders here
}

~AW2RModuleWidget()
Expand Down Expand Up @@ -1597,13 +1693,20 @@ struct AW2RModuleWidget : rack::ModuleWidget
}
void appendContextMenu(rack::Menu *menu) override
{
auto awm = dynamic_cast<AW2RModule *>(module);
menu->addChild(new rack::MenuSeparator);
menu->addChild(rack::createMenuItem("Panic Reset", "", [awm]() {
if (awm)
{
awm->panicReset = true;
}
}));
menu->addChild(new rack::MenuSeparator);
menu->addChild(rack::createMenuItem("Light Mode", CHECKMARK(awSkin.skin == AWSkin::LIGHT),
[]() { awSkin.changeTo(AWSkin::LIGHT, true); }));
menu->addChild(rack::createMenuItem("Dark Mode", CHECKMARK(awSkin.skin == AWSkin::DARK),
[]() { awSkin.changeTo(AWSkin::DARK, true); }));

auto awm = dynamic_cast<AW2RModule *>(module);
if (awm)
{
menu->addChild(new rack::MenuSeparator);
Expand Down Expand Up @@ -1873,7 +1976,7 @@ struct AW2RModuleWidget : rack::ModuleWidget

void drawBG(NVGcontext *vg)
{
auto cutPoint{58};
auto cutPoint{67};

// Main Gradient Background
nvgBeginPath(vg);
Expand All @@ -1899,7 +2002,7 @@ struct AW2RModuleWidget : rack::ModuleWidget
nvgStrokeColor(vg, awSkin.panelInputBorder());
nvgFillColor(vg, awSkin.panelInputFill());
nvgStrokeWidth(vg, 1);
nvgRoundedRect(vg, 4, box.size.y - cutPoint + 3, box.size.x * 0.5 - 8, 37, 2);
nvgRoundedRect(vg, 4, box.size.y - cutPoint + 3, box.size.x * 0.5 - 8, 37 + 9, 2);
nvgFill(vg);
nvgStroke(vg);

Expand Down Expand Up @@ -1934,7 +2037,7 @@ struct AW2RModuleWidget : rack::ModuleWidget
nvgFillColor(vg, awSkin.panelOutputFill());
nvgStrokeWidth(vg, 1);
nvgRoundedRect(vg, box.size.x * 0.5 + 4, box.size.y - cutPoint + 3, box.size.x * 0.5 - 8,
37, 2);
37 + 9, 2);
nvgFill(vg);
nvgStroke(vg);

Expand Down

0 comments on commit 96384fe

Please sign in to comment.