computerscare-vcv-modules

ComputerScare modules for VCV Rack
Log | Files | Refs

ComputerscareGolyPenerator.cpp (7917B)


      1 #include "Computerscare.hpp"
      2 
      3 #include "dtpulse.hpp"
      4 #include "golyFunctions.hpp"
      5 
      6 struct ComputerscareGolyPenerator;
      7 
      8 
      9 /*
     10 	knob1: number of channels output 1-16
     11 	knob2: algorithm
     12 	knob3: param 1
     13 */
     14 const std::string GolyPeneratorAvailableAlgorithmsArr[5] = {"Linear", "Sigmoid", "Hump", "Sinusoid", "Pseudo-Random"};
     15 
     16 
     17 //template <const std::string& options>
     18 struct GolyAlgoParamQuantity : ParamQuantity {
     19 	std::string getDisplayValueString() override {
     20 		int val = getValue();
     21 		return GolyPeneratorAvailableAlgorithmsArr[val];
     22 	}
     23 };
     24 
     25 struct ComputerscareGolyPenerator : ComputerscareMenuParamModule {
     26 	int counter = 0;
     27 	int numChannels = 16;
     28 	ComputerscareSVGPanel* panelRef;
     29 	Goly goly;
     30 	float currentValues[16] = {0.f};
     31 	std::vector<std::string> availableAlgorithms;
     32 
     33 	enum ParamIds {
     34 		ALGORITHM,
     35 		IN_OFFSET,
     36 		IN_SCALE,
     37 		OUT_SCALE,
     38 		OUT_OFFSET,
     39 		POLY_CHANNELS,
     40 		COLOR,
     41 		NUM_PARAMS
     42 	};
     43 	enum InputIds {
     44 		CHANNEL_INPUT,
     45 		NUM_INPUTS
     46 	};
     47 	enum OutputIds {
     48 		POLY_OUTPUT,
     49 		NUM_OUTPUTS
     50 	};
     51 	enum LightIds {
     52 		NUM_LIGHTS
     53 	};
     54 
     55 
     56 	ComputerscareGolyPenerator()  {
     57 
     58 		config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
     59 
     60 		configParam<GolyAlgoParamQuantity>(ALGORITHM , 0.f, 4.f, 0.f, "Algorithm");
     61 		configParam(IN_OFFSET, -1.f, 1.f, 0.f, "Channel Center");
     62 
     63 		configParam(IN_SCALE, -2.f, 2.f, 1.f, "Channel Spread");
     64 
     65 		configParam(OUT_SCALE, -20.f, 20.f, 10.f, "Output Scale");
     66 		configParam(OUT_OFFSET, -10.f, 10.f, 0.f, "Output Offset");
     67 		configParam<AutoParamQuantity>(POLY_CHANNELS, 1.f, 16.f, 16.f, "Poly Channels");
     68 		configMenuParam(COLOR, 0.f, 9.f, 0.f, "Display Color", 2);
     69 
     70 		getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false;
     71 		getParamQuantity(POLY_CHANNELS)->resetEnabled = false;
     72 
     73 		configOutput(POLY_OUTPUT, "Main");
     74 
     75 		availableAlgorithms.push_back("Linear");
     76 		availableAlgorithms.push_back("Sigmoid");
     77 		availableAlgorithms.push_back("Hump");
     78 		availableAlgorithms.push_back("Sinusoid");
     79 		availableAlgorithms.push_back("Pseudo-Random");
     80 
     81 
     82 		goly = Goly();
     83 
     84 	}
     85 	void updateCurrents() {
     86 		std::vector<float> golyParams = {params[IN_OFFSET].getValue(), params[IN_SCALE].getValue(), params[OUT_SCALE].getValue(), params[OUT_OFFSET].getValue()};
     87 		goly.invoke((int) std::floor(params[ALGORITHM].getValue()), golyParams, params[POLY_CHANNELS].getValue());
     88 	}
     89 	void setAlgorithm(int algoVal) {
     90 		params[ALGORITHM].setValue(algoVal);
     91 	}
     92 	void checkPoly() override {
     93 		int knobSetting = params[POLY_CHANNELS].getValue();
     94 		polyChannels = knobSetting == 0 ? 16 : knobSetting;
     95 		outputs[POLY_OUTPUT].setChannels(polyChannels);
     96 	}
     97 	void process(const ProcessArgs &args) override {
     98 		ComputerscarePolyModule::checkCounter();
     99 		counter++;
    100 		if (counter > 13) {
    101 			counter = 0;
    102 			updateCurrents();
    103 			//numChannels=(int) (std::floor(params[POLY_CHANNELS].getValue()));
    104 		}
    105 
    106 
    107 		//outputs[POLY_OUTPUT].setChannels(numChannels);
    108 		for (int i = 0; i < polyChannels; i++) {
    109 			outputs[POLY_OUTPUT].setVoltage(goly.currentValues[i], i);
    110 		}
    111 	}
    112 
    113 };
    114 struct setAlgoItem : MenuItem
    115 {
    116 	ComputerscareGolyPenerator *penerator;
    117 	int mySetVal;
    118 	setAlgoItem(int setVal)
    119 	{
    120 		mySetVal = setVal;
    121 	}
    122 
    123 	void onAction(const event::Action &e) override
    124 	{
    125 		penerator->setAlgorithm(mySetVal);
    126 	}
    127 	void step() override {
    128 		rightText = CHECKMARK(penerator->params[ComputerscareGolyPenerator::ALGORITHM].getValue() == mySetVal);
    129 		MenuItem::step();
    130 	}
    131 };
    132 
    133 struct AlgorithmChildMenu : MenuItem {
    134 	ComputerscareGolyPenerator *penerator;
    135 
    136 	Menu *createChildMenu() override {
    137 		Menu *menu = new Menu;
    138 		menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Select an Algorithm... NOW"));
    139 
    140 		for (unsigned int i = 0; i < penerator->availableAlgorithms.size(); i++) {
    141 			setAlgoItem *menuItem = new setAlgoItem(i);
    142 			//ParamSettingItem *menuItem = new ParamSettingItem(i,ComputerscareGolyPenerator::ALGORITHM);
    143 
    144 			menuItem->text = penerator->availableAlgorithms[i];
    145 			menuItem->penerator = penerator;
    146 			menu->addChild(menuItem);
    147 		}
    148 
    149 		return menu;
    150 	}
    151 
    152 };
    153 struct PeneratorDisplay : TransparentWidget {
    154 	ComputerscareGolyPenerator *module;
    155 
    156 	PeneratorDisplay() {
    157 
    158 	}
    159 	void drawLayer(const BGPanel::DrawArgs& args, int layer) override {
    160 		if (layer == 1) {
    161 			float valsToDraw[16] = {1.f};
    162 			int ch = 16;
    163 			float colorArg;
    164 
    165 			if (module) {
    166 				ch = module->polyChannels;
    167 				colorArg = module->params[ComputerscareGolyPenerator::COLOR].getValue();
    168 				for (int i = 0; i < ch; i++) {
    169 					valsToDraw[i] = module->goly.currentValues[i];
    170 				}
    171 			}
    172 			else {
    173 				for (int i = 0; i < ch; i++) {
    174 					valsToDraw[i] = random::uniform() * 10;
    175 				}
    176 				colorArg = random::uniform() * 2;
    177 			}
    178 			DrawHelper draw = DrawHelper(args.vg);
    179 			Points pts = Points();
    180 
    181 			nvgTranslate(args.vg, box.size.x / 2, box.size.y / 2 + 5);
    182 			pts.linear(ch, Vec(0, -box.size.y / 2), Vec(0, 150));
    183 			std::vector<Vec> polyVals;
    184 			std::vector<NVGcolor> colors;
    185 			std::vector<Vec> thicknesses;
    186 
    187 			for (int i = 0; i < 16; i++) {
    188 				polyVals.push_back(Vec(valsToDraw[i] * 2, 0.f));
    189 				colors.push_back(draw.sincolor(colorArg, {1, 1, 0}));
    190 
    191 				thicknesses.push_back(Vec(160 / (1 + ch), 0));
    192 			}
    193 			draw.drawLines(pts.get(), polyVals, colors, thicknesses);
    194 		}
    195 	}
    196 };
    197 struct ComputerscareGolyPeneratorWidget : ModuleWidget {
    198 	ComputerscareGolyPeneratorWidget(ComputerscareGolyPenerator *module) {
    199 
    200 		setModule(module);
    201 		box.size = Vec(4 * 15, 380);
    202 		{
    203 			ComputerscareSVGPanel *panel = new ComputerscareSVGPanel();
    204 			panel->box.size = box.size;
    205 			panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareGolyPeneratorPanel.svg")));
    206 			addChild(panel);
    207 		}
    208 
    209 		PeneratorDisplay *display = new PeneratorDisplay();
    210 		display->module = module;
    211 		display->box.pos = Vec(0, 120);
    212 		display->box.size = Vec(box.size.x, 400);
    213 		addChild(display);
    214 
    215 		addLabeledKnob<ScrambleSnapKnob>("Algo", 4, 324, module, ComputerscareGolyPenerator::ALGORITHM, 0, 0, true);
    216 		addLabeledKnob<SmoothKnob>("center", 28, 80, module, ComputerscareGolyPenerator::IN_OFFSET, 0, 0);
    217 		addLabeledKnob<SmallKnob>("spread", 5, 86, module, ComputerscareGolyPenerator::IN_SCALE, 0, 0);
    218 		addLabeledKnob<SmallKnob>("scale", 33, 290, module, ComputerscareGolyPenerator::OUT_SCALE, 0, 0);
    219 		addLabeledKnob<SmoothKnob>("offset", 2, 284, module, ComputerscareGolyPenerator::OUT_OFFSET, 0, 0);
    220 
    221 		channelWidget = new PolyOutputChannelsWidget(Vec(28, 309), module, ComputerscareGolyPenerator::POLY_CHANNELS);
    222 		addChild(channelWidget);
    223 
    224 		addOutput(createOutput<InPort>(Vec(28, 329), module, ComputerscareGolyPenerator::POLY_OUTPUT));
    225 
    226 	}
    227 	void appendContextMenu(Menu* menu) override {
    228 		ComputerscareGolyPenerator* penerator = dynamic_cast<ComputerscareGolyPenerator*>(this->module);
    229 
    230 		MenuParam* colorParam = new MenuParam(penerator->paramQuantities[ComputerscareGolyPenerator::COLOR], 2);
    231 		menu->addChild(colorParam);
    232 
    233 		menu->addChild(new MenuSeparator);
    234 
    235 		AlgorithmChildMenu *algoMenu = new AlgorithmChildMenu();
    236 		algoMenu->text = "Algorithm";
    237 		algoMenu->rightText = RIGHT_ARROW;
    238 		algoMenu->penerator = penerator;
    239 		menu->addChild(algoMenu);
    240 	}
    241 
    242 	template <typename BASE>
    243 	void addLabeledKnob(std::string label, int x, int y, ComputerscareGolyPenerator *module, int paramIndex, float labelDx, float labelDy, bool snap = false) {
    244 
    245 		smallLetterDisplay = new SmallLetterDisplay();
    246 		smallLetterDisplay->box.size = Vec(5, 10);
    247 		smallLetterDisplay->fontSize = 14;
    248 		smallLetterDisplay->value = label;
    249 		smallLetterDisplay->textAlign = 1;
    250 
    251 		if (snap) {
    252 			addParam(createParam<BASE>(Vec(x, y), module, paramIndex));
    253 		}
    254 		else {
    255 			addParam(createParam<BASE>(Vec(x, y), module, paramIndex));
    256 
    257 		}
    258 		smallLetterDisplay->box.pos = Vec(x + labelDx, y - 12 + labelDy);
    259 
    260 
    261 		//addChild(smallLetterDisplay);
    262 
    263 	}
    264 	PolyOutputChannelsWidget* channelWidget;
    265 
    266 	SmallLetterDisplay* smallLetterDisplay;
    267 };
    268 
    269 Model *modelComputerscareGolyPenerator = createModel<ComputerscareGolyPenerator, ComputerscareGolyPeneratorWidget>("computerscare-goly-penerator");