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.

140 lines
4.3KB

  1. #include "Fundamental.hpp"
  2. #include "dsp/samplerate.hpp"
  3. #include "dsp/ringbuffer.hpp"
  4. #include "dsp/filter.hpp"
  5. #define HISTORY_SIZE (1<<21)
  6. struct Delay : Module {
  7. enum ParamIds {
  8. TIME_PARAM,
  9. FEEDBACK_PARAM,
  10. COLOR_PARAM,
  11. MIX_PARAM,
  12. NUM_PARAMS
  13. };
  14. enum InputIds {
  15. TIME_INPUT,
  16. FEEDBACK_INPUT,
  17. COLOR_INPUT,
  18. MIX_INPUT,
  19. IN_INPUT,
  20. NUM_INPUTS
  21. };
  22. enum OutputIds {
  23. OUT_OUTPUT,
  24. NUM_OUTPUTS
  25. };
  26. DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer;
  27. DoubleRingBuffer<float, 16> outBuffer;
  28. SampleRateConverter<1> src;
  29. float lastWet = 0.0;
  30. RCFilter lowpassFilter;
  31. RCFilter highpassFilter;
  32. Delay() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
  33. void step();
  34. };
  35. void Delay::step() {
  36. // Get input to delay block
  37. float in = inputs[IN_INPUT].value;
  38. float feedback = clampf(params[FEEDBACK_PARAM].value + inputs[FEEDBACK_INPUT].value / 10.0, 0.0, 0.99);
  39. float dry = in + lastWet * feedback;
  40. // Compute delay time in seconds
  41. float delay = 1e-3 * powf(10.0 / 1e-3, clampf(params[TIME_PARAM].value + inputs[TIME_INPUT].value / 10.0, 0.0, 1.0));
  42. // Number of delay samples
  43. float index = delay * gSampleRate;
  44. // TODO This is a horrible digital delay algorithm. Rewrite later.
  45. // Push dry sample into history buffer
  46. if (!historyBuffer.full()) {
  47. historyBuffer.push(dry);
  48. }
  49. // How many samples do we need consume to catch up?
  50. float consume = index - historyBuffer.size();
  51. // printf("%f\t%d\t%f\n", index, historyBuffer.size(), consume);
  52. // printf("wanted: %f\tactual: %d\tdiff: %d\tratio: %f\n", index, historyBuffer.size(), consume, index / historyBuffer.size());
  53. if (outBuffer.empty()) {
  54. // Idk wtf I'm doing
  55. double ratio = 1.0;
  56. if (consume <= -16)
  57. ratio = 0.5;
  58. else if (consume >= 16)
  59. ratio = 2.0;
  60. // printf("%f\t%lf\n", consume, ratio);
  61. int inFrames = mini(historyBuffer.size(), 16);
  62. int outFrames = outBuffer.capacity();
  63. // printf(">\t%d\t%d\n", inFrames, outFrames);
  64. src.setRatioSmooth(ratio);
  65. src.process((const Frame<1>*)historyBuffer.startData(), &inFrames, (Frame<1>*)outBuffer.endData(), &outFrames);
  66. historyBuffer.startIncr(inFrames);
  67. outBuffer.endIncr(outFrames);
  68. // printf("<\t%d\t%d\n", inFrames, outFrames);
  69. // printf("====================================\n");
  70. }
  71. float wet = 0.0;
  72. if (!outBuffer.empty()) {
  73. wet = outBuffer.shift();
  74. }
  75. // Apply color to delay wet output
  76. // TODO Make it sound better
  77. float color = clampf(params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 10.0, 0.0, 1.0);
  78. float lowpassFreq = 10000.0 * powf(10.0, clampf(2.0*color, 0.0, 1.0));
  79. lowpassFilter.setCutoff(lowpassFreq / gSampleRate);
  80. lowpassFilter.process(wet);
  81. wet = lowpassFilter.lowpass();
  82. float highpassFreq = 10.0 * powf(100.0, clampf(2.0*color - 1.0, 0.0, 1.0));
  83. highpassFilter.setCutoff(highpassFreq / gSampleRate);
  84. highpassFilter.process(wet);
  85. wet = highpassFilter.highpass();
  86. lastWet = wet;
  87. float mix = clampf(params[MIX_PARAM].value + inputs[MIX_INPUT].value / 10.0, 0.0, 1.0);
  88. float out = crossf(in, wet, mix);
  89. outputs[OUT_OUTPUT].value = out;
  90. }
  91. DelayWidget::DelayWidget() {
  92. Delay *module = new Delay();
  93. setModule(module);
  94. box.size = Vec(15*8, 380);
  95. {
  96. SVGPanel *panel = new SVGPanel();
  97. panel->box.size = box.size;
  98. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Delay.svg")));
  99. addChild(panel);
  100. }
  101. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  102. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  103. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  104. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  105. addParam(createParam<RoundBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM, 0.0, 1.0, 0.5));
  106. addParam(createParam<RoundBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0, 1.0, 0.5));
  107. addParam(createParam<RoundBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0, 1.0, 0.5));
  108. addParam(createParam<RoundBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM, 0.0, 1.0, 0.5));
  109. addInput(createInput<PJ301MPort>(Vec(14, 63), module, Delay::TIME_INPUT));
  110. addInput(createInput<PJ301MPort>(Vec(14, 129), module, Delay::FEEDBACK_INPUT));
  111. addInput(createInput<PJ301MPort>(Vec(14, 196), module, Delay::COLOR_INPUT));
  112. addInput(createInput<PJ301MPort>(Vec(14, 263), module, Delay::MIX_INPUT));
  113. addInput(createInput<PJ301MPort>(Vec(14, 320), module, Delay::IN_INPUT));
  114. addOutput(createOutput<PJ301MPort>(Vec(73, 320), module, Delay::OUT_OUTPUT));
  115. }