computerscare-vcv-modules

ComputerScare modules for VCV Rack
Log | Files | Refs

ComputerscareDebug.cpp (16365B)


      1 #include "Computerscare.hpp"
      2 
      3 #include <string>
      4 #include <sstream>
      5 #include <iomanip>
      6 
      7 const int NUM_LINES = 16;
      8 
      9 struct ComputerscareDebug;
     10 
     11 std::string noModuleStringValue = "+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n";
     12 
     13 
     14 struct ComputerscareDebug : Module {
     15 	enum ParamIds {
     16 		MANUAL_TRIGGER,
     17 		MANUAL_CLEAR_TRIGGER,
     18 		CLOCK_CHANNEL_FOCUS,
     19 		INPUT_CHANNEL_FOCUS,
     20 		SWITCH_VIEW,
     21 		WHICH_CLOCK,
     22 		NUM_PARAMS
     23 	};
     24 	enum InputIds {
     25 		VAL_INPUT,
     26 		TRG_INPUT,
     27 		CLR_INPUT,
     28 		NUM_INPUTS
     29 	};
     30 	enum OutputIds {
     31 		POLY_OUTPUT,
     32 		NUM_OUTPUTS
     33 	};
     34 	enum LightIds {
     35 		BLINK_LIGHT,
     36 		NUM_LIGHTS
     37 	};
     38 
     39 	std::string defaultStrValue = "+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n+0.000000\n";
     40 	std::string strValue = "0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n0.000000\n";
     41 
     42 	float logLines[NUM_LINES] = {0.f};
     43 
     44 	int lineCounter = 0;
     45 
     46 	int clockChannel = 0;
     47 	int inputChannel = 0;
     48 
     49 	int clockMode = 1;
     50 	int inputMode = 2;
     51 
     52 	int outputRangeEnum = 0;
     53 
     54 
     55 	float outputRanges[8][2];
     56 
     57 	int stepCounter;
     58 	dsp::SchmittTrigger clockTriggers[NUM_LINES];
     59 	dsp::SchmittTrigger clearTrigger;
     60 	dsp::SchmittTrigger manualClockTrigger;
     61 	dsp::SchmittTrigger manualClearTrigger;
     62 
     63 	enum clockAndInputModes {
     64 		SINGLE_MODE,
     65 		INTERNAL_MODE,
     66 		POLY_MODE
     67 	};
     68 
     69 	ComputerscareDebug() {
     70 		config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
     71 		configButton(MANUAL_TRIGGER, "Manual Trigger");
     72 		configButton(MANUAL_CLEAR_TRIGGER, "Reset/Clear");
     73 		configSwitch(SWITCH_VIEW, 0.0f, 2.0f, 2.0f, "Input Mode", {"Single-Channel", "Internal", "Polyphonic"});
     74 		configSwitch(WHICH_CLOCK, 0.0f, 2.0f, 1.0f, "Clock Mode", {"Single-Channel", "Internal", "Polyphonic"});
     75 		configParam(CLOCK_CHANNEL_FOCUS, 0.f, 15.f, 0.f, "Clock Channel Selector");
     76 		configParam(INPUT_CHANNEL_FOCUS, 0.f, 15.f, 0.f, "Input Channel Selector");
     77 
     78 		configInput(VAL_INPUT, "Value");
     79 		configInput(TRG_INPUT, "Clock");
     80 		configInput(CLR_INPUT, "Reset");
     81 		configOutput(POLY_OUTPUT, "Main");
     82 
     83 
     84 
     85 		outputRanges[0][0] = 0.f;
     86 		outputRanges[0][1] = 10.f;
     87 		outputRanges[1][0] = -5.f;
     88 		outputRanges[1][1] = 5.f;
     89 		outputRanges[2][0] = 0.f;
     90 		outputRanges[2][1] = 5.f;
     91 		outputRanges[3][0] = 0.f;
     92 		outputRanges[3][1] = 1.f;
     93 		outputRanges[4][0] = -1.f;
     94 		outputRanges[4][1] = 1.f;
     95 		outputRanges[5][0] = -10.f;
     96 		outputRanges[5][1] = 10.f;
     97 		outputRanges[6][0] = -2.f;
     98 		outputRanges[6][1] = 2.f;
     99 		outputRanges[7][0] = 0.f;
    100 		outputRanges[7][1] = 2.f;
    101 
    102 		stepCounter = 0;
    103 
    104 		getParamQuantity(SWITCH_VIEW)->randomizeEnabled = false;
    105 		getParamQuantity(WHICH_CLOCK)->randomizeEnabled = false;
    106 		getParamQuantity(CLOCK_CHANNEL_FOCUS)->randomizeEnabled = false;
    107 		getParamQuantity(INPUT_CHANNEL_FOCUS)->randomizeEnabled = false;
    108 
    109 		randomizeStorage();
    110 	}
    111 	void process(const ProcessArgs &args) override;
    112 
    113 	void onRandomize() override {
    114 		randomizeStorage();
    115 	}
    116 
    117 	void randomizeStorage() {
    118 		float min = outputRanges[outputRangeEnum][0];
    119 		float max = outputRanges[outputRangeEnum][1];
    120 		float spread = max - min;
    121 		for (int i = 0; i < 16; i++) {
    122 			logLines[i] = min + spread * random::uniform();
    123 		}
    124 	}
    125 
    126 	json_t *dataToJson() override {
    127 		json_t *rootJ = json_object();
    128 
    129 		json_object_set_new(rootJ, "outputRange", json_integer(outputRangeEnum));
    130 
    131 		json_t *sequencesJ = json_array();
    132 
    133 		for (int i = 0; i < 16; i++) {
    134 			json_t *sequenceJ = json_real(logLines[i]);
    135 			json_array_append_new(sequencesJ, sequenceJ);
    136 		}
    137 		json_object_set_new(rootJ, "lines", sequencesJ);
    138 		return rootJ;
    139 	}
    140 
    141 	void dataFromJson(json_t *rootJ) override {
    142 		float val;
    143 
    144 		json_t *outputRangeEnumJ = json_object_get(rootJ, "outputRange");
    145 		if (outputRangeEnumJ) { outputRangeEnum = json_integer_value(outputRangeEnumJ); }
    146 
    147 		json_t *sequencesJ = json_object_get(rootJ, "lines");
    148 
    149 		if (sequencesJ) {
    150 			for (int i = 0; i < 16; i++) {
    151 				json_t *sequenceJ = json_array_get(sequencesJ, i);
    152 				if (sequenceJ)
    153 					val = json_real_value(sequenceJ);
    154 				logLines[i] = val;
    155 			}
    156 		}
    157 
    158 	}
    159 	int setChannelCount() {
    160 		clockMode = floor(params[WHICH_CLOCK].getValue());
    161 
    162 		inputMode = floor(params[SWITCH_VIEW].getValue());
    163 
    164 
    165 		int numInputChannels = inputs[VAL_INPUT].getChannels();
    166 		int numClockChannels = inputs[TRG_INPUT].getChannels();
    167 
    168 		bool inputConnected = inputs[VAL_INPUT].isConnected();
    169 		bool clockConnected = inputs[TRG_INPUT].isConnected();
    170 
    171 		bool noConnection = !inputConnected && !clockConnected;
    172 
    173 		int numOutputChannels = 16;
    174 
    175 		if (!noConnection) {
    176 
    177 			if (clockMode == SINGLE_MODE) {
    178 				if (inputMode == POLY_MODE) {
    179 					numOutputChannels = numInputChannels;
    180 				}
    181 			}
    182 			else if (clockMode == INTERNAL_MODE) {
    183 				if (inputMode == POLY_MODE) {
    184 					numOutputChannels = numInputChannels;
    185 					for (int i = 0; i < 16; i++) {
    186 						logLines[i] = inputs[VAL_INPUT].getVoltage(i);
    187 					}
    188 				}
    189 			}
    190 			else if (clockMode == POLY_MODE) {
    191 				if (inputMode == POLY_MODE) {
    192 					numOutputChannels = std::min(numInputChannels, numClockChannels);
    193 				}
    194 				else if (inputMode == SINGLE_MODE) {
    195 					numOutputChannels = numClockChannels;
    196 				}
    197 				else if (inputMode == INTERNAL_MODE) {
    198 					numOutputChannels = numClockChannels;
    199 				}
    200 
    201 			}
    202 		}
    203 		outputs[POLY_OUTPUT].setChannels(numOutputChannels);
    204 
    205 		return numOutputChannels;
    206 	}
    207 };
    208 
    209 void ComputerscareDebug::process(const ProcessArgs &args) {
    210 	std::string thisVal;
    211 
    212 	clockMode = floor(params[WHICH_CLOCK].getValue());
    213 
    214 	inputMode = floor(params[SWITCH_VIEW].getValue());
    215 
    216 	inputChannel = floor(params[INPUT_CHANNEL_FOCUS].getValue());
    217 	clockChannel = floor(params[CLOCK_CHANNEL_FOCUS].getValue());
    218 
    219 	bool inputConnected = inputs[VAL_INPUT].isConnected();
    220 
    221 	float min = outputRanges[outputRangeEnum][0];
    222 	float max = outputRanges[outputRangeEnum][1];
    223 	float spread = max - min;
    224 
    225 	if (clockMode == SINGLE_MODE) {
    226 		if (clockTriggers[clockChannel].process(inputs[TRG_INPUT].getVoltage(clockChannel) / 2.f) || manualClockTrigger.process(params[MANUAL_TRIGGER].getValue()) ) {
    227 			if (inputMode == POLY_MODE) {
    228 				for (int i = 0; i < 16; i++) {
    229 					logLines[i] = inputs[VAL_INPUT].getVoltage(i);
    230 				}
    231 			}
    232 			else if (inputMode == SINGLE_MODE) {
    233 				for ( unsigned int a = NUM_LINES - 1; a > 0; a = a - 1 )
    234 				{
    235 					logLines[a] = logLines[a - 1];
    236 				}
    237 
    238 
    239 				logLines[0] = inputs[VAL_INPUT].getVoltage(inputChannel);
    240 			}
    241 			else if (inputMode == INTERNAL_MODE) {
    242 				for (int i = 0; i < 16; i++) {
    243 					logLines[i] = min + spread * random::uniform();
    244 				}
    245 			}
    246 		}
    247 	}
    248 	else if (clockMode == INTERNAL_MODE) {
    249 		if (inputConnected) {
    250 			if (inputMode == POLY_MODE) {
    251 				for (int i = 0; i < 16; i++) {
    252 					logLines[i] = inputs[VAL_INPUT].getVoltage(i);
    253 				}
    254 			}
    255 			else if (inputMode == SINGLE_MODE) {
    256 				logLines[inputChannel] = inputs[VAL_INPUT].getVoltage(inputChannel);
    257 			}
    258 		}
    259 		if (inputMode == INTERNAL_MODE) {
    260 			for (int i = 0; i < 16; i++) {
    261 				logLines[i] = min + spread * random::uniform();
    262 			}
    263 		}
    264 	}
    265 	else if (clockMode == POLY_MODE) {
    266 		if (inputMode == POLY_MODE) {
    267 			for (int i = 0; i < 16; i++) {
    268 				if (clockTriggers[i].process(inputs[TRG_INPUT].getVoltage(i) / 2.f) || manualClockTrigger.process(params[MANUAL_TRIGGER].getValue()) ) {
    269 					logLines[i] = inputs[VAL_INPUT].getVoltage(i);
    270 				}
    271 			}
    272 		}
    273 		else if (inputMode == SINGLE_MODE) {
    274 			for (int i = 0; i < 16; i++) {
    275 				if (clockTriggers[i].process(inputs[TRG_INPUT].getVoltage(i) / 2.f) || manualClockTrigger.process(params[MANUAL_TRIGGER].getValue()) ) {
    276 					logLines[i] = inputs[VAL_INPUT].getVoltage(inputChannel);
    277 				}
    278 			}
    279 		}
    280 		else if (inputMode == INTERNAL_MODE) {
    281 			for (int i = 0; i < 16; i++) {
    282 				if (clockTriggers[i].process(inputs[TRG_INPUT].getVoltage(i) / 2.f) || manualClockTrigger.process(params[MANUAL_TRIGGER].getValue()) ) {
    283 					logLines[i] = min + spread * random::uniform();
    284 				}
    285 
    286 			}
    287 		}
    288 	}
    289 
    290 	if (clearTrigger.process(inputs[CLR_INPUT].getVoltage() / 2.f) || manualClearTrigger.process(params[MANUAL_CLEAR_TRIGGER].getValue())) {
    291 		for ( unsigned int a = 0; a < NUM_LINES; a++ )
    292 		{
    293 			logLines[a] = 0;
    294 		}
    295 		strValue = defaultStrValue;
    296 	}
    297 
    298 	int numOutputChannels = setChannelCount();
    299 
    300 	stepCounter++;
    301 
    302 	if (stepCounter > 1025) {
    303 		stepCounter = 0;
    304 
    305 		thisVal = "";
    306 		std::string thisLine = "";
    307 		for ( unsigned int a = 0; a < NUM_LINES; a = a + 1 )
    308 		{
    309 
    310 			if (a < numOutputChannels) {
    311 				thisLine = logLines[a] >= 0 ? "+" : "";
    312 				thisLine += std::to_string(logLines[a]);
    313 				thisLine = thisLine.substr(0, 9);
    314 			}
    315 			else {
    316 				thisLine = "";
    317 			}
    318 
    319 			thisVal += (a > 0 ? "\n" : "") + thisLine;
    320 
    321 			outputs[POLY_OUTPUT].setVoltage(logLines[a], a);
    322 		}
    323 		strValue = thisVal;
    324 	}
    325 }
    326 struct HidableSmallSnapKnob : SmallSnapKnob {
    327 	bool visible = true;
    328 	int hackIndex = 0;
    329 	ComputerscareDebug *module;
    330 
    331 	HidableSmallSnapKnob() {
    332 		SmallSnapKnob();
    333 	}
    334 	void draw(const DrawArgs &args) override {
    335 		if (module ? (hackIndex == 0 ? module->clockMode == 0 : module->inputMode == 0) : true) {
    336 			Widget::draw(args);
    337 		}
    338 	};
    339 };
    340 ////////////////////////////////////
    341 struct StringDisplayWidget3 : Widget {
    342 
    343 	std::string value;
    344 	std::string fontPath = "res/Oswald-Regular.ttf";
    345 	ComputerscareDebug * module;
    346 
    347 	StringDisplayWidget3() {
    348 	};
    349 
    350 	void draw(const DrawArgs &ctx) override
    351 	{
    352 		// Background
    353 		NVGcolor backgroundColor = nvgRGB(0x10, 0x00, 0x10);
    354 		NVGcolor StrokeColor = nvgRGB(0xC0, 0xC7, 0xDE);
    355 		nvgBeginPath(ctx.vg);
    356 		nvgRoundedRect(ctx.vg, -1.0, -1.0, box.size.x + 2, box.size.y + 2, 4.0);
    357 		nvgFillColor(ctx.vg, StrokeColor);
    358 		nvgFill(ctx.vg);
    359 		nvgBeginPath(ctx.vg);
    360 		nvgRoundedRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, 4.0);
    361 		nvgFillColor(ctx.vg, backgroundColor);
    362 		nvgFill(ctx.vg);
    363 	}
    364 	void drawLayer(const BGPanel::DrawArgs& args, int layer) override {
    365 		if (layer == 1) {
    366 
    367 			std::shared_ptr<Font> font = APP->window->loadFont(asset::plugin(pluginInstance, fontPath));
    368 
    369 			//text
    370 			nvgFontSize(args.vg, 15);
    371 			nvgFontFaceId(args.vg, font->handle);
    372 			nvgTextLetterSpacing(args.vg, 2.5);
    373 
    374 			std::string textToDraw = module ? module->strValue : noModuleStringValue;
    375 			Vec textPos = Vec(6.0f, 12.0f);
    376 			NVGcolor textColor = nvgRGB(0xC0, 0xE7, 0xDE);
    377 			nvgFillColor(args.vg, textColor);
    378 			nvgTextBox(args.vg, textPos.x, textPos.y, 80, textToDraw.c_str(), NULL);
    379 		}
    380 		Widget::drawLayer(args, layer);
    381 	}
    382 };
    383 struct ConnectedSmallLetter : SmallLetterDisplay {
    384 	ComputerscareDebug *module;
    385 	int index;
    386 	ConnectedSmallLetter(int dex) {
    387 		index = dex;
    388 		value = std::to_string(dex + 1);
    389 	}
    390 	void draw(const DrawArgs &ctx) override {
    391 		if (module) {
    392 			int cm = module->clockMode;
    393 			int im = module->inputMode;
    394 			int cc = module->clockChannel;
    395 			int ic = module->inputChannel;
    396 
    397 			// both:pink
    398 			// clock: green
    399 			// input:yellow
    400 			baseColor = COLOR_COMPUTERSCARE_TRANSPARENT;
    401 			if (cm == 0 && im == 0 && cc == index && ic == index)  {
    402 				baseColor = COLOR_COMPUTERSCARE_PINK;
    403 			}
    404 			else {
    405 				if (cm == 0 && cc == index) {
    406 					baseColor = COLOR_COMPUTERSCARE_LIGHT_GREEN;
    407 				}
    408 				if (im == 0 && ic == index) {
    409 					baseColor = COLOR_COMPUTERSCARE_YELLOW;
    410 				}
    411 			}
    412 		}
    413 		SmallLetterDisplay::draw(ctx);
    414 	}
    415 };
    416 struct ComputerscareDebugWidget : ModuleWidget {
    417 
    418 	ComputerscareDebugWidget(ComputerscareDebug *module) {
    419 		setModule(module);
    420 		setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/ComputerscareDebugPanel.svg")));
    421 
    422 		addInput(createInput<InPort>(Vec(2, 335), module, ComputerscareDebug::TRG_INPUT));
    423 		addInput(createInput<InPort>(Vec(61, 335),  module, ComputerscareDebug::VAL_INPUT));
    424 		addInput(createInput<InPort>(Vec(31, 335), module, ComputerscareDebug::CLR_INPUT));
    425 
    426 		addParam(createParam<ComputerscareClockButton>(Vec(2, 321), module, ComputerscareDebug::MANUAL_TRIGGER));
    427 
    428 		addParam(createParam<ComputerscareResetButton>(Vec(32, 320), module, ComputerscareDebug::MANUAL_CLEAR_TRIGGER));
    429 
    430 		addParam(createParam<ThreeVerticalXSwitch>(Vec(2, 279), module, ComputerscareDebug::WHICH_CLOCK));
    431 		addParam(createParam<ThreeVerticalXSwitch>(Vec(66, 279), module, ComputerscareDebug::SWITCH_VIEW));
    432 
    433 		HidableSmallSnapKnob *clockKnob = createParam<HidableSmallSnapKnob>(Vec(6, 305), module, ComputerscareDebug::CLOCK_CHANNEL_FOCUS);
    434 		clockKnob->module = module;
    435 		clockKnob->hackIndex = 0;
    436 		addParam(clockKnob);
    437 
    438 		HidableSmallSnapKnob *inputKnob = createParam<HidableSmallSnapKnob>(Vec(66, 305), module, ComputerscareDebug::INPUT_CHANNEL_FOCUS);
    439 		inputKnob->module = module;
    440 		inputKnob->hackIndex = 1;
    441 		addParam(inputKnob);
    442 
    443 		addOutput(createOutput<OutPort>(Vec(56, 1), module, ComputerscareDebug::POLY_OUTPUT));
    444 
    445 		for (int i = 0; i < 16; i++) {
    446 			ConnectedSmallLetter *sld = new ConnectedSmallLetter(i);
    447 			sld->fontSize = 15;
    448 			sld->textAlign = 1;
    449 			sld->box.pos = Vec(-4, 33.8 + 15.08 * i);
    450 			sld->box.size = Vec(28, 20);
    451 			sld->module = module;
    452 			addChild(sld);
    453 		}
    454 
    455 		StringDisplayWidget3 *stringDisplay = createWidget<StringDisplayWidget3>(Vec(15, 34));
    456 		stringDisplay->box.size = Vec(73, 245);
    457 		stringDisplay->module = module;
    458 		addChild(stringDisplay);
    459 
    460 		debug = module;
    461 	}
    462 	/*json_t *toJson() override
    463 	{
    464 		json_t *rootJ = ModuleWidget::toJson();
    465 		json_object_set_new(rootJ, "outputRange", json_integer(debug->outputRangeEnum));
    466 
    467 		json_t *sequencesJ = json_array();
    468 
    469 		for (int i = 0; i < 16; i++) {
    470 			json_t *sequenceJ = json_real(debug->logLines[i]);
    471 			json_array_append_new(sequencesJ, sequenceJ);
    472 		}
    473 		json_object_set_new(rootJ, "lines", sequencesJ);
    474 		return rootJ;
    475 	}*/
    476 	/*void fromJson(json_t *rootJ) override
    477 	{
    478 		float val;
    479 		ModuleWidget::fromJson(rootJ);
    480 		// button states
    481 
    482 		json_t *outputRangeEnumJ = json_object_get(rootJ, "outputRange");
    483 		if (outputRangeEnumJ) { debug->outputRangeEnum = json_integer_value(outputRangeEnumJ); }
    484 
    485 		json_t *sequencesJ = json_object_get(rootJ, "lines");
    486 
    487 		if (sequencesJ) {
    488 			for (int i = 0; i < 16; i++) {
    489 				json_t *sequenceJ = json_array_get(sequencesJ, i);
    490 				if (sequenceJ)
    491 					val = json_real_value(sequenceJ);
    492 				debug->logLines[i] = val;
    493 			}
    494 		}
    495 
    496 
    497 	}*/
    498 	void appendContextMenu(Menu *menu) override;
    499 	ComputerscareDebug *debug;
    500 };
    501 struct DebugOutputRangeItem : MenuItem {
    502 	ComputerscareDebug *debug;
    503 	int outputRangeEnum;
    504 	void onAction(const event::Action &e) override {
    505 		debug->outputRangeEnum = outputRangeEnum;
    506 		printf("outputRangeEnum %i\n", outputRangeEnum);
    507 	}
    508 	void step() override {
    509 		rightText = CHECKMARK(debug->outputRangeEnum == outputRangeEnum);
    510 		MenuItem::step();
    511 	}
    512 };
    513 void ComputerscareDebugWidget::appendContextMenu(Menu *menu)
    514 {
    515 	ComputerscareDebug *debug = dynamic_cast<ComputerscareDebug *>(this->module);
    516 
    517 	MenuLabel *spacerLabel = new MenuLabel();
    518 	menu->addChild(spacerLabel);
    519 
    520 	menu->addChild(construct<MenuLabel>());
    521 	menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Random Generator Range (Internal In)"));
    522 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, "  0v ... +10v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 0));
    523 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, " -5v ...  +5v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 1));
    524 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, "  0v ...  +5v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 2));
    525 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, "  0v ...  +1v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 3));
    526 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, " -1v ...  +1v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 4));
    527 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, "-10v ... +10v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 5));
    528 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, " -2v ...  +2v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 6));
    529 	menu->addChild(construct<DebugOutputRangeItem>(&MenuItem::text, "  0v ...  +2v", &DebugOutputRangeItem::debug, debug, &DebugOutputRangeItem::outputRangeEnum, 7));
    530 
    531 }
    532 Model *modelComputerscareDebug = createModel<ComputerscareDebug, ComputerscareDebugWidget>("computerscare-debug");