@@ -97,20 +97,20 @@ struct MidSideWidget : ModuleWidget { | |||
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))); | |||
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)); | |||
} | |||
}; | |||
@@ -167,7 +167,7 @@ struct OctaveWidget : ModuleWidget { | |||
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->setModule(module); | |||
addChild(display); | |||
@@ -133,8 +133,13 @@ struct QuantizerButton : OpaqueWidget { | |||
return; | |||
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); | |||
nvgRect(args.vg, RECT_ARGS(r)); | |||
if (module ? module->playingNotes[note] : (note == 0)) { | |||
@@ -172,13 +177,28 @@ struct QuantizerButton : OpaqueWidget { | |||
struct QuantizerDisplay : LedDisplay { | |||
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->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->note = note; | |||
addChild(quantizerButton); | |||
@@ -31,7 +31,7 @@ struct SequentialSwitch : Module { | |||
SequentialSwitch() { | |||
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(RESET_INPUT, "Reset"); | |||
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))) { | |||
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) | |||
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(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, 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, 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(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, 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)); | |||
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)); | |||
} | |||
}; | |||
@@ -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"); |
@@ -133,160 +133,3 @@ struct VCAWidget : ModuleWidget { | |||
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"); |
@@ -232,7 +232,7 @@ struct WTLFO : Module { | |||
if (channels == 1) { | |||
float b = 1.f - phases[0][0]; | |||
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); | |||
} | |||
else { | |||