Browse Source

Fix backward compatibility and components.

tags/v2.0.1
Andrew Belt 3 years ago
parent
commit
76ff24c4f7
8 changed files with 408 additions and 2688 deletions
  1. +171
    -2496
      res/VCA-1.svg
  2. +14
    -14
      src/MidSide.cpp
  3. +1
    -1
      src/Octave.cpp
  4. +27
    -7
      src/Quantizer.cpp
  5. +26
    -12
      src/SequentialSwitch.cpp
  6. +168
    -0
      src/VCA-1.cpp
  7. +0
    -157
      src/VCA.cpp
  8. +1
    -1
      src/WTLFO.cpp

+ 171
- 2496
res/VCA-1.svg
File diff suppressed because it is too large
View File


+ 14
- 14
src/MidSide.cpp View File

@@ -97,20 +97,20 @@ struct MidSideWidget : ModuleWidget {
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));


addParam(createParamCentered<RoundSmallBlackKnob>(mm2px(Vec(18.699, 26.234)), module, MidSide::ENC_WIDTH_PARAM));
addParam(createParamCentered<RoundSmallBlackKnob>(mm2px(Vec(18.699, 81.235)), module, MidSide::DEC_WIDTH_PARAM));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.699, 26.234)), module, MidSide::ENC_WIDTH_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.699, 41.234)), module, MidSide::ENC_LEFT_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.699, 41.234)), module, MidSide::ENC_RIGHT_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.699, 81.234)), module, MidSide::DEC_WIDTH_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.699, 96.234)), module, MidSide::DEC_MID_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.699, 96.234)), module, MidSide::DEC_SIDES_INPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(6.699, 57.253)), module, MidSide::ENC_MID_OUTPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.699, 57.253)), module, MidSide::ENC_SIDES_OUTPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(6.699, 112.252)), module, MidSide::DEC_LEFT_OUTPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.699, 112.252)), module, MidSide::DEC_RIGHT_OUTPUT));
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(7.285, 25.203)), module, MidSide::ENC_WIDTH_PARAM));
addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(7.285, 80.583)), module, MidSide::DEC_WIDTH_PARAM));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.122, 25.142)), module, MidSide::ENC_WIDTH_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.285, 41.373)), module, MidSide::ENC_LEFT_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.122, 41.373)), module, MidSide::ENC_RIGHT_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.122, 80.603)), module, MidSide::DEC_WIDTH_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.285, 96.859)), module, MidSide::DEC_MID_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.122, 96.859)), module, MidSide::DEC_SIDES_INPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.285, 57.679)), module, MidSide::ENC_MID_OUTPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.122, 57.679)), module, MidSide::ENC_SIDES_OUTPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.285, 113.115)), module, MidSide::DEC_LEFT_OUTPUT));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.122, 113.115)), module, MidSide::DEC_RIGHT_OUTPUT));
} }
}; };




+ 1
- 1
src/Octave.cpp View File

@@ -167,7 +167,7 @@ struct OctaveWidget : ModuleWidget {


addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.62, 113.115)), module, Octave::PITCH_OUTPUT)); addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.62, 113.115)), module, Octave::PITCH_OUTPUT));


OctaveDisplay* display = createWidget<OctaveDisplay>(mm2px(Vec(-0.011, 13.039)));
OctaveDisplay* display = createWidget<OctaveDisplay>(mm2px(Vec(0.0, 13.039)));
display->box.size = mm2px(Vec(15.263, 55.88)); display->box.size = mm2px(Vec(15.263, 55.88));
display->setModule(module); display->setModule(module);
addChild(display); addChild(display);


+ 27
- 7
src/Quantizer.cpp View File

