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.

174 lines
3.8KB

  1. #include "util/common.hpp"
  2. #include "dsp/digital.hpp"
  3. #include "dsp/noise.hpp"
  4. #include "AH.hpp"
  5. #include "Core.hpp"
  6. #include "UI.hpp"
  7. namespace rack_plugin_AmalgamatedHarmonics {
  8. struct SLN : AHModule {
  9. enum ParamIds {
  10. SPEED_PARAM,
  11. SLOPE_PARAM,
  12. NOISE_PARAM,
  13. NUM_PARAMS
  14. };
  15. enum InputIds {
  16. TRIG_INPUT,
  17. NUM_INPUTS
  18. };
  19. enum OutputIds {
  20. OUT_OUTPUT,
  21. NOISE_OUTPUT,
  22. NUM_OUTPUTS
  23. };
  24. enum LightIds {
  25. NUM_LIGHTS
  26. };
  27. SLN() : AHModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  28. }
  29. void step() override;
  30. Core core;
  31. SchmittTrigger inTrigger;
  32. bogaudio_dsp::WhiteNoiseGenerator white;
  33. bogaudio_dsp::PinkNoiseGenerator pink;
  34. bogaudio_dsp::RedNoiseGenerator brown;
  35. float target = 0.0f;
  36. float current = 0.0f;
  37. // minimum and maximum slopes in volts per second
  38. const float slewMin = 0.1f;
  39. const float slewMax = 10000.0f;
  40. const float slewRatio = slewMin / slewMax;
  41. // Amount of extra slew per voltage difference
  42. const float shapeScale = 1.0f/10.0f;
  43. };
  44. void SLN::step() {
  45. AHModule::step();
  46. float noise;
  47. int noiseType = params[NOISE_PARAM].value;
  48. switch(noiseType) {
  49. case 0:
  50. noise = white.next() * 10.0f;
  51. break;
  52. case 1:
  53. noise = pink.next() * 10.8f; // scale to -10 to 10;
  54. break;
  55. case 2:
  56. noise = brown.next() * 23.4f; // scale to -10 to 10;
  57. break;
  58. default:
  59. noise = white.next() * 10.0f;
  60. }
  61. // Capture noise
  62. if (inTrigger.process(inputs[TRIG_INPUT].value / 0.7)) {
  63. target = noise;
  64. }
  65. float shape = params[SLOPE_PARAM].value;
  66. float speed = params[SPEED_PARAM].value;
  67. float slew = slewMax * powf(slewRatio, speed);
  68. // Rise
  69. if (target > current) {
  70. current += slew * crossfade(1.0f, shapeScale * (target - current), shape) * delta;
  71. if (current > target) // Trap overshoot
  72. current = target;
  73. }
  74. // Fall
  75. else if (target < current) {
  76. current -= slew * crossfade(1.0f, shapeScale * (current - target), shape) * delta;
  77. if (current < target) // Trap overshoot
  78. current = target;
  79. }
  80. outputs[OUT_OUTPUT].value = current;
  81. outputs[NOISE_OUTPUT].value = noise;
  82. }
  83. struct SLNWidget : ModuleWidget {
  84. SLNWidget(SLN *module);
  85. };
  86. SLNWidget::SLNWidget(SLN *module) : ModuleWidget(module) {
  87. UI ui;
  88. box.size = Vec(45, 380);
  89. {
  90. SVGPanel *panel = new SVGPanel();
  91. panel->box.size = box.size;
  92. panel->setBackground(SVG::load(assetPlugin(plugin, "res/SLN.svg")));
  93. addChild(panel);
  94. }
  95. float panelwidth = 45.0;
  96. float portwidth = 25.0;
  97. float knobwidth = 23.0;
  98. float portX = (panelwidth - portwidth) / 2.0;
  99. float knobX = (panelwidth - knobwidth) / 2.0;
  100. Vec p1 = ui.getPosition(UI::PORT, 0, 0, false, false);
  101. p1.x = portX;
  102. addInput(Port::create<PJ301MPort>(p1, Port::INPUT, module, SLN::TRIG_INPUT));
  103. Vec p2 = ui.getPosition(UI::PORT, 0, 4, false, false);
  104. p2.x = portX;
  105. addOutput(Port::create<PJ301MPort>(p2, Port::OUTPUT, module, SLN::OUT_OUTPUT));
  106. Vec p3 = ui.getPosition(UI::PORT, 0, 5, false, false);
  107. p3.x = portX;
  108. addOutput(Port::create<PJ301MPort>(p3, Port::OUTPUT, module, SLN::NOISE_OUTPUT));
  109. Vec k1 = ui.getPosition(UI::PORT, 0, 1, false, false);
  110. k1.x = knobX;
  111. AHKnobNoSnap *speedW = ParamWidget::create<AHKnobNoSnap>(k1, module, SLN::SPEED_PARAM, 0.0, 1.0, 0.0);
  112. addParam(speedW);
  113. Vec k2 = ui.getPosition(UI::PORT, 0, 2, false, false);
  114. k2.x = knobX;
  115. AHKnobNoSnap *slopeW = ParamWidget::create<AHKnobNoSnap>(k2, module, SLN::SLOPE_PARAM, 0.0, 1.0, 0.0);
  116. addParam(slopeW);
  117. Vec k3 = ui.getPosition(UI::PORT, 0, 3, false, false);
  118. k3.x = knobX;
  119. AHKnobSnap *noiseW = ParamWidget::create<AHKnobSnap>(k3, module, SLN::NOISE_PARAM, 0.0, 2.0, 0.0);
  120. addParam(noiseW);
  121. }
  122. } // namespace rack_plugin_AmalgamatedHarmonics
  123. using namespace rack_plugin_AmalgamatedHarmonics;
  124. RACK_PLUGIN_MODEL_INIT(AmalgamatedHarmonics, SLN) {
  125. Model *modelSLN = Model::create<SLN, SLNWidget>( "Amalgamated Harmonics", "SLN", "SLN", NOISE_TAG);
  126. return modelSLN;
  127. }