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");