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.

205 lines
6.7KB

  1. //***********************************************************************************************
  2. //
  3. //SuperDriveFx module for VCV Rack by Alfredo Santamaria - AS - https://github.com/AScustomWorks/AS
  4. //Variable-hardness clipping code from scoofy[ AT ]inf[ DOT ]elte[ DOT ]hu
  5. //Filter code from from VCV rack dsp
  6. //
  7. //***********************************************************************************************
  8. #include "AS.hpp"
  9. #include "dsp/digital.hpp"
  10. #include "dsp/filter.hpp"
  11. //#include <stdlib.h>
  12. struct SuperDriveFx : Module{
  13. enum ParamIds {
  14. DRIVE_PARAM,
  15. OUTPUT_GAIN_PARAM,
  16. TONE_PARAM,
  17. BYPASS_SWITCH,
  18. NUM_PARAMS
  19. };
  20. enum InputIds {
  21. SIGNAL_INPUT,
  22. DRIVE_CV_INPUT,
  23. GAIN_CV_INPUT,
  24. TONE_CV_INPUT,
  25. BYPASS_CV_INPUT,
  26. NUM_INPUTS
  27. };
  28. enum OutputIds {
  29. SIGNAL_OUTPUT,
  30. NUM_OUTPUTS
  31. };
  32. enum LightIds {
  33. GAIN_LIGHT,
  34. TONE_LIGHT,
  35. DRIVE_LIGHT,
  36. BYPASS_LED,
  37. NUM_LIGHTS
  38. };
  39. SchmittTrigger bypass_button_trig;
  40. SchmittTrigger bypass_cv_trig;
  41. int drive_scale=50;//to handle cv parameters properly
  42. RCFilter lowpassFilter;
  43. RCFilter highpassFilter;
  44. bool fx_bypass = false;
  45. float fade_in_fx = 0.0f;
  46. float fade_in_dry = 0.0f;
  47. float fade_out_fx = 1.0f;
  48. float fade_out_dry = 1.0f;
  49. const float fade_speed = 0.001f;
  50. SuperDriveFx() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  51. void step() override;
  52. json_t *toJson()override {
  53. json_t *rootJm = json_object();
  54. json_t *statesJ = json_array();
  55. json_t *bypassJ = json_boolean(fx_bypass);
  56. json_array_append_new(statesJ, bypassJ);
  57. json_object_set_new(rootJm, "as_FxBypass", statesJ);
  58. return rootJm;
  59. }
  60. void fromJson(json_t *rootJm)override {
  61. json_t *statesJ = json_object_get(rootJm, "as_FxBypass");
  62. json_t *bypassJ = json_array_get(statesJ, 0);
  63. fx_bypass = !!json_boolean_value(bypassJ);
  64. }
  65. void resetFades(){
  66. fade_in_fx = 0.0f;
  67. fade_in_dry = 0.0f;
  68. fade_out_fx = 1.0f;
  69. fade_out_dry = 1.0f;
  70. }
  71. float input_signal=0.0f;
  72. float drive = 0.1f;
  73. float process= 0.0f;
  74. float inv_atan_drive = 0.0f;
  75. float output_signal= 0.0f;
  76. };
  77. void SuperDriveFx::step() {
  78. if (bypass_button_trig.process(params[BYPASS_SWITCH].value) || bypass_cv_trig.process(inputs[BYPASS_CV_INPUT].value) ){
  79. fx_bypass = !fx_bypass;
  80. resetFades();
  81. }
  82. lights[BYPASS_LED].value = fx_bypass ? 1.0f : 0.0f;
  83. float input_signal = inputs[SIGNAL_INPUT].value;
  84. //OVERDRIVE SIGNAL
  85. //float drive = params[DRIVE_PARAM].value;
  86. drive = clamp(params[DRIVE_PARAM].value + inputs[DRIVE_CV_INPUT].value / 10.0f, 0.1f, 1.0f);
  87. drive = drive * drive_scale;
  88. //precalc
  89. inv_atan_drive = 1.0f/atan(drive);
  90. //process
  91. process = inv_atan_drive * atan(input_signal*drive);
  92. //output_signal = process * params[OUTPUT_GAIN_PARAM].value;
  93. output_signal = process * clamp(params[OUTPUT_GAIN_PARAM].value + inputs[GAIN_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  94. //TONE CONTROL
  95. float tone = clamp(params[TONE_PARAM].value + inputs[TONE_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  96. float lowpassFreq = 10000.0f * powf(10.0f, clamp(2.0f*tone, 0.0f, 1.0f));
  97. lowpassFilter.setCutoff(lowpassFreq / engineGetSampleRate());
  98. lowpassFilter.process(output_signal);
  99. output_signal = lowpassFilter.lowpass();
  100. float highpassFreq = 10.0f * powf(100.0f, clamp(2.0f*tone - 1.0f, 0.0f, 1.0f));
  101. highpassFilter.setCutoff(highpassFreq / engineGetSampleRate());
  102. highpassFilter.process(output_signal);
  103. output_signal = highpassFilter.highpass();
  104. //check bypass switch status
  105. if (fx_bypass){
  106. fade_in_dry += fade_speed;
  107. if ( fade_in_dry > 1.0f ) {
  108. fade_in_dry = 1.0f;
  109. }
  110. fade_out_fx -= fade_speed;
  111. if ( fade_out_fx < 0.0f ) {
  112. fade_out_fx = 0.0f;
  113. }
  114. outputs[SIGNAL_OUTPUT].value = ( input_signal * fade_in_dry ) + ( (output_signal*3.5f) * fade_out_fx );
  115. }else{
  116. fade_in_fx += fade_speed;
  117. if ( fade_in_fx > 1.0f ) {
  118. fade_in_fx = 1.0f;
  119. }
  120. fade_out_dry -= fade_speed;
  121. if ( fade_out_dry < 0.0f ) {
  122. fade_out_dry = 0.0f;
  123. }
  124. outputs[SIGNAL_OUTPUT].value = ( input_signal * fade_out_dry ) + ( (output_signal*3.5f) * fade_in_fx );
  125. }
  126. lights[DRIVE_LIGHT].value = clamp(params[DRIVE_PARAM].value + inputs[DRIVE_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  127. lights[TONE_LIGHT].value = clamp(params[TONE_PARAM].value + inputs[TONE_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  128. lights[GAIN_LIGHT].value = clamp(params[OUTPUT_GAIN_PARAM].value + inputs[GAIN_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  129. }
  130. struct SuperDriveFxWidget : ModuleWidget
  131. {
  132. SuperDriveFxWidget(SuperDriveFx *module);
  133. };
  134. SuperDriveFxWidget::SuperDriveFxWidget(SuperDriveFx *module) : ModuleWidget(module) {
  135. setPanel(SVG::load(assetPlugin(plugin, "res/SuperDrive.svg")));
  136. //SCREWS
  137. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, 0)));
  138. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  139. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  140. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  141. //KNOBS
  142. addParam(ParamWidget::create<as_FxKnobWhite>(Vec(43, 60), module, SuperDriveFx::DRIVE_PARAM, 0.1f, 1.0f, 0.1f));
  143. addParam(ParamWidget::create<as_FxKnobWhite>(Vec(43, 125), module, SuperDriveFx::TONE_PARAM, 0.0f, 1.0f, 0.5f));
  144. addParam(ParamWidget::create<as_FxKnobWhite>(Vec(43, 190), module, SuperDriveFx::OUTPUT_GAIN_PARAM, 0.0f, 1.0f, 0.5f));
  145. //LIGHTS
  146. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 57), module, SuperDriveFx::DRIVE_LIGHT));
  147. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 122), module, SuperDriveFx::TONE_LIGHT));
  148. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 187), module, SuperDriveFx::GAIN_LIGHT));
  149. //BYPASS SWITCH
  150. addParam(ParamWidget::create<LEDBezel>(Vec(55, 260), module, SuperDriveFx::BYPASS_SWITCH , 0.0f, 1.0f, 0.0f));
  151. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(57.2, 262), module, SuperDriveFx::BYPASS_LED));
  152. //INS/OUTS
  153. addInput(Port::create<as_PJ301MPort>(Vec(10, 310), Port::INPUT, module, SuperDriveFx::SIGNAL_INPUT));
  154. addOutput(Port::create<as_PJ301MPort>(Vec(55, 310), Port::OUTPUT, module, SuperDriveFx::SIGNAL_OUTPUT));
  155. //CV INPUTS
  156. addInput(Port::create<as_PJ301MPort>(Vec(10, 67), Port::INPUT, module, SuperDriveFx::DRIVE_CV_INPUT));
  157. addInput(Port::create<as_PJ301MPort>(Vec(10, 132), Port::INPUT, module, SuperDriveFx::TONE_CV_INPUT));
  158. addInput(Port::create<as_PJ301MPort>(Vec(10, 197), Port::INPUT, module, SuperDriveFx::GAIN_CV_INPUT));
  159. //BYPASS CV INPUT
  160. addInput(Port::create<as_PJ301MPort>(Vec(10, 259), Port::INPUT, module, SuperDriveFx::BYPASS_CV_INPUT));
  161. }
  162. RACK_PLUGIN_MODEL_INIT(AS, SuperDriveFx) {
  163. Model *modelSuperDriveFx = Model::create<SuperDriveFx, SuperDriveFxWidget>("AS", "SuperDriveFx", "Super Drive FX", AMPLIFIER_TAG, EFFECT_TAG);
  164. return modelSuperDriveFx;
  165. }