@@ -133,8 +133,13 @@ struct QuantizerButton : OpaqueWidget {
return; return;


const float margin = mm2px(1.5); const float margin = mm2px(1.5);
Rect r = box.zeroPos().grow(Vec(margin, margin / 2).neg());
Rect r = box.zeroPos();
nvgBeginPath(args.vg);
nvgRect(args.vg, RECT_ARGS(r));
nvgFillColor(args.vg, nvgRGB(0x12, 0x12, 0x12));
nvgFill(args.vg);


r = r.shrink(Vec(margin, margin / 2));
nvgBeginPath(args.vg); nvgBeginPath(args.vg);
nvgRect(args.vg, RECT_ARGS(r)); nvgRect(args.vg, RECT_ARGS(r));
if (module ? module->playingNotes[note] : (note == 0)) { if (module ? module->playingNotes[note] : (note == 0)) {
@@ -172,13 +177,28 @@ struct QuantizerButton : OpaqueWidget {


struct QuantizerDisplay : LedDisplay { struct QuantizerDisplay : LedDisplay {
void setModule(Quantizer* module) { void setModule(Quantizer* module) {
const float margin = mm2px(1.5) / 2;
const int notes = 12;
const float height = box.size.y - 2 * margin;
for (int note = 0; note < notes; note++) {
// White notes
static const std::vector<int> whiteNotes = {0, 2, 4, 5, 7, 9, 11};
for (size_t i = 0; i < whiteNotes.size(); i++) {
int note = whiteNotes[i];
QuantizerButton* quantizerButton = new QuantizerButton();
quantizerButton->box.pos = Vec(0, i * box.size.y / 7);
quantizerButton->box.size = Vec(box.size.x, box.size.y / 7);
quantizerButton->module = module;
quantizerButton->note = note;
addChild(quantizerButton);
}
// Black notes
static const std::vector<int> blackNotes = {1, 3, 6, 8, 10};
static const std::vector<float> blackPos = {1, 2, 4, 5, 6};
for (size_t i = 0; i < blackNotes.size(); i++) {
int note = blackNotes[i];
float height = box.size.y * 0.1f;
float width = box.size.x * 0.6f;
float pos = blackPos[i] / 7.f * box.size.y - height / 2;
QuantizerButton* quantizerButton = new QuantizerButton(); QuantizerButton* quantizerButton = new QuantizerButton();
quantizerButton->box.pos = Vec(0, margin + height / notes * note);
quantizerButton->box.size = Vec(box.size.x, height / notes);
quantizerButton->box.pos = Vec(0, pos);
quantizerButton->box.size = Vec(width, height);
quantizerButton->module = module; quantizerButton->module = module;
quantizerButton->note = note; quantizerButton->note = note;
addChild(quantizerButton); addChild(quantizerButton);


+ 26
- 12
src/SequentialSwitch.cpp View File

@@ -31,7 +31,7 @@ struct SequentialSwitch : Module {


SequentialSwitch() { SequentialSwitch() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configSwitch(STEPS_PARAM, 0.0, 2.0, 0.0, "Steps", {"4", "3", "2"});
configSwitch(STEPS_PARAM, 0.0, 2.0, 2.0, "Steps", {"2", "3", "4"});
configInput(CLOCK_INPUT, "Clock"); configInput(CLOCK_INPUT, "Clock");
configInput(RESET_INPUT, "Reset"); configInput(RESET_INPUT, "Reset");
if (INPUTS == 1) { if (INPUTS == 1) {
@@ -64,7 +64,7 @@ struct SequentialSwitch : Module {
if (resetTrigger.process(rescale(inputs[RESET_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) { if (resetTrigger.process(rescale(inputs[RESET_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
index = 0; index = 0;
} }
int length = 4 - (int) std::round(params[STEPS_PARAM].getValue());
int length = 2 + (int) std::round(params[STEPS_PARAM].getValue());
if (index >= length) if (index >= length)
index = 0; index = 0;


@@ -117,6 +117,20 @@ struct SequentialSwitch : Module {
} }
} }
} }

void fromJson(json_t* rootJ) override {
Module::fromJson(rootJ);

// Get version to check if we should transform STEPS_PARAM
json_t* versionJ = json_object_get(rootJ, "version");
if (versionJ) {
std::string version = json_string_value(versionJ);
if (string::startsWith(version, "0.") || string::startsWith(version, "1.")) {
DEBUG("steps %f", params[STEPS_PARAM].getValue());
params[STEPS_PARAM].setValue(2 - params[STEPS_PARAM].getValue());
}
}
}
}; };




@@ -132,7 +146,7 @@ struct SequentialSwitch1Widget : ModuleWidget {
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));


addParam(createParamCentered<CKSSThree>(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM));
addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM));


addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 33.831)), module, TSequentialSwitch::CLOCK_INPUT)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 50.126)), module, TSequentialSwitch::RESET_INPUT)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 50.126)), module, TSequentialSwitch::RESET_INPUT));
@@ -143,10 +157,10 @@ struct SequentialSwitch1Widget : ModuleWidget {
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 102.927)), module, TSequentialSwitch::OUT_OUTPUTS + 2)); addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 102.927)), module, TSequentialSwitch::OUT_OUTPUTS + 2));
addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 113.087)), module, TSequentialSwitch::OUT_OUTPUTS + 3)); addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 113.087)), module, TSequentialSwitch::OUT_OUTPUTS + 3));


addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0));
addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1));
addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2));
addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3));
} }
}; };


@@ -166,7 +180,7 @@ struct SequentialSwitch2Widget : ModuleWidget {
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));


addParam(createParamCentered<CKSSThree>(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM));
addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM));


addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 33.831)), module, TSequentialSwitch::CLOCK_INPUT)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 50.126)), module, TSequentialSwitch::RESET_INPUT)); addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 50.126)), module, TSequentialSwitch::RESET_INPUT));
@@ -177,10 +191,10 @@ struct SequentialSwitch2Widget : ModuleWidget {


addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.8, 113.115)), module, TSequentialSwitch::OUT_OUTPUTS + 0)); addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.8, 113.115)), module, TSequentialSwitch::OUT_OUTPUTS + 0));


addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0));
addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1));
addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2));
addChild(createLightCentered<TinyLight<RedLight>>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2));
addChild(createLightCentered<TinyLight<YellowLight>>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3));
} }
}; };




+ 168
- 0
src/VCA-1.cpp View File

@@ -0,0 +1,168 @@
#include "plugin.hpp"


struct VCA_1 : Module {
enum ParamIds {
LEVEL_PARAM,
EXP_PARAM, // removed from panel in 2.0, still in context menu
NUM_PARAMS
};
enum InputIds {
CV_INPUT,
IN_INPUT,
NUM_INPUTS
};
enum OutputIds {
OUT_OUTPUT,
NUM_OUTPUTS
};
enum LightIds {
NUM_LIGHTS
};

int lastChannels = 1;
float lastGains[16] = {};

VCA_1() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(LEVEL_PARAM, 0.0, 1.0, 1.0, "Level", "%", 0, 100);
configSwitch(EXP_PARAM, 0.0, 1.0, 1.0, "Response mode", {"Exponential", "Linear"});
configInput(CV_INPUT, "CV");
configInput(IN_INPUT, "Channel");
configOutput(OUT_OUTPUT, "Channel");
configBypass(IN_INPUT, OUT_OUTPUT);
}

void process(const ProcessArgs& args) override {
int channels = std::max(inputs[IN_INPUT].getChannels(), 1);
float level = params[LEVEL_PARAM].getValue();

for (int c = 0; c < channels; c++) {
// Get input
float in = inputs[IN_INPUT].getVoltage(c);

// Get gain
float gain = level;
if (inputs[CV_INPUT].isConnected()) {
float cv = clamp(inputs[CV_INPUT].getPolyVoltage(c) / 10.f, 0.f, 1.f);
if (int(params[EXP_PARAM].getValue()) == 0)
cv = std::pow(cv, 4.f);
gain *= cv;
}

// Apply gain
in *= gain;
lastGains[c] = gain;

// Set output
outputs[OUT_OUTPUT].setVoltage(in, c);
}

outputs[OUT_OUTPUT].setChannels(channels);
lastChannels = channels;
}
};


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

VCA_1* module = dynamic_cast<VCA_1*>(this->module);

const Vec margin = Vec(3, 3);
Rect r = box.zeroPos().grow(margin.neg());

int channels = module ? module->lastChannels : 1;
engine::ParamQuantity* pq = getParamQuantity();
float value = pq ? pq->getValue() : 1.f;

// Segment value
if (value >= 0.005f) {
nvgBeginPath(args.vg);
nvgRect(args.vg,
r.pos.x,
r.pos.y + r.size.y * (1 - value),
r.size.x,
r.size.y * value);
nvgFillColor(args.vg, color::mult(color::WHITE, 0.33));
nvgFill(args.vg);
}

