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.

207 lines
5.5KB

  1. #include "JE.hpp"
  2. #include "../common/constants.hpp"
  3. #include "../utils/meta.hpp"
  4. #include "../ext/LambertW/LambertW.h"
  5. // STL
  6. #include <cmath>
  7. #include <iostream>
  8. /*
  9. http://smc2017.aalto.fi/media/materials/proceedings/SMC17_p336.pdf
  10. */
  11. namespace rack_plugin_JE {
  12. struct WaveFolder : rack::Module
  13. {
  14. enum ParamIds
  15. {
  16. INPUT_GAIN_PARAM = 0,
  17. DC_OFFSET_PARAM,
  18. OUTPUT_GAIN_PARAM,
  19. RESISTOR_PARAM,
  20. LOAD_RESISTOR_PARAM,
  21. NUM_PARAMS
  22. };
  23. enum InputIds
  24. {
  25. INPUT_INPUT = 0,
  26. INPUT_GAIN_INPUT,
  27. DC_OFFSET_INPUT,
  28. OUTPUT_GAIN_INPUT,
  29. NUM_INPUTS
  30. };
  31. enum OutputIds
  32. {
  33. OUTPUT_OUTPUT = 0,
  34. NUM_OUTPUTS
  35. };
  36. enum LightIds
  37. {
  38. NUM_LIGHTS = 0
  39. };
  40. WaveFolder()
  41. : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS)
  42. {}
  43. inline float getParameterValue(const ParamIds id) const
  44. {
  45. return params[id].value;
  46. }
  47. inline float getAudioInputValue(const InputIds id) const
  48. {
  49. return inputs[id].value;
  50. }
  51. inline float getControlInputValue(const InputIds id) const
  52. {
  53. return inputs[id].value;
  54. }
  55. inline void setOutputValue(OutputIds id, float v)
  56. {
  57. outputs[id].value = v;
  58. }
  59. inline bool needToStep()
  60. {
  61. if (!outputs[OUTPUT_OUTPUT].active)
  62. return false;
  63. if (!inputs[INPUT_INPUT].active)
  64. {
  65. outputs[OUTPUT_OUTPUT].value = 0.f;
  66. return false;
  67. }
  68. return true;
  69. }
  70. inline void updateResistors()
  71. {
  72. if (meta::updateIfDifferent(m_resistor, getParameterValue(RESISTOR_PARAM)))
  73. {
  74. m_alpha = m_loadResistor2 / m_resistor;
  75. m_beta = (m_resistor + m_loadResistor2) / (m_thermalVoltage * m_resistor);
  76. }
  77. if (meta::updateIfDifferent(m_loadResistor, getParameterValue(LOAD_RESISTOR_PARAM)))
  78. {
  79. m_loadResistor2 = m_loadResistor * 2.f;
  80. m_alpha = m_loadResistor2 / m_resistor;
  81. m_beta = (m_resistor + m_loadResistor2) / (m_thermalVoltage * m_resistor);
  82. m_delta = (m_loadResistor * m_saturationCurrent) / m_thermalVoltage;
  83. }
  84. }
  85. inline float getGainedOffsetedInputValue()
  86. {
  87. return (getAudioInputValue(INPUT_INPUT) * meta::clamp(getParameterValue(INPUT_GAIN_PARAM) + getControlInputValue(INPUT_GAIN_INPUT) / g_audioPeakVoltage, 0.f, 1.f)) +
  88. (getParameterValue(DC_OFFSET_PARAM) + getControlInputValue(DC_OFFSET_INPUT)) / 2.f;
  89. }
  90. inline float waveFolder(float in)
  91. {
  92. const float theta = (in >= 0.f) ? 1.f : -1.f;
  93. return theta * m_thermalVoltage * utl::LambertW<0>(m_delta * meta::exp(theta * m_beta * in)) - m_alpha * in;
  94. }
  95. inline void step() override
  96. {
  97. if (!needToStep())
  98. return;
  99. updateResistors();
  100. setOutputValue(OUTPUT_OUTPUT, std::tanh(waveFolder(getGainedOffsetedInputValue())) *
  101. meta::clamp(getParameterValue(OUTPUT_GAIN_PARAM) + getControlInputValue(OUTPUT_GAIN_INPUT), 0.f, 10.f));
  102. }
  103. private:
  104. const float m_thermalVoltage = 0.026f;
  105. const float m_saturationCurrent = 10e-17f;
  106. float m_resistor = 15000.f;
  107. float m_loadResistor = 7500.f;
  108. float m_loadResistor2 = m_loadResistor * 2.f;
  109. // Derived values
  110. float m_alpha = m_loadResistor2 / m_resistor;
  111. float m_beta = (m_resistor + m_loadResistor2) / (m_thermalVoltage * m_resistor);
  112. float m_delta = (m_loadResistor * m_saturationCurrent) / m_thermalVoltage;
  113. };
  114. struct WaveFolderWidget : rack::ModuleWidget
  115. {
  116. WaveFolderWidget(WaveFolder *module);
  117. };
  118. WaveFolderWidget::WaveFolderWidget(WaveFolder *module) : ModuleWidget(module)
  119. {
  120. box.size = rack::Vec(15*7, 380);
  121. {
  122. rack::SVGPanel *panel = new rack::SVGPanel();
  123. panel->box.size = box.size;
  124. panel->setBackground(rack::SVG::load(assetPlugin(plugin, "res/CleanWaveFolder.svg")));
  125. addChild(panel);
  126. }
  127. addChild(rack::createScrew<rack::ScrewBlack>(rack::Vec(15, 0)));
  128. addChild(rack::createScrew<rack::ScrewBlack>(rack::Vec(box.size.x-30, 0)));
  129. addChild(rack::createScrew<rack::ScrewBlack>(rack::Vec(15, 365)));
  130. addChild(rack::createScrew<rack::ScrewBlack>(rack::Vec(box.size.x-30, 365)));
  131. float yOffset = 67.f;
  132. float portY = 63.f;
  133. float knobY = 57.f;
  134. addInput(rack::createInput<rack::PJ301MPort>(rack::Vec(9, portY), module, WaveFolder::INPUT_GAIN_INPUT));
  135. addParam(rack::createParam<rack::RoundBlackKnob>(rack::Vec(54, knobY), module, WaveFolder::INPUT_GAIN_PARAM, 0.0f, 1.0f, 0.1f));
  136. portY += yOffset;
  137. knobY += yOffset;
  138. addInput(rack::createInput<rack::PJ301MPort>(rack::Vec(9, portY), module, WaveFolder::DC_OFFSET_INPUT));
  139. addParam(rack::createParam<rack::RoundBlackKnob>(rack::Vec(54, knobY), module, WaveFolder::DC_OFFSET_PARAM, -5.0f, 5.0f, 0.0f));
  140. portY += yOffset;
  141. knobY += yOffset;
  142. addInput(rack::createInput<rack::PJ301MPort>(rack::Vec(9, portY), module, WaveFolder::OUTPUT_GAIN_INPUT));
  143. addParam(rack::createParam<rack::RoundBlackKnob>(rack::Vec(54, knobY), module, WaveFolder::OUTPUT_GAIN_PARAM, 0.0f, 10.0f, 1.0f));
  144. portY += yOffset;
  145. knobY += yOffset;
  146. addInput(rack::createInput<rack::PJ301MPort>(rack::Vec(18, portY), module, WaveFolder::INPUT_INPUT));
  147. addOutput(rack::createOutput<rack::PJ301MPort>(rack::Vec(box.size.x-43, portY), module, WaveFolder::OUTPUT_OUTPUT));
  148. portY += yOffset;
  149. knobY += yOffset;
  150. const float y = knobY - 6.f;
  151. float xOffset = 52.f;
  152. float x = 9.f;
  153. addParam(rack::createParam<rack::RoundSmallBlackKnob>(rack::Vec(x, y), module, WaveFolder::RESISTOR_PARAM, 10000.f, 100000.f, 15000.f));
  154. x += xOffset;
  155. addParam(rack::createParam<rack::RoundSmallBlackKnob>(rack::Vec(x, y), module, WaveFolder::LOAD_RESISTOR_PARAM, 1000.f, 10000.f, 7500.f));
  156. }
  157. } // namespace rack_plugin_JE
  158. using namespace rack_plugin_JE;
  159. RACK_PLUGIN_MODEL_INIT(JE, SimpleWaveFolder) {
  160. return Model::create<WaveFolder, WaveFolderWidget>(
  161. "JE", "SimpleWaveFolder", "Simple Wave Folder",
  162. rack::EFFECT_TAG, rack::WAVESHAPER_TAG
  163. );
  164. }