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.

137 lines
4.5KB

  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.0f;
  30. RCFilter lowpassFilter;
  31. RCFilter highpassFilter;
  32. Delay() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
  33. void step() override;
  34. };
  35. void Delay::step() {
  36. // Get input to delay block
  37. float in = inputs[IN_INPUT].value;
  38. float feedback = clamp(params[FEEDBACK_PARAM].value + inputs[FEEDBACK_INPUT].value / 10.0f, 0.0f, 1.0f);
  39. float dry = in + lastWet * feedback;
  40. // Compute delay time in seconds
  41. float delay = 1e-3 * powf(10.0f / 1e-3, clamp(params[TIME_PARAM].value + inputs[TIME_INPUT].value / 10.0f, 0.0f, 1.0f));
  42. // Number of delay samples
  43. float index = delay * engineGetSampleRate();
  44. // TODO Rewrite this digital delay algorithm.
  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. double ratio = 1.0f;
  55. if (consume <= -16)
  56. ratio = 0.5f;
  57. else if (consume >= 16)
  58. ratio = 2.0f;
  59. // printf("%f\t%lf\n", consume, ratio);
  60. int inFrames = min(historyBuffer.size(), 16);
  61. int outFrames = outBuffer.capacity();
  62. // printf(">\t%d\t%d\n", inFrames, outFrames);
  63. src.setRates(ratio * engineGetSampleRate(), engineGetSampleRate());
  64. src.process((const Frame<1>*)historyBuffer.startData(), &inFrames, (Frame<1>*)outBuffer.endData(), &outFrames);
  65. historyBuffer.startIncr(inFrames);
  66. outBuffer.endIncr(outFrames);
  67. // printf("<\t%d\t%d\n", inFrames, outFrames);
  68. // printf("====================================\n");
  69. }
  70. float wet = 0.0f;
  71. if (!outBuffer.empty()) {
  72. wet = outBuffer.shift();
  73. }
  74. // Apply color to delay wet output
  75. // TODO Make it sound better
  76. float color = clamp(params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 10.0f, 0.0f, 1.0f);
  77. float lowpassFreq = 10000.0f * powf(10.0f, clamp(2.0f*color, 0.0f, 1.0f));
  78. lowpassFilter.setCutoff(lowpassFreq / engineGetSampleRate());
  79. lowpassFilter.process(wet);
  80. wet = lowpassFilter.lowpass();
  81. float highpassFreq = 10.0f * powf(100.0f, clamp(2.0f*color - 1.0f, 0.0f, 1.0f));
  82. highpassFilter.setCutoff(highpassFreq / engineGetSampleRate());
  83. highpassFilter.process(wet);
  84. wet = highpassFilter.highpass();
  85. lastWet = wet;
  86. float mix = clamp(params[MIX_PARAM].value + inputs[MIX_INPUT].value / 10.0f, 0.0f, 1.0f);
  87. float out = crossfade(in, wet, mix);
  88. outputs[OUT_OUTPUT].value = out;
  89. }
  90. struct DelayWidget : ModuleWidget {
  91. DelayWidget(Delay *module);
  92. };
  93. DelayWidget::DelayWidget(Delay *module) : ModuleWidget(module) {
  94. setPanel(SVG::load(assetPlugin(plugin, "res/Delay.svg")));
  95. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  96. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  97. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  98. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  99. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM, 0.0f, 1.0f, 0.5f));
  100. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0f, 1.0f, 0.5f));
  101. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0f, 1.0f, 0.5f));
  102. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM, 0.0f, 1.0f, 0.5f));
  103. addInput(Port::create<PJ301MPort>(Vec(14, 63), Port::INPUT, module, Delay::TIME_INPUT));
  104. addInput(Port::create<PJ301MPort>(Vec(14, 129), Port::INPUT, module, Delay::FEEDBACK_INPUT));
  105. addInput(Port::create<PJ301MPort>(Vec(14, 196), Port::INPUT, module, Delay::COLOR_INPUT));
  106. addInput(Port::create<PJ301MPort>(Vec(14, 263), Port::INPUT, module, Delay::MIX_INPUT));
  107. addInput(Port::create<PJ301MPort>(Vec(14, 320), Port::INPUT, module, Delay::IN_INPUT));
  108. addOutput(Port::create<PJ301MPort>(Vec(73, 320), Port::OUTPUT, module, Delay::OUT_OUTPUT));
  109. }
  110. Model *modelDelay = Model::create<Delay, DelayWidget>("Fundamental", "Delay", "Delay", DELAY_TAG);