You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
3.5KB

  1. #include "dsp/digital.hpp"
  2. #include "util/math.hpp"
  3. #include "qwelk.hpp"
  4. #define CHANNELS 8
  5. namespace rack_plugin_Qwelk {
  6. struct ModuleByte : Module {
  7. enum ParamIds {
  8. PARAM_SCAN,
  9. NUM_PARAMS
  10. };
  11. enum InputIds {
  12. INPUT_SCAN,
  13. INPUT_GATE,
  14. NUM_INPUTS = INPUT_GATE + CHANNELS
  15. };
  16. enum OutputIds {
  17. OUTPUT_COUNT,
  18. OUTPUT_NUMBER,
  19. NUM_OUTPUTS
  20. };
  21. enum LightIds {
  22. LIGHT_POS_SCAN,
  23. LIGHT_NEG_SCAN,
  24. NUM_LIGHTS,
  25. };
  26. int scan = 1;
  27. int scan_sign = 0;
  28. SchmittTrigger trig_scan_input;
  29. SchmittTrigger trig_scan_manual;
  30. const float output_volt_uni = 10.0;
  31. ModuleByte() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  32. void step() override;
  33. };
  34. void ModuleByte::step()
  35. {
  36. // determine scan direction
  37. int scan_input_sign = (int)sgn(inputs[INPUT_SCAN].normalize(scan));
  38. if (scan_input_sign != scan_sign)
  39. scan = scan_sign = scan_input_sign;
  40. // manual tinkering with step?
  41. if (trig_scan_manual.process(params[PARAM_SCAN].value))
  42. scan *= -1;
  43. int active_count = 0, count = 0, number = 0;
  44. for (int i = 0; i < CHANNELS; ++i) {
  45. int bit = scan >= 0 ? i : (CHANNELS - 1 - i);
  46. int above0 = inputs[INPUT_GATE + i].value > 0 ? 1 : 0;
  47. active_count += inputs[INPUT_GATE + i].active ? 1 : 0;
  48. count += above0;
  49. if (above0)
  50. number |= 1 << bit;
  51. }
  52. outputs[OUTPUT_COUNT].value = active_count ? ((float)count / active_count) * output_volt_uni : 0.0f;
  53. outputs[OUTPUT_NUMBER].value = ((float)number / (float)(1 << (CHANNELS - 1))) * output_volt_uni;
  54. // indicate step direction
  55. lights[LIGHT_POS_SCAN].setBrightness(scan < 0 ? 0.0 : 0.9);
  56. lights[LIGHT_NEG_SCAN].setBrightness(scan < 0 ? 0.9 : 0.0);
  57. }
  58. template <typename _BASE>
  59. struct MuteLight : _BASE {
  60. MuteLight()
  61. {
  62. this->box.size = mm2px(Vec(6, 6));
  63. }
  64. };
  65. struct WidgetByte : ModuleWidget {
  66. WidgetByte(ModuleByte *module);
  67. };
  68. WidgetByte::WidgetByte(ModuleByte *module) : ModuleWidget(module) {
  69. setPanel(SVG::load(assetPlugin(plugin, "res/Byte.svg")));
  70. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  71. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  72. const float ypad = 27.5;
  73. float x = box.size.x / 2.0 - 25.0 / 2.0;
  74. float ytop = 90.5;
  75. addParam(ParamWidget::create<LEDBezel>(Vec(x + 1.5, ytop - ypad * 2 - 3.5), module, ModuleByte::PARAM_SCAN, 0.0, 1.0, 0.0));
  76. addChild(ModuleLightWidget::create<MuteLight<GreenRedLight>>(Vec(x + 3.75, ytop - ypad * 2 + - 3.5 + 2), module, ModuleByte::LIGHT_POS_SCAN));
  77. addInput(Port::create<PJ301MPort>(Vec(x, ytop - ypad + 1), Port::INPUT, module, ModuleByte::INPUT_SCAN));
  78. //ytop += ypad * 0.25;
  79. for (int i = 0; i < CHANNELS; ++i) {
  80. addInput(Port::create<PJ301MPort>(Vec(x, ytop + ypad * i), Port::INPUT, module, ModuleByte::INPUT_GATE + i));
  81. }
  82. //ytop += ypad * 0.25;
  83. const float output_y = ytop + ypad * CHANNELS;
  84. addOutput(Port::create<PJ301MPort>(Vec(x, output_y ), Port::OUTPUT, module, ModuleByte::OUTPUT_NUMBER));
  85. addOutput(Port::create<PJ301MPort>(Vec(x, output_y + ypad ), Port::OUTPUT, module, ModuleByte::OUTPUT_COUNT));
  86. }
  87. } // namespace rack_plugin_Qwelk
  88. using namespace rack_plugin_Qwelk;
  89. RACK_PLUGIN_MODEL_INIT(Qwelk, Byte) {
  90. Model *modelByte = Model::create<ModuleByte, WidgetByte>(
  91. TOSTRING(SLUG), "Byte", "Byte", UTILITY_TAG, LOGIC_TAG);
  92. return modelByte;
  93. }