diff --git a/res/VCA-1.svg b/res/VCA-1.svg index 5f3e8dc..41ceeed 100644 --- a/res/VCA-1.svg +++ b/res/VCA-1.svg @@ -1,6 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="svg112" + sodipodi:docname="VCA.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + id="metadata116"> image/svg+xml - + + + + + + + - - - - - - - - - - - - - - - - + id="a0bab2db-694e-4656-a5ef-4e87a140906d" + data-name="FND BG"> + + + + - + id="g22"> + + + + - + + + + + id="g35"> - - + d="M12.06836,27.66113,9.22852,20.86719a1.20432,1.20432,0,0,1-.11329-.46338.94586.94586,0,0,1,.96387-.95069,1.001,1.001,0,0,1,.97559.67579l2.18945,5.668L15.459,20.06641a.99831.99831,0,0,1,.92579-.61329.92975.92975,0,0,1,.95117.92579,1.12318,1.12318,0,0,1-.09961.42529l-2.86524,6.85693a1.13191,1.13191,0,0,1-1.08886.76319h-.125A1.131,1.131,0,0,1,12.06836,27.66113Z" + fill="#1f1f1f" + id="path29" /> - - + d="M18.09961,23.93262v-.02539a4.45146,4.45146,0,0,1,4.56641-4.5293,4.6351,4.6351,0,0,1,2.92773.88867.962.962,0,0,1,.375.7627.93918.93918,0,0,1-.9502.93847,1.00557,1.00557,0,0,1-.57519-.1875,2.88441,2.88441,0,0,0-1.78906-.62548,2.59566,2.59566,0,0,0-2.541,2.72753v.02491a2.60214,2.60214,0,0,0,2.541,2.75293,2.8117,2.8117,0,0,0,1.90136-.68848A.89264.89264,0,1,1,25.707,27.33594a4.40507,4.40507,0,0,1-3.11621,1.10058A4.42045,4.42045,0,0,1,18.09961,23.93262Z" + fill="#1f1f1f" + id="path31" /> + d="M27.29688,27.04785l3.05273-6.894a1.19059,1.19059,0,0,1,1.126-.76319h.1123a1.17307,1.17307,0,0,1,1.11328.76319l3.05371,6.894a.94139.94139,0,0,1,.10059.3877.91359.91359,0,0,1-.91406.92627.98119.98119,0,0,1-.92579-.66358l-.58789-1.376H29.57422l-.61328,1.439a.94692.94692,0,0,1-.88867.60059.88717.88717,0,0,1-.88868-.90088A1.02515,1.02515,0,0,1,27.29688,27.04785Zm5.418-2.42724L31.5,21.73047l-1.21289,2.89014Z" + fill="#1f1f1f" + id="path33" /> + id="g41"> - - + d="M19.30078,266.603a.417.417,0,0,1,.834,0v3.98388a.417.417,0,0,1-.834,0Z" + fill="#1f1f1f" + id="path37" /> + d="M21.61133,266.6167a.41783.41783,0,0,1,.41992-.42041h.08789a.52448.52448,0,0,1,.43359.24414l2.3711,3.06934v-2.91358a.40968.40968,0,0,1,.81933,0v3.98389a.40441.40441,0,0,1-.40625.41308h-.03418a.52423.52423,0,0,1-.43359-.251l-2.43848-3.15674v3.0083a.40968.40968,0,0,1-.81933,0Z" + fill="#1f1f1f" + id="path39" /> + id="g49"> - - + d="M15.01367,316.55127v-.01367a2.52165,2.52165,0,0,1,5.041-.01319v.01319a2.52166,2.52166,0,0,1-5.041.01367Zm3.94922,0v-.01367a1.44016,1.44016,0,0,0-1.43555-1.49024,1.41838,1.41838,0,0,0-1.42285,1.477v.01319a1.44137,1.44137,0,0,0,1.43653,1.49072A1.41786,1.41786,0,0,0,18.96289,316.55127Z" + fill="#f0f0f0" + id="path43" /> - - + d="M21.13281,316.87646v-2.229a.52149.52149,0,0,1,1.043,0v2.20215c0,.772.38672,1.17187,1.02344,1.17187s1.02344-.38623,1.02344-1.13818v-2.23584a.52148.52148,0,1,1,1.043,0v2.19531a1.90916,1.90916,0,0,1-2.08007,2.14063A1.88222,1.88222,0,0,1,21.13281,316.87646Z" + fill="#f0f0f0" + id="path45" /> + d="M27.61719,315.12842h-1.002a.481.481,0,0,1,0-.96192h3.04883a.481.481,0,0,1,0,.96192H28.66113v3.29931a.522.522,0,1,1-1.04394,0Z" + fill="#f0f0f0" + id="path47" /> diff --git a/src/MidSide.cpp b/src/MidSide.cpp index 86e76bc..740ef2a 100644 --- a/src/MidSide.cpp +++ b/src/MidSide.cpp @@ -97,20 +97,20 @@ struct MidSideWidget : ModuleWidget { addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addParam(createParamCentered(mm2px(Vec(18.699, 26.234)), module, MidSide::ENC_WIDTH_PARAM)); - addParam(createParamCentered(mm2px(Vec(18.699, 81.235)), module, MidSide::DEC_WIDTH_PARAM)); - - addInput(createInputCentered(mm2px(Vec(6.699, 26.234)), module, MidSide::ENC_WIDTH_INPUT)); - addInput(createInputCentered(mm2px(Vec(6.699, 41.234)), module, MidSide::ENC_LEFT_INPUT)); - addInput(createInputCentered(mm2px(Vec(18.699, 41.234)), module, MidSide::ENC_RIGHT_INPUT)); - addInput(createInputCentered(mm2px(Vec(6.699, 81.234)), module, MidSide::DEC_WIDTH_INPUT)); - addInput(createInputCentered(mm2px(Vec(6.699, 96.234)), module, MidSide::DEC_MID_INPUT)); - addInput(createInputCentered(mm2px(Vec(18.699, 96.234)), module, MidSide::DEC_SIDES_INPUT)); - - addOutput(createOutputCentered(mm2px(Vec(6.699, 57.253)), module, MidSide::ENC_MID_OUTPUT)); - addOutput(createOutputCentered(mm2px(Vec(18.699, 57.253)), module, MidSide::ENC_SIDES_OUTPUT)); - addOutput(createOutputCentered(mm2px(Vec(6.699, 112.252)), module, MidSide::DEC_LEFT_OUTPUT)); - addOutput(createOutputCentered(mm2px(Vec(18.699, 112.252)), module, MidSide::DEC_RIGHT_OUTPUT)); + addParam(createParamCentered(mm2px(Vec(7.285, 25.203)), module, MidSide::ENC_WIDTH_PARAM)); + addParam(createParamCentered(mm2px(Vec(7.285, 80.583)), module, MidSide::DEC_WIDTH_PARAM)); + + addInput(createInputCentered(mm2px(Vec(18.122, 25.142)), module, MidSide::ENC_WIDTH_INPUT)); + addInput(createInputCentered(mm2px(Vec(7.285, 41.373)), module, MidSide::ENC_LEFT_INPUT)); + addInput(createInputCentered(mm2px(Vec(18.122, 41.373)), module, MidSide::ENC_RIGHT_INPUT)); + addInput(createInputCentered(mm2px(Vec(18.122, 80.603)), module, MidSide::DEC_WIDTH_INPUT)); + addInput(createInputCentered(mm2px(Vec(7.285, 96.859)), module, MidSide::DEC_MID_INPUT)); + addInput(createInputCentered(mm2px(Vec(18.122, 96.859)), module, MidSide::DEC_SIDES_INPUT)); + + addOutput(createOutputCentered(mm2px(Vec(7.285, 57.679)), module, MidSide::ENC_MID_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(18.122, 57.679)), module, MidSide::ENC_SIDES_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(7.285, 113.115)), module, MidSide::DEC_LEFT_OUTPUT)); + addOutput(createOutputCentered(mm2px(Vec(18.122, 113.115)), module, MidSide::DEC_RIGHT_OUTPUT)); } }; diff --git a/src/Octave.cpp b/src/Octave.cpp index e61c2af..ae7515f 100644 --- a/src/Octave.cpp +++ b/src/Octave.cpp @@ -167,7 +167,7 @@ struct OctaveWidget : ModuleWidget { addOutput(createOutputCentered(mm2px(Vec(7.62, 113.115)), module, Octave::PITCH_OUTPUT)); - OctaveDisplay* display = createWidget(mm2px(Vec(-0.011, 13.039))); + OctaveDisplay* display = createWidget(mm2px(Vec(0.0, 13.039))); display->box.size = mm2px(Vec(15.263, 55.88)); display->setModule(module); addChild(display); diff --git a/src/Quantizer.cpp b/src/Quantizer.cpp index 1c5b09f..cf33f9a 100644 --- a/src/Quantizer.cpp +++ b/src/Quantizer.cpp @@ -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 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 blackNotes = {1, 3, 6, 8, 10}; + static const std::vector 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); diff --git a/src/SequentialSwitch.cpp b/src/SequentialSwitch.cpp index eda8d2d..4c02634 100644 --- a/src/SequentialSwitch.cpp +++ b/src/SequentialSwitch.cpp @@ -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(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addParam(createParamCentered(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM)); + addParam(createParamCentered(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM)); addInput(createInputCentered(mm2px(Vec(7.555, 33.831)), module, TSequentialSwitch::CLOCK_INPUT)); addInput(createInputCentered(mm2px(Vec(7.555, 50.126)), module, TSequentialSwitch::RESET_INPUT)); @@ -143,10 +157,10 @@ struct SequentialSwitch1Widget : ModuleWidget { addOutput(createOutputCentered(mm2px(Vec(7.555, 102.927)), module, TSequentialSwitch::OUT_OUTPUTS + 2)); addOutput(createOutputCentered(mm2px(Vec(7.555, 113.087)), module, TSequentialSwitch::OUT_OUTPUTS + 3)); - addChild(createLightCentered>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0)); - addChild(createLightCentered>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1)); - addChild(createLightCentered>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2)); - addChild(createLightCentered>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3)); + addChild(createLightCentered>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0)); + addChild(createLightCentered>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1)); + addChild(createLightCentered>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2)); + addChild(createLightCentered>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3)); } }; @@ -166,7 +180,7 @@ struct SequentialSwitch2Widget : ModuleWidget { addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addParam(createParamCentered(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM)); + addParam(createParamCentered(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM)); addInput(createInputCentered(mm2px(Vec(7.8, 33.831)), module, TSequentialSwitch::CLOCK_INPUT)); addInput(createInputCentered(mm2px(Vec(7.8, 50.126)), module, TSequentialSwitch::RESET_INPUT)); @@ -177,10 +191,10 @@ struct SequentialSwitch2Widget : ModuleWidget { addOutput(createOutputCentered(mm2px(Vec(7.8, 113.115)), module, TSequentialSwitch::OUT_OUTPUTS + 0)); - addChild(createLightCentered>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0)); - addChild(createLightCentered>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1)); - addChild(createLightCentered>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2)); - addChild(createLightCentered>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3)); + addChild(createLightCentered>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 0)); + addChild(createLightCentered>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 1)); + addChild(createLightCentered>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2)); + addChild(createLightCentered>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 3)); } }; diff --git a/src/VCA-1.cpp b/src/VCA-1.cpp new file mode 100644 index 0000000..f8045db --- /dev/null +++ b/src/VCA-1.cpp @@ -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(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(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(Vec(RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); + addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + addInput(createInputCentered(mm2px(Vec(7.62, 80.603)), module, VCA_1::CV_INPUT)); + addInput(createInputCentered(mm2px(Vec(7.62, 96.859)), module, VCA_1::IN_INPUT)); + + addOutput(createOutputCentered(mm2px(Vec(7.62, 113.115)), module, VCA_1::OUT_OUTPUT)); + + VCA_1Display* display = createWidget(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(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"); diff --git a/src/VCA.cpp b/src/VCA.cpp index 3ac73da..fdc0206 100644 --- a/src/VCA.cpp +++ b/src/VCA.cpp @@ -133,160 +133,3 @@ struct VCAWidget : ModuleWidget { Model* modelVCA = createModel("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(Vec(RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); - addChild(createWidget(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - addChild(createWidget(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); - - VCA_1VUKnob* levelParam = createParam(mm2px(Vec(2.62103, 12.31692)), module, VCA_1::LEVEL_PARAM); - levelParam->module = module; - addParam(levelParam); - addParam(createParam(mm2px(Vec(5.24619, 79.9593)), module, VCA_1::EXP_PARAM)); - - addInput(createInput(mm2px(Vec(3.51261, 60.4008)), module, VCA_1::CV_INPUT)); - addInput(createInput(mm2px(Vec(3.51398, 97.74977)), module, VCA_1::IN_INPUT)); - - addOutput(createOutput(mm2px(Vec(3.51398, 108.64454)), module, VCA_1::OUT_OUTPUT)); - } -}; - - -Model* modelVCA_1 = createModel("VCA-1"); diff --git a/src/WTLFO.cpp b/src/WTLFO.cpp index f7a9680..6d09b5a 100644 --- a/src/WTLFO.cpp +++ b/src/WTLFO.cpp @@ -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 {