// Segment gain
nvgBeginPath(args.vg);
for (int c = 0; c < channels; c++) {
float gain = module ? module->lastGains[c] : 1.f;
if (gain >= 0.005f) {
nvgRect(args.vg,
r.pos.x + r.size.x * c / channels,
r.pos.y + r.size.y * (1 - gain),
r.size.x / channels,
r.size.y * gain);
}
}
nvgFillColor(args.vg, SCHEME_GREEN);
nvgFill(args.vg);

// Invisible separators
const int segs = 25;
nvgBeginPath(args.vg);
for (int i = 1; i < segs; i++) {
nvgRect(args.vg,
r.pos.x - 1.0,
r.pos.y + r.size.y * i / segs,
r.size.x + 2.0,
1.0);
}
nvgFillColor(args.vg, color::BLACK);
nvgFill(args.vg);
}
};


struct VCA_1Display : LedDisplay {
void setModule(VCA_1* module) {
VCA_1VUKnob* knob = createParam<VCA_1VUKnob>(mm2px(Vec(0.0, 0.0)), module, VCA_1::LEVEL_PARAM);
knob->box.size = mm2px(Vec(15.263, 55.88));
addChild(knob);
}
};


struct VCA_1Widget : ModuleWidget {
VCA_1Widget(VCA_1* module) {
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/VCA-1.svg")));

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

addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.62, 80.603)), module, VCA_1::CV_INPUT));
addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.62, 96.859)), module, VCA_1::IN_INPUT));

addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.62, 113.115)), module, VCA_1::OUT_OUTPUT));

VCA_1Display* display = createWidget<VCA_1Display>(mm2px(Vec(0.0, 13.039)));
display->box.size = mm2px(Vec(15.263, 55.88));
display->setModule(module);
addChild(display);
}

void appendContextMenu(Menu* menu) override {
VCA_1* module = dynamic_cast<VCA_1*>(this->module);
assert(module);

menu->addChild(new MenuSeparator);

menu->addChild(createBoolMenuItem("Exponential response", "",
[=]() {return module->params[VCA_1::EXP_PARAM].getValue() == 0.f;},
[=](bool value) {module->params[VCA_1::EXP_PARAM].setValue(!value);}
));
}
};


Model* modelVCA_1 = createModel<VCA_1, VCA_1Widget>("VCA-1");

+ 0
- 157
src/VCA.cpp View File

@@ -133,160 +133,3 @@ struct VCAWidget : ModuleWidget {




Model* modelVCA = createModel<VCA, VCAWidget>("VCA"); Model* modelVCA = createModel<VCA, VCAWidget>("VCA");


struct VCA_1 : Module {
enum ParamIds {
LEVEL_PARAM,
EXP_PARAM,
NUM_PARAMS
};
enum InputIds {
CV_INPUT,
IN_INPUT,
NUM_INPUTS
};
enum OutputIds {
OUT_OUTPUT,
NUM_OUTPUTS
};
enum LightIds {
NUM_LIGHTS
};

int lastChannels = 1;
float lastGains[16] = {};

VCA_1() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
configParam(LEVEL_PARAM, 0.0, 1.0, 1.0, "Level", "%", 0, 100);
configSwitch(EXP_PARAM, 0.0, 1.0, 1.0, "Response mode", {"Exponential", "Linear"});
configInput(CV_INPUT, "CV");
configInput(IN_INPUT, "Channel");
configOutput(OUT_OUTPUT, "Channel");
configBypass(IN_INPUT, OUT_OUTPUT);
}

void process(const ProcessArgs& args) override {
int channels = std::max(inputs[IN_INPUT].getChannels(), 1);
float level = params[LEVEL_PARAM].getValue();

for (int c = 0; c < channels; c++) {
// Get input
float in = inputs[IN_INPUT].getVoltage(c);

// Get gain
float gain = level;
if (inputs[CV_INPUT].isConnected()) {
float cv = clamp(inputs[CV_INPUT].getPolyVoltage(c) / 10.f, 0.f, 1.f);
if (int(params[EXP_PARAM].getValue()) == 0)
cv = std::pow(cv, 4.f);
gain *= cv;
}

// Apply gain
in *= gain;
lastGains[c] = gain;

// Set output
outputs[OUT_OUTPUT].setVoltage(in, c);
}

outputs[OUT_OUTPUT].setChannels(channels);
lastChannels = channels;
}
};


