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.

143 lines
4.3KB

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