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.

181 lines
5.5KB

  1. #include <iostream>
  2. #include <stdlib.h>
  3. #include <random>
  4. #include <cmath>
  5. #include "dsp/digital.hpp"
  6. #include "dsp/samplerate.hpp"
  7. #include "dsp/ringbuffer.hpp"
  8. #include "dsp/filter.hpp"
  9. #include "RJModules.hpp"
  10. #include "VAStateVariableFilter.h"
  11. namespace rack_plugin_RJModules {
  12. #define HISTORY_SIZE (1<<21)
  13. struct Widener : Module {
  14. enum ParamIds {
  15. TIME_PARAM,
  16. MIX_PARAM,
  17. FILTER_PARAM,
  18. NUM_PARAMS
  19. };
  20. enum InputIds {
  21. CH1_INPUT,
  22. TIME_CV_INPUT,
  23. MIX_CV_INPUT,
  24. FILTER_CV_INPUT,
  25. NUM_INPUTS
  26. };
  27. enum OutputIds {
  28. CH1_OUTPUT,
  29. CH2_OUTPUT,
  30. NUM_OUTPUTS
  31. };
  32. enum LightIds {
  33. NUM_LIGHTS
  34. };
  35. DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer;
  36. DoubleRingBuffer<float, 16> outBuffer;
  37. SampleRateConverter<1> src;
  38. float low = 99;
  39. float high = 0;
  40. float next;
  41. float mapped_pink = 0.0;
  42. float white = 0.0;
  43. float mixed = 0.0;
  44. float mix_value = 1.0;
  45. std::random_device rd; // obtain a random number from hardware
  46. float outLP;
  47. float outHP;
  48. VAStateVariableFilter *lpFilter = new VAStateVariableFilter() ; // create a lpFilter;
  49. VAStateVariableFilter *hpFilter = new VAStateVariableFilter() ; // create a hpFilter;
  50. Widener() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  51. void step() override;
  52. };
  53. void Widener::step(){
  54. float in = inputs[CH1_INPUT].value;
  55. // Compute delay time in seconds
  56. float delay = .001 * powf(10.0 / .001, clamp(params[TIME_PARAM].value + inputs[TIME_CV_INPUT].value / 10.0f, 0.0f, 1.0f));
  57. // Number of delay samples
  58. float index = delay * engineGetSampleRate();
  59. if (!historyBuffer.full()) {
  60. historyBuffer.push(in);
  61. }
  62. // How many samples do we need consume to catch up?
  63. float consume = index - historyBuffer.size();
  64. if (outBuffer.empty()) {
  65. double ratio = 1.0;
  66. if (consume <= -16)
  67. ratio = 0.5;
  68. else if (consume >= 16)
  69. ratio = 2.0;
  70. float inSR = engineGetSampleRate();
  71. float outSR = ratio * inSR;
  72. int inFrames = min(historyBuffer.size(), 16);
  73. int outFrames = outBuffer.capacity();
  74. src.setRates(inSR, outSR);
  75. src.process((const Frame<1>*)historyBuffer.startData(), &inFrames, (Frame<1>*)outBuffer.endData(), &outFrames);
  76. historyBuffer.startIncr(inFrames);
  77. outBuffer.endIncr(outFrames);
  78. }
  79. float wet = 0.0;
  80. if (!outBuffer.empty()) {
  81. wet = outBuffer.shift();
  82. }
  83. // filter the wet
  84. lpFilter->setFilterType(0);
  85. hpFilter->setFilterType(2);
  86. lpFilter->setResonance(.7);
  87. hpFilter->setResonance(.7);
  88. lpFilter->setSampleRate(engineGetSampleRate());
  89. hpFilter->setSampleRate(engineGetSampleRate());
  90. float param = params[FILTER_PARAM].value * clamp(inputs[FILTER_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  91. if(param < .5){
  92. // new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min
  93. float lp_cutoff = ( (param - 0) / (.5 - 0.0)) * (8000.0 - 30.0) + 30.0;
  94. lpFilter->setCutoffFreq(lp_cutoff);
  95. wet = lpFilter->processAudioSample(wet, 1);
  96. }
  97. if(param > .5){
  98. // new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min
  99. float hp_cutoff = ( (param - .5) / (1.0 - 0.5)) * (8000.0 - 200.0) + 200.0;
  100. hpFilter->setCutoffFreq(hp_cutoff);
  101. wet = hpFilter->processAudioSample(wet, 1);
  102. }
  103. // if(param == .5){
  104. // wet = wet;
  105. // }
  106. //mix
  107. float mix_percent = params[MIX_PARAM].value * clamp(inputs[MIX_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  108. float mixed = ((wet * mix_percent)) + (in * (1-mix_percent));
  109. outputs[CH1_OUTPUT].value = in;
  110. outputs[CH2_OUTPUT].value = mixed;
  111. }
  112. struct WidenerWidget: ModuleWidget {
  113. WidenerWidget(Widener *module);
  114. };
  115. WidenerWidget::WidenerWidget(Widener *module) : ModuleWidget(module) {
  116. box.size = Vec(15*10, 380);
  117. {
  118. SVGPanel *panel = new SVGPanel();
  119. panel->box.size = box.size;
  120. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Widener.svg")));
  121. addChild(panel);
  122. }
  123. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  124. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  125. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  126. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  127. addParam(ParamWidget::create<RoundHugeBlackKnob>(Vec(47, 61), module, Widener::TIME_PARAM, 0.0, 0.7, 0.35));
  128. addParam(ParamWidget::create<RoundHugeBlackKnob>(Vec(47, 143), module, Widener::MIX_PARAM, 0.0, 1.0, 1.0));
  129. addParam(ParamWidget::create<RoundHugeBlackKnob>(Vec(47, 228), module, Widener::FILTER_PARAM, 0.0, 1.0, 0.5));
  130. addInput(Port::create<PJ301MPort>(Vec(22, 100), Port::INPUT, module, Widener::TIME_CV_INPUT));
  131. addInput(Port::create<PJ301MPort>(Vec(22, 190), Port::INPUT, module, Widener::MIX_CV_INPUT));
  132. addInput(Port::create<PJ301MPort>(Vec(22, 270), Port::INPUT, module, Widener::FILTER_CV_INPUT));
  133. addInput(Port::create<PJ301MPort>(Vec(22, 315), Port::INPUT, module, Widener::CH1_INPUT));
  134. addOutput(Port::create<PJ301MPort>(Vec(62, 315), Port::OUTPUT, module, Widener::CH1_OUTPUT));
  135. addOutput(Port::create<PJ301MPort>(Vec(100, 315), Port::OUTPUT, module, Widener::CH2_OUTPUT));
  136. }
  137. } // namespace rack_plugin_RJModules
  138. using namespace rack_plugin_RJModules;
  139. RACK_PLUGIN_MODEL_INIT(RJModules, Widener) {
  140. Model *modelWidener = Model::create<Widener, WidenerWidget>("RJModules", "Widener", "[FX] Widener", UTILITY_TAG);
  141. return modelWidener;
  142. }