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.

244 lines
6.2KB

  1. #include "HetrickCV.hpp"
  2. namespace rack_plugin_HetrickCV {
  3. #ifdef USE_VST2
  4. #define plugin "HetrickCV"
  5. #endif // USE_VST2
  6. struct RandomGates : Module
  7. {
  8. enum ParamIds
  9. {
  10. MIN_PARAM,
  11. MAX_PARAM,
  12. MODE_PARAM,
  13. MODE_PARAM_INVIS,
  14. NUM_PARAMS
  15. };
  16. enum InputIds
  17. {
  18. CLOCK_INPUT,
  19. MINI_INPUT,
  20. MAXI_INPUT,
  21. NUM_INPUTS
  22. };
  23. enum OutputIds
  24. {
  25. OUT1_OUTPUT,
  26. OUT2_OUTPUT,
  27. OUT3_OUTPUT,
  28. OUT4_OUTPUT,
  29. OUT5_OUTPUT,
  30. OUT6_OUTPUT,
  31. OUT7_OUTPUT,
  32. OUT8_OUTPUT,
  33. NUM_OUTPUTS
  34. };
  35. enum LightIds
  36. {
  37. CLOCK_LIGHT,
  38. MODE_TRIG_LIGHT,
  39. MODE_GATE_LIGHT,
  40. MODE_HOLD_LIGHT,
  41. OUT1_LIGHT,
  42. OUT2_LIGHT,
  43. OUT3_LIGHT,
  44. OUT4_LIGHT,
  45. OUT5_LIGHT,
  46. OUT6_LIGHT,
  47. OUT7_LIGHT,
  48. OUT8_LIGHT,
  49. NUM_LIGHTS
  50. };
  51. RandomGates() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS)
  52. {
  53. }
  54. void step() override;
  55. int clampInt(const int _in, const int min = 0, const int max = 7)
  56. {
  57. if (_in > max) return max;
  58. if (_in < min) return min;
  59. return _in;
  60. }
  61. SchmittTrigger clockTrigger;
  62. SchmittTrigger modeTrigger;
  63. TriggerGenerator trigger[8];
  64. SchmittTrigger trigOut[8];
  65. bool active[8] = {};
  66. int mode = 0;
  67. json_t *toJson() override
  68. {
  69. json_t *rootJ = json_object();
  70. json_object_set_new(rootJ, "mode", json_integer(mode));
  71. return rootJ;
  72. }
  73. void fromJson(json_t *rootJ) override
  74. {
  75. json_t *modeJ = json_object_get(rootJ, "mode");
  76. if (modeJ)
  77. mode = json_integer_value(modeJ);
  78. }
  79. void reset() override
  80. {
  81. mode = 0;
  82. }
  83. void randomize() override
  84. {
  85. mode = round(randomf() * 2.0f);
  86. }
  87. // For more advanced Module features, read Rack's engine.hpp header file
  88. // - toJson, fromJson: serialization of internal data
  89. // - onSampleRateChange: event triggered by a change of sample rate
  90. // - reset, randomize: implements special behavior when user clicks these from the context menu
  91. };
  92. void RandomGates::step()
  93. {
  94. int max = round(params[MAX_PARAM].value + inputs[MAXI_INPUT].value);
  95. int min = round(params[MIN_PARAM].value + inputs[MINI_INPUT].value);
  96. max = clampInt(max);
  97. min = clampInt(min);
  98. if (min > max) min = max;
  99. const bool clockHigh = inputs[CLOCK_INPUT].value > 1.0f;
  100. if (modeTrigger.process(params[MODE_PARAM].value))
  101. {
  102. mode = (mode + 1) % 3;
  103. }
  104. if (clockTrigger.process(clockHigh))
  105. {
  106. uint32_t range = max-min;
  107. uint32_t randNum;
  108. if (range == 0) randNum = max;
  109. else randNum = (randomu32() % (range + 1)) + min;
  110. for(uint32_t i = 0; i < 8; i++)
  111. {
  112. active[i] = randNum == i;
  113. }
  114. }
  115. lights[MODE_TRIG_LIGHT].setBrightness(mode == 0 ? 1.0f : 0.0f);
  116. lights[MODE_HOLD_LIGHT].setBrightness(mode == 1 ? 1.0f : 0.0f);
  117. lights[MODE_GATE_LIGHT].setBrightness(mode == 2 ? 1.0f : 0.0f);
  118. switch(mode)
  119. {
  120. case 0: //trigger mode
  121. for(int i = 0; i < 8; i++)
  122. {
  123. if(trigOut[i].process(active[i]))
  124. {
  125. trigger[i].trigger();
  126. active[i] = false;
  127. }
  128. outputs[i].value = (trigger[i].process() ? 5.0f : 0.0f);
  129. }
  130. break;
  131. case 1: //hold mode
  132. for(int i = 0; i < 8; i++)
  133. {
  134. outputs[i].value = (active[i] ? 5.0f : 0.0f);
  135. }
  136. break;
  137. case 2: //gate mode
  138. for(int i = 0; i < 8; i++)
  139. {
  140. outputs[i].value = ((active[i] && clockHigh) ? 5.0f : 0.0f);
  141. }
  142. break;
  143. default:
  144. break;
  145. }
  146. for(int i = 0; i < 8; i++)
  147. {
  148. lights[OUT1_LIGHT + i].setBrightnessSmooth(fmaxf(0.0, outputs[i].value));
  149. }
  150. }
  151. struct RandomGatesWidget : ModuleWidget { RandomGatesWidget(RandomGates *module); };
  152. RandomGatesWidget::RandomGatesWidget(RandomGates *module) : ModuleWidget(module)
  153. {
  154. box.size = Vec(12 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  155. {
  156. auto *panel = new SVGPanel();
  157. panel->box.size = box.size;
  158. panel->setBackground(SVG::load(assetPlugin(plugin, "res/RandomGates.svg")));
  159. addChild(panel);
  160. }
  161. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  162. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  163. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  164. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  165. //const int inXPos = 10;
  166. const int outXPos = 145;
  167. const int outLightX = 120;
  168. const int inLightX = 45;
  169. addInput(Port::create<PJ301MPort>(Vec(58, 90), Port::INPUT, module, RandomGates::CLOCK_INPUT));
  170. addParam(ParamWidget::create<Davies1900hBlackKnob>(Vec(10, 145), module, RandomGates::MIN_PARAM, 0, 7.0, 0.0));
  171. addParam(ParamWidget::create<Davies1900hBlackKnob>(Vec(10, 205), module, RandomGates::MAX_PARAM, 0, 7.0, 7.0));
  172. addInput(Port::create<PJ301MPort>(Vec(58, 150), Port::INPUT, module, RandomGates::MINI_INPUT));
  173. addInput(Port::create<PJ301MPort>(Vec(58, 210), Port::INPUT, module, RandomGates::MAXI_INPUT));
  174. addParam(ParamWidget::create<CKD6>(Vec(56, 270), module, RandomGates::MODE_PARAM, 0.0, 1.0, 0.0));
  175. //////BLINKENLIGHTS//////
  176. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(inLightX, 306), module, RandomGates::MODE_TRIG_LIGHT));
  177. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(inLightX, 319), module, RandomGates::MODE_HOLD_LIGHT));
  178. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(inLightX, 332), module, RandomGates::MODE_GATE_LIGHT));
  179. for(int i = 0; i < 8; i++)
  180. {
  181. const int yPos = 50 + (40 * i);
  182. const int lightY = 59 + (40 * i);
  183. //////OUTPUTS//////
  184. addOutput(Port::create<PJ301MPort>(Vec(outXPos, yPos), Port::OUTPUT, module, i));
  185. //////BLINKENLIGHTS//////
  186. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(outLightX, lightY), module, RandomGates::OUT1_LIGHT + i));
  187. }
  188. }
  189. } // namespace rack_plugin_HetrickCV
  190. using namespace rack_plugin_HetrickCV;
  191. RACK_PLUGIN_MODEL_INIT(HetrickCV, RandomGates) {
  192. Model *modelRandomGates = Model::create<RandomGates, RandomGatesWidget>("HetrickCV", "RandomGates", "Random Gates", RANDOM_TAG);
  193. return modelRandomGates;
  194. }