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.

153 lines
4.8KB

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