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.

244 lines
7.8KB

  1. //***********************************************************************************************
  2. //
  3. //Reverb Stereo module for VCV Rack by Alfredo Santamaria - AS - https://github.com/AScustomWorks/AS
  4. //
  5. //Based on code from ML_Modules by martin-lueders https://github.com/martin-lueders/ML_modules
  6. //And code from Freeverb by Jezar at Dreampoint - http://www.dreampoint.co.uk
  7. //
  8. //***********************************************************************************************
  9. #include "AS.hpp"
  10. #include "dsp/digital.hpp"
  11. #include "../freeverb/revmodel.hpp"
  12. struct ReverbStereoFx : Module{
  13. enum ParamIds {
  14. DECAY_PARAM,
  15. DAMP_PARAM,
  16. BLEND_PARAM,
  17. BYPASS_SWITCH,
  18. NUM_PARAMS
  19. };
  20. enum InputIds {
  21. SIGNAL_INPUT_L,
  22. SIGNAL_INPUT_R,
  23. DECAY_CV_INPUT,
  24. DAMP_CV_INPUT,
  25. BLEND_CV_INPUT,
  26. BYPASS_CV_INPUT,
  27. NUM_INPUTS
  28. };
  29. enum OutputIds {
  30. SIGNAL_OUTPUT_L,
  31. SIGNAL_OUTPUT_R,
  32. NUM_OUTPUTS
  33. };
  34. enum LightIds {
  35. DECAY_LIGHT,
  36. DAMP_LIGHT,
  37. BLEND_LIGHT,
  38. BYPASS_LED,
  39. NUM_LIGHTS
  40. };
  41. revmodel reverb;
  42. float roomsize, damp;
  43. SchmittTrigger bypass_button_trig;
  44. SchmittTrigger bypass_cv_trig;
  45. bool fx_bypass = false;
  46. float input_signal_L = 0.0f;
  47. float input_signal_R = 0.0f;
  48. float mix_value = 0.0f;
  49. float outL = 0.0f;
  50. float outR = 0.0f;
  51. float fade_in_fx = 0.0f;
  52. float fade_in_dry = 0.0f;
  53. float fade_out_fx = 1.0f;
  54. float fade_out_dry = 1.0f;
  55. const float fade_speed = 0.001f;
  56. ReverbStereoFx() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  57. float gSampleRate = engineGetSampleRate();
  58. reverb.init(gSampleRate);
  59. }
  60. void step() override;
  61. void onSampleRateChange() override;
  62. json_t *toJson()override {
  63. json_t *rootJm = json_object();
  64. json_t *statesJ = json_array();
  65. json_t *bypassJ = json_boolean(fx_bypass);
  66. json_array_append_new(statesJ, bypassJ);
  67. json_object_set_new(rootJm, "as_FxBypass", statesJ);
  68. return rootJm;
  69. }
  70. void fromJson(json_t *rootJm)override {
  71. json_t *statesJ = json_object_get(rootJm, "as_FxBypass");
  72. json_t *bypassJ = json_array_get(statesJ, 0);
  73. fx_bypass = !!json_boolean_value(bypassJ);
  74. }
  75. void resetFades(){
  76. fade_in_fx = 0.0f;
  77. fade_in_dry = 0.0f;
  78. fade_out_fx = 1.0f;
  79. fade_out_dry = 1.0f;
  80. }
  81. };
  82. void ReverbStereoFx::onSampleRateChange() {
  83. float gSampleRate = engineGetSampleRate();
  84. reverb.init(gSampleRate);
  85. reverb.setdamp(damp);
  86. reverb.setroomsize(roomsize);
  87. reverb.setwidth(1.0f);
  88. };
  89. void ReverbStereoFx::step() {
  90. if (bypass_button_trig.process(params[BYPASS_SWITCH].value) || bypass_cv_trig.process(inputs[BYPASS_CV_INPUT].value) ){
  91. fx_bypass = !fx_bypass;
  92. resetFades();
  93. }
  94. lights[BYPASS_LED].value = fx_bypass ? 1.0f : 0.0f;
  95. float wetL, wetR;
  96. wetL = wetR = 0.0f;
  97. float old_roomsize = roomsize;
  98. float old_damp = damp;
  99. input_signal_L = clamp(inputs[SIGNAL_INPUT_L].value,-10.0f,10.0f);
  100. if(!inputs[SIGNAL_INPUT_R].active){
  101. input_signal_R = input_signal_L;
  102. }else{
  103. input_signal_R = clamp(inputs[SIGNAL_INPUT_R].value,-10.0f,10.0f);
  104. }
  105. roomsize = clamp(params[DECAY_PARAM].value + inputs[DECAY_CV_INPUT].value / 10.0f, 0.0f, 0.88f);
  106. damp = clamp(params[DAMP_PARAM].value + inputs[DAMP_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  107. if( old_damp != damp ) reverb.setdamp(damp);
  108. if( old_roomsize != roomsize) reverb.setroomsize(roomsize);
  109. reverb.process(input_signal_L + input_signal_R, wetL, wetR);
  110. /*
  111. //original mix method, changed to work better when used with a mixer FX loop
  112. float outL = input_signal_L + wetL * clamp(params[BLEND_PARAM].value + inputs[BLEND_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  113. float outR = input_signal_R + wetR * clamp(params[BLEND_PARAM].value + inputs[BLEND_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  114. */
  115. mix_value = clamp(params[BLEND_PARAM].value + inputs[BLEND_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  116. outL = crossfade(input_signal_L, wetL, mix_value);
  117. outR = crossfade(input_signal_R, wetR, mix_value);
  118. //check bypass switch status
  119. if (fx_bypass){
  120. fade_in_dry += fade_speed;
  121. if ( fade_in_dry > 1.0f ) {
  122. fade_in_dry = 1.0f;
  123. }
  124. fade_out_fx -= fade_speed;
  125. if ( fade_out_fx < 0.0f ) {
  126. fade_out_fx = 0.0f;
  127. }
  128. outputs[SIGNAL_OUTPUT_L].value = ( input_signal_L * fade_in_dry ) + ( outL * fade_out_fx );
  129. outputs[SIGNAL_OUTPUT_R].value = ( input_signal_R * fade_in_dry ) + ( outR * fade_out_fx );
  130. }else{
  131. fade_in_fx += fade_speed;
  132. if ( fade_in_fx > 1.0f ) {
  133. fade_in_fx = 1.0f;
  134. }
  135. fade_out_dry -= fade_speed;
  136. if ( fade_out_dry < 0.0f ) {
  137. fade_out_dry = 0.0f;
  138. }
  139. outputs[SIGNAL_OUTPUT_L].value = ( input_signal_L * fade_out_dry ) + ( outL * fade_in_fx );
  140. outputs[SIGNAL_OUTPUT_R].value = ( input_signal_R * fade_out_dry ) + ( outR * fade_in_fx );
  141. }
  142. lights[DECAY_LIGHT].value = clamp(params[DECAY_PARAM].value + inputs[DECAY_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  143. lights[DAMP_LIGHT].value = clamp(params[DAMP_PARAM].value + inputs[DAMP_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  144. lights[BLEND_LIGHT].value = clamp(params[BLEND_PARAM].value + inputs[BLEND_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  145. }
  146. struct ReverbStereoFxWidget : ModuleWidget
  147. {
  148. ReverbStereoFxWidget(ReverbStereoFx *module);
  149. };
  150. ReverbStereoFxWidget::ReverbStereoFxWidget(ReverbStereoFx *module) : ModuleWidget(module) {
  151. setPanel(SVG::load(assetPlugin(plugin, "res/ReverbStereo.svg")));
  152. //SCREWS
  153. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, 0)));
  154. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  155. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  156. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  157. //KNOBS
  158. addParam(ParamWidget::create<as_FxKnobWhite>(Vec(43, 60), module, ReverbStereoFx::DECAY_PARAM, 0.0f, 0.95f, 0.475f));
  159. addParam(ParamWidget::create<as_FxKnobWhite>(Vec(43, 125), module, ReverbStereoFx::DAMP_PARAM, 0.0f, 1.0f, 0.5f));
  160. addParam(ParamWidget::create<as_FxKnobWhite>(Vec(43, 190), module, ReverbStereoFx::BLEND_PARAM, 0.0f, 1.0f, 0.5f));
  161. //LIGHTS
  162. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 57), module, ReverbStereoFx::DECAY_LIGHT));
  163. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 122), module, ReverbStereoFx::DAMP_LIGHT));
  164. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 187), module, ReverbStereoFx::BLEND_LIGHT));
  165. //BYPASS SWITCH
  166. addParam(ParamWidget::create<LEDBezel>(Vec(55, 260), module, ReverbStereoFx::BYPASS_SWITCH , 0.0f, 1.0f, 0.0f));
  167. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(57.2, 262), module, ReverbStereoFx::BYPASS_LED));
  168. /*
  169. //INS/OUTS
  170. addInput(Port::create<as_PJ301MPort>(Vec(10, 310), Port::INPUT, module, ReverbStereoFx::SIGNAL_INPUT_L));
  171. addOutput(Port::create<as_PJ301MPort>(Vec(55, 310), Port::OUTPUT, module, ReverbStereoFx::SIGNAL_OUTPUT_L));
  172. */
  173. //INPUTS
  174. addInput(Port::create<as_PJ301MPort>(Vec(15, 300), Port::INPUT, module, ReverbStereoFx::SIGNAL_INPUT_L));
  175. addInput(Port::create<as_PJ301MPort>(Vec(15, 330), Port::INPUT, module, ReverbStereoFx::SIGNAL_INPUT_R));
  176. //OUTPUTS
  177. addOutput(Port::create<as_PJ301MPort>(Vec(50, 300), Port::OUTPUT, module, ReverbStereoFx::SIGNAL_OUTPUT_L));
  178. addOutput(Port::create<as_PJ301MPort>(Vec(50, 330), Port::OUTPUT, module, ReverbStereoFx::SIGNAL_OUTPUT_R));
  179. //CV INPUTS
  180. addInput(Port::create<as_PJ301MPort>(Vec(10, 67), Port::INPUT, module, ReverbStereoFx::DECAY_CV_INPUT));
  181. addInput(Port::create<as_PJ301MPort>(Vec(10, 132), Port::INPUT, module, ReverbStereoFx::DAMP_CV_INPUT));
  182. addInput(Port::create<as_PJ301MPort>(Vec(10, 197), Port::INPUT, module, ReverbStereoFx::BLEND_CV_INPUT));
  183. //BYPASS CV INPUT
  184. addInput(Port::create<as_PJ301MPort>(Vec(10, 259), Port::INPUT, module, ReverbStereoFx::BYPASS_CV_INPUT));
  185. }
  186. RACK_PLUGIN_MODEL_INIT(AS, ReverbStereoFx) {
  187. Model *modelReverbStereoFx = Model::create<ReverbStereoFx, ReverbStereoFxWidget>("AS", "ReverbStereoFx", "Reverb Stereo FX", REVERB_TAG, EFFECT_TAG);
  188. return modelReverbStereoFx;
  189. }