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.

205 lines
5.9KB

  1. #include "plugin.hpp"
  2. struct Random : Module {
  3. enum ParamIds {
  4. RATE_PARAM,
  5. SHAPE_PARAM,
  6. OFFSET_PARAM,
  7. MODE_PARAM,
  8. NUM_PARAMS
  9. };
  10. enum InputIds {
  11. RATE_INPUT,
  12. SHAPE_INPUT,
  13. TRIGGER_INPUT,
  14. EXTERNAL_INPUT,
  15. NUM_INPUTS
  16. };
  17. enum OutputIds {
  18. STEPPED_OUTPUT,
  19. LINEAR_OUTPUT,
  20. SMOOTH_OUTPUT,
  21. EXPONENTIAL_OUTPUT,
  22. NUM_OUTPUTS
  23. };
  24. enum LightIds {
  25. RATE_LIGHT,
  26. SHAPE_LIGHT,
  27. NUM_LIGHTS
  28. };
  29. dsp::SchmittTrigger trigTrigger;
  30. float lastValue = 0.f;
  31. float value = 0.f;
  32. float clockPhase = 0.f;
  33. int trigFrame = 0;
  34. int lastTrigFrames = INT_MAX;
  35. Random() {
  36. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  37. configParam(RATE_PARAM, std::log2(0.002f), std::log2(2000.f), std::log2(2.f), "Rate", " Hz", 2);
  38. configParam(SHAPE_PARAM, 0.f, 1.f, 0.5f, "Shape", "%", 0, 100);
  39. configParam(OFFSET_PARAM, 0.f, 1.f, 1.f, "Bipolar/unipolar");
  40. configParam(MODE_PARAM, 0.f, 1.f, 1.f, "Relative/absolute randomness");
  41. }
  42. void trigger() {
  43. lastValue = value;
  44. if (inputs[EXTERNAL_INPUT].isConnected()) {
  45. value = inputs[EXTERNAL_INPUT].getVoltage() / 10.f;
  46. }
  47. else {
  48. // Choose a new random value
  49. bool absolute = params[MODE_PARAM].getValue() > 0.f;
  50. bool uni = params[OFFSET_PARAM].getValue() > 0.f;
  51. if (absolute) {
  52. value = random::uniform();
  53. if (!uni)
  54. value -= 0.5f;
  55. }
  56. else {
  57. // Switch to uni if bi
  58. if (!uni)
  59. value += 0.5f;
  60. float deltaValue = random::normal();
  61. // Bias based on value
  62. deltaValue -= (value - 0.5f) * 2.f;
  63. // Scale delta and accumulate value
  64. const float stdDev = 1 / 10.f;
  65. deltaValue *= stdDev;
  66. value += deltaValue;
  67. value = clamp(value, 0.f, 1.f);
  68. // Switch back to bi
  69. if (!uni)
  70. value -= 0.5f;
  71. }
  72. }
  73. lights[RATE_LIGHT].setBrightness(3.f);
  74. }
  75. void process(const ProcessArgs& args) override {
  76. if (inputs[TRIGGER_INPUT].isConnected()) {
  77. // Advance clock phase based on tempo estimate
  78. trigFrame++;
  79. float deltaPhase = 1.f / lastTrigFrames;
  80. clockPhase += deltaPhase;
  81. clockPhase = std::min(clockPhase, 1.f);
  82. // Trigger
  83. if (trigTrigger.process(rescale(inputs[TRIGGER_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
  84. clockPhase = 0.f;
  85. lastTrigFrames = trigFrame;
  86. trigFrame = 0;
  87. trigger();
  88. }
  89. }
  90. else {
  91. // Advance clock phase by rate
  92. float rate = params[RATE_PARAM].getValue();
  93. rate += inputs[RATE_PARAM].getVoltage();
  94. float clockFreq = std::pow(2.f, rate);
  95. float deltaPhase = std::fmin(clockFreq * args.sampleTime, 0.5f);
  96. clockPhase += deltaPhase;
  97. // Trigger
  98. if (clockPhase >= 1.f) {
  99. clockPhase -= 1.f;
  100. trigger();
  101. }
  102. }
  103. // Shape
  104. float shape = params[SHAPE_PARAM].getValue();
  105. shape += inputs[SHAPE_INPUT].getVoltage() / 10.f;
  106. shape = clamp(shape, 0.f, 1.f);
  107. // Stepped
  108. if (outputs[STEPPED_OUTPUT].isConnected()) {
  109. float steps = std::ceil(std::pow(shape, 2) * 15 + 1);
  110. float v = std::ceil(clockPhase * steps) / steps;
  111. v = rescale(v, 0.f, 1.f, lastValue, value);
  112. outputs[STEPPED_OUTPUT].setVoltage(v * 10.f);
  113. }
  114. // Linear
  115. if (outputs[LINEAR_OUTPUT].isConnected()) {
  116. float slope = 1 / shape;
  117. float v;
  118. if (slope < 1e6f) {
  119. v = std::fmin(clockPhase * slope, 1.f);
  120. }
  121. else {
  122. v = 1.f;
  123. }
  124. v = rescale(v, 0.f, 1.f, lastValue, value);
  125. outputs[LINEAR_OUTPUT].setVoltage(v * 10.f);
  126. }
  127. // Smooth
  128. if (outputs[SMOOTH_OUTPUT].isConnected()) {
  129. float p = 1 / shape;
  130. float v;
  131. if (p < 1e6f) {
  132. v = std::fmin(clockPhase * p, 1.f);
  133. v = std::cos(M_PI * v);
  134. }
  135. else {
  136. v = -1.f;
  137. }
  138. v = rescale(v, 1.f, -1.f, lastValue, value);
  139. outputs[SMOOTH_OUTPUT].setVoltage(v * 10.f);
  140. }
  141. // Exp
  142. if (outputs[EXPONENTIAL_OUTPUT].isConnected()) {
  143. float b = std::pow(shape, 4);
  144. float v;
  145. if (0.999f < b) {
  146. v = clockPhase;
  147. }
  148. else if (1e-20f < b) {
  149. v = (std::pow(b, clockPhase) - 1.f) / (b - 1.f);
  150. }
  151. else {
  152. v = 1.f;
  153. }
  154. v = rescale(v, 0.f, 1.f, lastValue, value);
  155. outputs[EXPONENTIAL_OUTPUT].setVoltage(v * 10.f);
  156. }
  157. // Lights
  158. lights[RATE_LIGHT].setSmoothBrightness(0.f, args.sampleTime);
  159. lights[SHAPE_LIGHT].setBrightness(shape);
  160. }
  161. };
  162. struct RandomWidget : ModuleWidget {
  163. RandomWidget(Random* module) {
  164. setModule(module);
  165. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Random.svg")));
  166. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  167. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  168. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  169. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  170. addParam(createLightParamCentered<LEDLightSliderFixed<GreenLight>>(mm2px(Vec(7.215, 30.858)), module, Random::RATE_PARAM, Random::RATE_LIGHT));
  171. addParam(createLightParamCentered<LEDLightSliderFixed<GreenLight>>(mm2px(Vec(18.214, 30.858)), module, Random::SHAPE_PARAM, Random::SHAPE_LIGHT));
  172. addParam(createParamCentered<CKSS>(mm2px(Vec(7.214, 78.259)), module, Random::OFFSET_PARAM));
  173. addParam(createParamCentered<CKSS>(mm2px(Vec(18.214, 78.259)), module, Random::MODE_PARAM));
  174. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.214, 50.726)), module, Random::RATE_INPUT));
  175. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.214, 50.726)), module, Random::SHAPE_INPUT));
  176. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.214, 64.513)), module, Random::TRIGGER_INPUT));
  177. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.214, 64.513)), module, Random::EXTERNAL_INPUT));
  178. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.214, 96.727)), module, Random::STEPPED_OUTPUT));
  179. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.214, 96.727)), module, Random::LINEAR_OUTPUT));
  180. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.214, 112.182)), module, Random::SMOOTH_OUTPUT));
  181. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.214, 112.182)), module, Random::EXPONENTIAL_OUTPUT));
  182. }
  183. };
  184. Model* modelRandom = createModel<Random, RandomWidget>("Random");