struct VCA_1VUKnob : SliderKnob {
VCA_1* module = NULL;

VCA_1VUKnob() {
box.size = mm2px(Vec(10, 46));
}

void draw(const DrawArgs& args) override {
nvgBeginPath(args.vg);
nvgRoundedRect(args.vg, 0, 0, box.size.x, box.size.y, 2.0);
nvgFillColor(args.vg, nvgRGB(0, 0, 0));
nvgFill(args.vg);
}

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

const Vec margin = Vec(3, 3);
Rect r = box.zeroPos().grow(margin.neg());

int channels = module ? module->lastChannels : 1;
engine::ParamQuantity* pq = getParamQuantity();
float value = pq ? pq->getValue() : 1.f;

// Segment value
if (value >= 0.005f) {
nvgBeginPath(args.vg);
nvgRect(args.vg,
r.pos.x,
r.pos.y + r.size.y * (1 - value),
r.size.x,
r.size.y * value);
nvgFillColor(args.vg, color::mult(color::WHITE, 0.33));
nvgFill(args.vg);
}

// Segment gain
nvgBeginPath(args.vg);
for (int c = 0; c < channels; c++) {
float gain = module ? module->lastGains[c] : 1.f;
if (gain >= 0.005f) {
nvgRect(args.vg,
r.pos.x + r.size.x * c / channels,
r.pos.y + r.size.y * (1 - gain),
r.size.x / channels,
r.size.y * gain);
}
}
nvgFillColor(args.vg, SCHEME_GREEN);
nvgFill(args.vg);

// Invisible separators
const int segs = 25;
nvgBeginPath(args.vg);
for (int i = 1; i <= segs; i++) {
nvgRect(args.vg,
r.pos.x - 1.0,
r.pos.y + r.size.y * i / segs,
r.size.x + 2.0,
1.0);
}
nvgFillColor(args.vg, color::BLACK);
nvgFill(args.vg);
}
};


struct VCA_1Widget : ModuleWidget {
VCA_1Widget(VCA_1* module) {
setModule(module);
setPanel(createPanel(asset::plugin(pluginInstance, "res/VCA-1.svg")));

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

VCA_1VUKnob* levelParam = createParam<VCA_1VUKnob>(mm2px(Vec(2.62103, 12.31692)), module, VCA_1::LEVEL_PARAM);
levelParam->module = module;
addParam(levelParam);
addParam(createParam<CKSS>(mm2px(Vec(5.24619, 79.9593)), module, VCA_1::EXP_PARAM));

addInput(createInput<PJ301MPort>(mm2px(Vec(3.51261, 60.4008)), module, VCA_1::CV_INPUT));
addInput(createInput<PJ301MPort>(mm2px(Vec(3.51398, 97.74977)), module, VCA_1::IN_INPUT));

addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.51398, 108.64454)), module, VCA_1::OUT_OUTPUT));
}
};


Model* modelVCA_1 = createModel<VCA_1, VCA_1Widget>("VCA-1");

+ 1
- 1
src/WTLFO.cpp View File

@@ -232,7 +232,7 @@ struct WTLFO : Module {
if (channels == 1) { if (channels == 1) {
float b = 1.f - phases[0][0]; float b = 1.f - phases[0][0];
lights[PHASE_LIGHT + 0].setSmoothBrightness(b, args.sampleTime * lightDivider.getDivision()); lights[PHASE_LIGHT + 0].setSmoothBrightness(b, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 1].setBrightness(0.f);
lights[PHASE_LIGHT + 1].setSmoothBrightness(b, args.sampleTime * lightDivider.getDivision());
lights[PHASE_LIGHT + 2].setBrightness(0.f); lights[PHASE_LIGHT + 2].setBrightness(0.f);
} }
else { else {


Loading…
Cancel
Save