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.

147 lines
4.6KB

  1. #include "plugin.hpp"
  2. #include "samplerate.h"
  3. #define HISTORY_SIZE (1<<21)
  4. struct Delay : Module {
  5. enum ParamIds {
  6. TIME_PARAM,
  7. FEEDBACK_PARAM,
  8. COLOR_PARAM,
  9. MIX_PARAM,
  10. NUM_PARAMS
  11. };
  12. enum InputIds {
  13. TIME_INPUT,
  14. FEEDBACK_INPUT,
  15. COLOR_INPUT,
  16. MIX_INPUT,
  17. IN_INPUT,
  18. NUM_INPUTS
  19. };
  20. enum OutputIds {
  21. OUT_OUTPUT,
  22. NUM_OUTPUTS
  23. };
  24. dsp::DoubleRingBuffer<float, HISTORY_SIZE> historyBuffer;
  25. dsp::DoubleRingBuffer<float, 16> outBuffer;
  26. SRC_STATE* src;
  27. float lastWet = 0.f;
  28. dsp::RCFilter lowpassFilter;
  29. dsp::RCFilter highpassFilter;
  30. Delay() {
  31. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
  32. configParam(TIME_PARAM, 0.f, 1.f, 0.5f, "Time", " s", 10.f / 1e-3, 1e-3);
  33. configParam(FEEDBACK_PARAM, 0.f, 1.f, 0.5f, "Feedback", "%", 0, 100);
  34. configParam(COLOR_PARAM, 0.f, 1.f, 0.5f, "Color", "%", 0, 100);
  35. configParam(MIX_PARAM, 0.f, 1.f, 0.5f, "Mix", "%", 0, 100);
  36. src = src_new(SRC_SINC_FASTEST, 1, NULL);
  37. assert(src);
  38. }
  39. ~Delay() {
  40. src_delete(src);
  41. }
  42. void process(const ProcessArgs& args) override {
  43. // Get input to delay block
  44. float in = inputs[IN_INPUT].getVoltage();
  45. float feedback = params[FEEDBACK_PARAM].getValue() + inputs[FEEDBACK_INPUT].getVoltage() / 10.f;
  46. feedback = clamp(feedback, 0.f, 1.f);
  47. float dry = in + lastWet * feedback;
  48. // Compute delay time in seconds
  49. float delay = params[TIME_PARAM].getValue() + inputs[TIME_INPUT].getVoltage() / 10.f;
  50. delay = clamp(delay, 0.f, 1.f);
  51. delay = 1e-3 * std::pow(10.f / 1e-3, delay);
  52. // Number of delay samples
  53. float index = std::round(delay * args.sampleRate);
  54. // Push dry sample into history buffer
  55. if (!historyBuffer.full()) {
  56. historyBuffer.push(dry);
  57. }
  58. // How many samples do we need consume to catch up?
  59. float consume = index - historyBuffer.size();
  60. if (outBuffer.empty()) {
  61. double ratio = 1.f;
  62. if (std::fabs(consume) >= 16.f) {
  63. // Here's where the delay magic is. Smooth the ratio depending on how divergent we are from the correct delay time.
  64. ratio = std::pow(10.f, clamp(consume / 10000.f, -1.f, 1.f));
  65. }
  66. SRC_DATA srcData;
  67. srcData.data_in = (const float*) historyBuffer.startData();
  68. srcData.data_out = (float*) outBuffer.endData();
  69. srcData.input_frames = std::min((int) historyBuffer.size(), 16);
  70. srcData.output_frames = outBuffer.capacity();
  71. srcData.end_of_input = false;
  72. srcData.src_ratio = ratio;
  73. src_process(src, &srcData);
  74. historyBuffer.startIncr(srcData.input_frames_used);
  75. outBuffer.endIncr(srcData.output_frames_gen);
  76. }
  77. float wet = 0.f;
  78. if (!outBuffer.empty()) {
  79. wet = outBuffer.shift();
  80. }
  81. // Apply color to delay wet output
  82. float color = params[COLOR_PARAM].getValue() + inputs[COLOR_INPUT].getVoltage() / 10.f;
  83. color = clamp(color, 0.f, 1.f);
  84. float colorFreq = std::pow(100.f, 2.f * color - 1.f);
  85. float lowpassFreq = clamp(20000.f * colorFreq, 20.f, 20000.f);
  86. lowpassFilter.setCutoffFreq(lowpassFreq / args.sampleRate);
  87. lowpassFilter.process(wet);
  88. wet = lowpassFilter.lowpass();
  89. float highpassFreq = clamp(20.f * colorFreq, 20.f, 20000.f);
  90. highpassFilter.setCutoff(highpassFreq / args.sampleRate);
  91. highpassFilter.process(wet);
  92. wet = highpassFilter.highpass();
  93. lastWet = wet;
  94. float mix = params[MIX_PARAM].getValue() + inputs[MIX_INPUT].getVoltage() / 10.f;
  95. mix = clamp(mix, 0.f, 1.f);
  96. float out = crossfade(in, wet, mix);
  97. outputs[OUT_OUTPUT].setVoltage(out);
  98. }
  99. };
  100. struct DelayWidget : ModuleWidget {
  101. DelayWidget(Delay* module) {
  102. setModule(module);
  103. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Delay.svg")));
  104. addChild(createWidget<ScrewSilver>(Vec(15, 0)));
  105. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0)));
  106. addChild(createWidget<ScrewSilver>(Vec(15, 365)));
  107. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365)));
  108. addParam(createParam<RoundLargeBlackKnob>(Vec(67, 57), module, Delay::TIME_PARAM));
  109. addParam(createParam<RoundLargeBlackKnob>(Vec(67, 123), module, Delay::FEEDBACK_PARAM));
  110. addParam(createParam<RoundLargeBlackKnob>(Vec(67, 190), module, Delay::COLOR_PARAM));
  111. addParam(createParam<RoundLargeBlackKnob>(Vec(67, 257), module, Delay::MIX_PARAM));
  112. addInput(createInput<PJ301MPort>(Vec(14, 63), module, Delay::TIME_INPUT));
  113. addInput(createInput<PJ301MPort>(Vec(14, 129), module, Delay::FEEDBACK_INPUT));
  114. addInput(createInput<PJ301MPort>(Vec(14, 196), module, Delay::COLOR_INPUT));
  115. addInput(createInput<PJ301MPort>(Vec(14, 263), module, Delay::MIX_INPUT));
  116. addInput(createInput<PJ301MPort>(Vec(14, 320), module, Delay::IN_INPUT));
  117. addOutput(createOutput<PJ301MPort>(Vec(73, 320), module, Delay::OUT_OUTPUT));
  118. }
  119. };
  120. Model* modelDelay = createModel<Delay, DelayWidget>("Delay");