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. #include "samplerate.h"
  6. #define HISTORY_SIZE (1<<21)
  7. struct Delay : Module {
  8. enum ParamIds {
  9. TIME_PARAM,
  10. FEEDBACK_PARAM,
  11. COLOR_PARAM,
  12. MIX_PARAM,
  13. NUM_PARAMS
  14. };
  15. enum InputIds {
  16. TIME_INPUT,
  17. FEEDBACK_INPUT,
  18. COLOR_INPUT,
  19. MIX_INPUT,
  20. IN_INPUT,
  21. NUM_INPUTS
  22. };
  23. enum OutputIds {
  24. OUT_OUTPUT,
  25. NUM_OUTPUTS
  26. };
  27. DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer;
  28. DoubleRingBuffer<float, 16> outBuffer;
  29. SRC_STATE *src;
  30. float lastWet = 0.0f;
  31. RCFilter lowpassFilter;
  32. RCFilter highpassFilter;
  33. Delay() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  34. src = src_new(SRC_SINC_FASTEST, 1, NULL);
  35. assert(src);
  36. }
  37. ~Delay() {
  38. src_delete(src);
  39. }
  40. void step() override;
  41. };
  42. void Delay::step() {
  43. // Get input to delay block
  44. float in = inputs[IN_INPUT].value;
  45. float feedback = clamp(params[FEEDBACK_PARAM].value + inputs[FEEDBACK_INPUT].value / 10.0f, 0.0f, 1.0f);
  46. float dry = in + lastWet * feedback;
  47. // Compute delay time in seconds
  48. float delay = 1e-3 * powf(10.0f / 1e-3, clamp(params[TIME_PARAM].value + inputs[TIME_INPUT].value / 10.0f, 0.0f, 1.0f));
  49. // Number of delay samples
  50. float index = delay * engineGetSampleRate();
  51. // Push dry sample into history buffer
  52. if (!historyBuffer.full()) {
  53. historyBuffer.push(dry);
  54. }
  55. // How many samples do we need consume to catch up?
  56. float consume = index - historyBuffer.size();
  57. if (outBuffer.empty()) {
  58. double ratio = 1.f;
  59. if (abs(consume) >= 16) {
  60. ratio = powf(10.f, clamp(consume / 10000.f, -1.f, 1.f));
  61. }
  62. SRC_DATA srcData;
  63. srcData.data_in = (const float*) historyBuffer.startData();
  64. srcData.data_out = (float*) outBuffer.endData();
  65. srcData.input_frames = min(historyBuffer.size(), 16);
  66. srcData.output_frames = outBuffer.capacity();
  67. srcData.end_of_input = false;
  68. srcData.src_ratio = ratio;
  69. src_process(src, &srcData);
  70. historyBuffer.startIncr(srcData.input_frames_used);
  71. outBuffer.endIncr(srcData.output_frames_gen);
  72. }
  73. float wet = 0.0f;
  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 = clamp(params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 10.0f, 0.0f, 1.0f);
  80. float lowpassFreq = 10000.0f * powf(10.0f, clamp(2.0f*color, 0.0f, 1.0f));
  81. lowpassFilter.setCutoff(lowpassFreq / engineGetSampleRate());
  82. lowpassFilter.process(wet);
  83. wet = lowpassFilter.lowpass();
  84. float highpassFreq = 10.0f * powf(100.0f, clamp(2.0f*color - 1.0f, 0.0f, 1.0f));
  85. highpassFilter.setCutoff(highpassFreq / engineGetSampleRate());
  86. highpassFilter.process(wet);
  87. wet = highpassFilter.highpass();
  88. lastWet = wet;
  89. float mix = clamp(params[MIX_PARAM].value + inputs[MIX_INPUT].value / 10.0f, 0.0f, 1.0f);
  90. float out = crossfade(in, wet, mix);
  91. outputs[OUT_OUTPUT].value = out;
  92. }
  93. struct DelayWidget : ModuleWidget {
  94. DelayWidget(Delay *module);
  95. };
  96. DelayWidget::DelayWidget(Delay *module) : ModuleWidget(module) {
  97. setPanel(SVG::load(assetPlugin(plugin, "res/Delay.svg")));
  98. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  99. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  100. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  101. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  102. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM, 0.0f, 1.0f, 0.5f));
  103. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM, 0.0f, 1.0f, 0.5f));
  104. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM, 0.0f, 1.0f, 0.5f));
  105. addParam(ParamWidget::create<RoundLargeBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM, 0.0f, 1.0f, 0.5f));
  106. addInput(Port::create<PJ301MPort>(Vec(14, 63), Port::INPUT, module, Delay::TIME_INPUT));
  107. addInput(Port::create<PJ301MPort>(Vec(14, 129), Port::INPUT, module, Delay::FEEDBACK_INPUT));
  108. addInput(Port::create<PJ301MPort>(Vec(14, 196), Port::INPUT, module, Delay::COLOR_INPUT));
  109. addInput(Port::create<PJ301MPort>(Vec(14, 263), Port::INPUT, module, Delay::MIX_INPUT));
  110. addInput(Port::create<PJ301MPort>(Vec(14, 320), Port::INPUT, module, Delay::IN_INPUT));
  111. addOutput(Port::create<PJ301MPort>(Vec(73, 320), Port::OUTPUT, module, Delay::OUT_OUTPUT));
  112. }
  113. Model *modelDelay = Model::create<Delay, DelayWidget>("Fundamental", "Delay", "Delay", DELAY_TAG);