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.

160 lines
5.1KB

  1. #include "plugin.hpp"
  2. using simd::float_4;
  3. struct RandomValues : Module {
  4. enum ParamId {
  5. PUSH_PARAM,
  6. PARAMS_LEN
  7. };
  8. enum InputId {
  9. TRIG_INPUT,
  10. INPUTS_LEN
  11. };
  12. enum OutputId {
  13. ENUMS(RND_OUTPUTS, 7),
  14. OUTPUTS_LEN
  15. };
  16. enum LightId {
  17. PUSH_LIGHT,
  18. LIGHTS_LEN
  19. };
  20. dsp::BooleanTrigger pushTrigger;
  21. dsp::TSchmittTrigger<float_4> trigTriggers[4];
  22. float values[7][16] = {};
  23. float randomGain = 10.f;
  24. float randomOffset = 0.f;
  25. RandomValues() {
  26. config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
  27. configButton(PUSH_PARAM, "Push");
  28. configInput(TRIG_INPUT, "Trigger");
  29. for (int i = 0; i < 7; i++)
  30. configOutput(RND_OUTPUTS + i, string::f("Random %d", i + 1));
  31. // Initialize values of all channels
  32. for (int c = 0; c < 16; c++) {
  33. randomizeValues(c);
  34. }
  35. }
  36. void onReset(const ResetEvent& e) override {
  37. Module::onReset(e);
  38. randomGain = 10.f;
  39. randomOffset = 0.f;
  40. }
  41. void process(const ProcessArgs& args) override {
  42. int channels = std::max(1, inputs[TRIG_INPUT].getChannels());
  43. bool pushed = pushTrigger.process(params[PUSH_PARAM].getValue());
  44. bool light = false;
  45. for (int c = 0; c < channels; c += 4) {
  46. float_4 triggered = trigTriggers[c / 4].process(inputs[TRIG_INPUT].getVoltageSimd<float_4>(c), 0.1f, 1.f);
  47. int triggeredMask = simd::movemask(triggered);
  48. // This branch is infrequent so we don't need to use SIMD.
  49. if (pushed || triggeredMask) {
  50. light = true;
  51. for (int c2 = 0; c2 < std::min(4, channels - c); c2++) {
  52. if (pushed || (triggeredMask & (1 << c2))) {
  53. randomizeValues(c + c2);
  54. }
  55. }
  56. }
  57. }
  58. for (int i = 0; i < 7; i++) {
  59. outputs[RND_OUTPUTS + i].setChannels(channels);
  60. outputs[RND_OUTPUTS + i].writeVoltages(values[i]);
  61. }
  62. lights[PUSH_LIGHT].setBrightnessSmooth(light, args.sampleTime);
  63. }
  64. void randomizeValues(int channel) {
  65. for (int i = 0; i < 7; i++) {
  66. values[i][channel] = random::get<float>() * randomGain + randomOffset;
  67. }
  68. }
  69. json_t* dataToJson() override {
  70. json_t* rootJ = json_object();
  71. json_t* valuesJ = json_array();
  72. for (int i = 0; i < 7; i++) {
  73. json_t* channelsJ = json_array();
  74. for (int c = 0; c < 16; c++) {
  75. json_array_insert_new(channelsJ, c, json_real(values[i][c]));
  76. }
  77. json_array_insert_new(valuesJ, i, channelsJ);
  78. }
  79. json_object_set_new(rootJ, "values", valuesJ);
  80. json_object_set_new(rootJ, "randomGain", json_real(randomGain));
  81. json_object_set_new(rootJ, "randomOffset", json_real(randomOffset));
  82. return rootJ;
  83. }
  84. void dataFromJson(json_t* rootJ) override {
  85. json_t* valuesJ = json_object_get(rootJ, "values");
  86. if (valuesJ)
  87. for (int i = 0; i < 7; i++) {
  88. json_t* channelsJ = json_array_get(valuesJ, i);
  89. if (channelsJ)
  90. for (int c = 0; c < 16; c++) {
  91. json_t* valueJ = json_array_get(channelsJ, c);
  92. if (valueJ)
  93. values[i][c] = json_number_value(valueJ);
  94. }
  95. }
  96. json_t* randomGainJ = json_object_get(rootJ, "randomGain");
  97. if (randomGainJ)
  98. randomGain = json_number_value(randomGainJ);
  99. json_t* randomOffsetJ = json_object_get(rootJ, "randomOffset");
  100. if (randomOffsetJ)
  101. randomOffset = json_number_value(randomOffsetJ);
  102. }
  103. };
  104. struct RandomValuesWidget : ModuleWidget {
  105. RandomValuesWidget(RandomValues* module) {
  106. setModule(module);
  107. setPanel(createPanel(asset::plugin(pluginInstance, "res/RandomValues.svg"), asset::plugin(pluginInstance, "res/RandomValues-dark.svg")));
  108. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, 0)));
  109. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  110. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  111. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  112. addParam(createLightParamCentered<LEDLightBezel<>>(mm2px(Vec(7.62, 21.968)), module, RandomValues::PUSH_PARAM, RandomValues::PUSH_LIGHT));
  113. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 38.225)), module, RandomValues::TRIG_INPUT));
  114. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 52.35)), module, RandomValues::RND_OUTPUTS + 0));
  115. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 62.477)), module, RandomValues::RND_OUTPUTS + 1));
  116. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 72.605)), module, RandomValues::RND_OUTPUTS + 2));
  117. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 82.732)), module, RandomValues::RND_OUTPUTS + 3));
  118. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 92.86)), module, RandomValues::RND_OUTPUTS + 4));
  119. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 102.987)), module, RandomValues::RND_OUTPUTS + 5));
  120. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.622, 113.013)), module, RandomValues::RND_OUTPUTS + 6));
  121. }
  122. void appendContextMenu(Menu* menu) override {
  123. RandomValues* module = getModule<RandomValues>();
  124. menu->addChild(new MenuSeparator);
  125. menu->addChild(createRangeItem("Random range", &module->randomGain, &module->randomOffset));
  126. }
  127. };
  128. Model* modelRandomValues = createModel<RandomValues, RandomValuesWidget>("RandomValues");