computerscare-vcv-modules

ComputerScare modules for VCV Rack
Log | Files | Refs

ComputerscareSolyPequencer.cpp (8074B)


      1 #include "Computerscare.hpp"
      2 
      3 struct ComputerscareSolyPequencer;
      4 
      5 struct ComputerscareSolyPequencer : ComputerscarePolyModule {
      6 	int currentStep[16] = {0};
      7 	int numSteps[16] = {16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
      8 	int clockChannels[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
      9 	int resetChannels[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
     10 
     11 	bool autoNumSteps = true;
     12 	rack::dsp::SchmittTrigger clockTriggers[16];
     13 	rack::dsp::SchmittTrigger resetTriggers[16];
     14 
     15 	rack::dsp::SchmittTrigger globalManualClockTrigger;
     16 	rack::dsp::SchmittTrigger globalManualResetTrigger;
     17 
     18 
     19 	ComputerscareSVGPanel* panelRef;
     20 	enum ParamIds {
     21 		MANUAL_RUN_BUTTON,
     22 		MANUAL_CLOCK_BUTTON,
     23 		MANUAL_RESET_BUTTON,
     24 		NUM_STEPS_AUTO_BUTTON,
     25 		NUM_STEPS_KNOB,
     26 		POLY_CHANNELS,
     27 		NUM_PARAMS
     28 	};
     29 	enum InputIds {
     30 		POLY_INPUT,
     31 		CLOCK_INPUT,
     32 		RESET_INPUT,
     33 		RUN_INPUT,
     34 		NUM_STEPS_INPUT,
     35 		NUM_INPUTS
     36 	};
     37 	enum OutputIds {
     38 		POLY_OUTPUT,
     39 		EOC_OUTPUT,
     40 		NUM_OUTPUTS
     41 	};
     42 	enum LightIds {
     43 		NUM_LIGHTS
     44 	};
     45 
     46 
     47 	ComputerscareSolyPequencer()  {
     48 
     49 		config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
     50 		configButton(MANUAL_CLOCK_BUTTON, "Manual Clock Advance");
     51 		configButton(MANUAL_RESET_BUTTON, "Manual Reset");
     52 		configParam<AutoParamQuantity>(POLY_CHANNELS, 0.f, 16.f, 16.f, "Poly Channels");
     53 
     54 		getParamQuantity(POLY_CHANNELS)->randomizeEnabled = false;
     55 		getParamQuantity(POLY_CHANNELS)->resetEnabled = false;
     56 
     57 		configInput(POLY_INPUT, "Main");
     58 		configInput(CLOCK_INPUT, "Clock");
     59 		configInput(RESET_INPUT, "Reset Trigger");
     60 
     61 		configOutput(POLY_OUTPUT, "Main");
     62 		configOutput(EOC_OUTPUT, "End of Cycle");
     63 	}
     64 	void resetAll() {
     65 		for (int i = 0; i < 16; i++) {
     66 			currentStep[i] = 0;
     67 		}
     68 	}
     69 	void checkPoly() override {
     70 		int resetNum = inputs[RESET_INPUT].getChannels();
     71 		int clockNum = inputs[CLOCK_INPUT].getChannels();
     72 		int knobSetting = params[POLY_CHANNELS].getValue();
     73 		if (knobSetting == 0) {
     74 			polyChannels = inputs[CLOCK_INPUT].isConnected() ? std::max(clockNum, resetNum) : 16;
     75 		}
     76 		else {
     77 			polyChannels = knobSetting;
     78 		}
     79 		for (int i = 0; i < 16; i++) {
     80 			clockChannels[i] = std::max(1, std::min(i + 1, clockNum));
     81 			resetChannels[i] = std::max(1, std::min(i + 1, resetNum));
     82 		}
     83 		outputs[POLY_OUTPUT].setChannels(polyChannels);
     84 		outputs[EOC_OUTPUT].setChannels(polyChannels);
     85 	}
     86 	void process(const ProcessArgs &args) override {
     87 		ComputerscarePolyModule::checkCounter();
     88 		int numInputChannels = inputs[POLY_INPUT].getChannels();
     89 		int numReset = inputs[RESET_INPUT].getChannels();
     90 		int numClock = inputs[CLOCK_INPUT].getChannels();
     91 		//int numOutputChannels = numClock > 0 ? numClock : 1;
     92 		bool globalClocked = globalManualClockTrigger.process(params[MANUAL_CLOCK_BUTTON].getValue());
     93 		bool manualReset = globalManualResetTrigger.process(params[MANUAL_RESET_BUTTON].getValue());
     94 
     95 		if (inputs[POLY_INPUT].isConnected()) {
     96 			bool currentClock[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     97 			bool currentReset[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     98 			bool isHigh[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     99 			bool eoc[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    100 			for (int i = 0; i < 16; i++) {
    101 				currentClock[i] = clockTriggers[i].process(inputs[CLOCK_INPUT].getVoltage(i));
    102 				currentReset[i] = resetTriggers[i].process(inputs[RESET_INPUT].getVoltage(i));
    103 				isHigh[i] = clockTriggers[i].isHigh();
    104 			}
    105 			for (int i = 0; i < 16; i++) {
    106 				eoc[i] = (currentClock[clockChannels[i] - 1] && isHigh[clockChannels[i] - 1]) || (currentReset[resetChannels[i] - 1] && resetTriggers[resetChannels[i] - 1].isHigh());
    107 			}
    108 			for (int j = 0; j < polyChannels; j++) {
    109 				if (globalClocked || currentClock[clockChannels[j] - 1]) {
    110 					currentStep[j]++;
    111 					if (autoNumSteps) {
    112 						currentStep[j] = currentStep[j] % numInputChannels;
    113 					}
    114 					else {
    115 						currentStep[j] = currentStep[j] % numSteps[j];
    116 					}
    117 
    118 
    119 				}
    120 				if (numReset == 1 && currentReset[0]) {
    121 					currentStep[j] = 0;
    122 				}
    123 				else if (j <= numReset && currentReset[j]) {
    124 					currentStep[j] = 0;
    125 				}
    126 			}
    127 			for (int c = 0; c < polyChannels; c++) {
    128 				outputs[POLY_OUTPUT].setVoltage(inputs[POLY_INPUT].getVoltage(currentStep[c]), c);
    129 				outputs[EOC_OUTPUT].setVoltage(currentStep[c] == 0 && eoc[c] ? 10.f : 0.f, c);
    130 			}
    131 
    132 		}
    133 		if (manualReset) {
    134 			resetAll();
    135 		}
    136 
    137 
    138 	}
    139 
    140 };
    141 struct PequencerSmallDisplay : SmallLetterDisplay
    142 {
    143 	ComputerscareSolyPequencer *module;
    144 	int ch;
    145 	PequencerSmallDisplay(int outputChannelNumber)
    146 	{
    147 
    148 		ch = outputChannelNumber;
    149 		SmallLetterDisplay();
    150 	};
    151 	void draw(const DrawArgs &args)
    152 	{
    153 		//this->setNumDivisionsString();
    154 		if (module)
    155 		{
    156 
    157 
    158 			//std::string str = std::to_string(module->routing[ch]);
    159 			value = std::to_string(module->currentStep[ch]);
    160 
    161 
    162 
    163 		}
    164 		else {
    165 			value = std::to_string((random::u32() % 16));
    166 		}
    167 		SmallLetterDisplay::draw(args);
    168 	}
    169 
    170 };
    171 
    172 struct ComputerscareSolyPequencerWidget : ModuleWidget {
    173 	ComputerscareSolyPequencerWidget(ComputerscareSolyPequencer *module) {
    174 
    175 		setModule(module);
    176 		//setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareSolyPequencerPanel.svg")));
    177 		box.size = Vec(4 * 15, 380);
    178 		{
    179 			ComputerscareSVGPanel *panel = new ComputerscareSVGPanel();
    180 			panel->box.size = box.size;
    181 			panel->setBackground(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareSolyPequencerPanel.svg")));
    182 			addChild(panel);
    183 
    184 		}
    185 
    186 		addOutput(createOutput<PointingUpPentagonPort>(Vec(4, 56), module, ComputerscareSolyPequencer::POLY_OUTPUT));
    187 		addOutput(createOutput<TinyJack>(Vec(40, 84), module, ComputerscareSolyPequencer::EOC_OUTPUT));
    188 
    189 
    190 		channelWidget = new PolyOutputChannelsWidget(Vec(26, 56), module, ComputerscareSolyPequencer::POLY_CHANNELS);
    191 		addChild(channelWidget);
    192 
    193 		addLabeledKnob("Steps", 10, 124, module, 0, 0, 0);
    194 		stepNumberGrid(1, 230, 30, 15, module);
    195 
    196 
    197 		addInput(createInput<InPort>(Vec(20, 116), module, ComputerscareSolyPequencer::POLY_INPUT));
    198 
    199 
    200 		addParam(createParam<ComputerscareClockButton>(Vec(8, 152), module, ComputerscareSolyPequencer::MANUAL_CLOCK_BUTTON));
    201 		addInput(createInput<PointingUpPentagonPort>(Vec(8, 169), module, ComputerscareSolyPequencer::CLOCK_INPUT));
    202 
    203 		addParam(createParam<ComputerscareResetButton>(Vec(32, 169), module, ComputerscareSolyPequencer::MANUAL_RESET_BUTTON));
    204 		addInput(createInput<InPort>(Vec(30, 182), module, ComputerscareSolyPequencer::RESET_INPUT));
    205 
    206 
    207 	}
    208 	void stepNumberGrid(int x, int y, int xspacing, int yspacing, ComputerscareSolyPequencer *module) {
    209 		for (int i = 0; i < 2; i++) {
    210 			for (int j = 0; j < 8; j++) {
    211 				psd = new PequencerSmallDisplay(i * 8 + j);
    212 				psd->box.size = Vec(10, 10);
    213 				psd->box.pos = Vec(x + i * xspacing , y + j * yspacing);
    214 				psd->fontSize = 18;
    215 				psd->textAlign = 18;
    216 				psd->textColor = nvgRGB(0x24, 0x44, 0x31);
    217 				psd->breakRowWidth = 20;
    218 				psd->module = module;
    219 				addChild(psd);
    220 			}
    221 		}
    222 	}
    223 	void addLabeledKnob(std::string label, int x, int y, ComputerscareSolyPequencer *module, int index, float labelDx, float labelDy) {
    224 
    225 		/*psd = new PequencerSmallDisplay(index);
    226 		psd->box.size = Vec(20, 20);
    227 		psd->box.pos = Vec(x - 2.5 , y + 1.f);
    228 		psd->fontSize = 26;
    229 		psd->textAlign = 18;
    230 		psd->textColor =nvgRGB(0x24, 0x44, 0x31);
    231 		psd->breakRowWidth = 20;
    232 		psd->module = module;*/
    233 
    234 
    235 		outputChannelLabel = new SmallLetterDisplay();
    236 		outputChannelLabel->box.size = Vec(5, 5);
    237 		outputChannelLabel->box.pos = Vec(x + labelDx, y - 12 + labelDy);
    238 		outputChannelLabel->fontSize = 14;
    239 		outputChannelLabel->textAlign = index < 8 ? 1 : 4;
    240 		outputChannelLabel->breakRowWidth = 15;
    241 
    242 		//outputChannelLabel->value = "hogman";
    243 
    244 		//addParam(createParam<MediumDotSnapKnob>(Vec(x, y), module, ComputerscareSolyPequencer::KNOB + index));
    245 		//addChild(psd);
    246 		addChild(outputChannelLabel);
    247 
    248 	}
    249 
    250 	PolyOutputChannelsWidget* channelWidget;
    251 	PequencerSmallDisplay* psd;
    252 	SmallLetterDisplay* outputChannelLabel;
    253 };
    254 
    255 
    256 Model *modelComputerscareSolyPequencer = createModel<ComputerscareSolyPequencer, ComputerscareSolyPequencerWidget>("computerscare-soly-pequencer");