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.

279 lines
7.8KB

  1. //***********************************************************************************************
  2. //
  3. //Phaser module for VCV Rack by Alfredo Santamaria - AS - https://github.com/AScustomWorks/AS
  4. //Based on the Phaser Module for VCV Rack by Autodafe http://www.autodafe.net
  5. //Based on code taken from the Fundamentals plugins by Andrew Belt http://www.vcvrack.com
  6. //And part of code on musicdsp.org: http://musicdsp.org/showArchiveComment.php?ArchiveID=78
  7. //
  8. //***********************************************************************************************
  9. #include "AS.hpp"
  10. #include "dsp/digital.hpp"
  11. #include <stdlib.h>
  12. struct PhaserFx : Module{
  13. enum ParamIds {
  14. RATE_PARAM,
  15. FBK_PARAM,
  16. DEPTH_PARAM,
  17. BYPASS_SWITCH,
  18. NUM_PARAMS
  19. };
  20. enum InputIds {
  21. INPUT,
  22. RATE_CV_INPUT,
  23. FEEDBACK_CV_INPUT,
  24. DEPTH_CV_INPUT,
  25. BYPASS_CV_INPUT,
  26. NUM_INPUTS
  27. };
  28. enum OutputIds {
  29. OUT,
  30. NUM_OUTPUTS
  31. };
  32. enum LightIds {
  33. RATE_LIGHT,
  34. FBK_LIGHT,
  35. DEPTH_LIGHT,
  36. BYPASS_LED,
  37. NUM_LIGHTS
  38. };
  39. SchmittTrigger bypass_button_trig;
  40. SchmittTrigger bypass_cv_trig;
  41. bool fx_bypass = false;
  42. float fade_in_fx = 0.0f;
  43. float fade_in_dry = 0.0f;
  44. float fade_out_fx = 1.0f;
  45. float fade_out_dry = 1.0f;
  46. const float fade_speed = 0.001f;
  47. PhaserFx() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  48. void step() override;
  49. json_t *toJson()override {
  50. json_t *rootJm = json_object();
  51. json_t *statesJ = json_array();
  52. json_t *bypassJ = json_boolean(fx_bypass);
  53. json_array_append_new(statesJ, bypassJ);
  54. json_object_set_new(rootJm, "as_FxBypass", statesJ);
  55. return rootJm;
  56. }
  57. void fromJson(json_t *rootJm)override {
  58. json_t *statesJ = json_object_get(rootJm, "as_FxBypass");
  59. json_t *bypassJ = json_array_get(statesJ, 0);
  60. fx_bypass = !!json_boolean_value(bypassJ);
  61. }
  62. void resetFades(){
  63. fade_in_fx = 0.0f;
  64. fade_in_dry = 0.0f;
  65. fade_out_fx = 1.0f;
  66. fade_out_dry = 1.0f;
  67. }
  68. };
  69. #define SR (44100.f) //sample rate
  70. #define F_PI (3.14159f)
  71. class Phaser{
  72. public:
  73. Phaser() //initialise to some useful defaults...
  74. : _fb( 0.7f )
  75. , _lfoPhase( 0.0f )
  76. , _depth( 1.0f )
  77. , _zm1( 0.f )
  78. {
  79. Range( 440.0f, 1600.0f );
  80. Rate( 0.5f );
  81. }
  82. void Range( float fMin, float fMax ){ // Hz
  83. _dmin = fMin / (SR/2.0f);
  84. _dmax = fMax / (SR/2.0f);
  85. }
  86. void Rate( float rate ){ // cps
  87. _lfoInc = 2.0f * F_PI * (rate / SR);
  88. }
  89. void Feedback( float fb ){ // 0 -> <1.
  90. _fb = fb;
  91. }
  92. void Depth( float depth ){ // 0 -> 1.
  93. _depth = depth;
  94. }
  95. float Update( float inSamp ){
  96. //calculate and update phaser sweep lfo...
  97. float d = _dmin + (_dmax-_dmin) * ((sin( _lfoPhase ) + 1.f)/2.f);
  98. _lfoPhase += _lfoInc;
  99. if( _lfoPhase >= F_PI * 2.0f )
  100. _lfoPhase -= F_PI * 2.0f;
  101. //update filter coeffs
  102. for( int i=0; i<6; i++ )
  103. _alps[i].Delay( d );
  104. //calculate output
  105. float y = _alps[0].Update(
  106. _alps[1].Update(
  107. _alps[2].Update(
  108. _alps[3].Update(
  109. _alps[4].Update(
  110. _alps[5].Update( inSamp + _zm1 * _fb ))))));
  111. _zm1 = y;
  112. return inSamp + y * _depth;
  113. }
  114. private:
  115. class AllpassDelay{
  116. public:
  117. AllpassDelay()
  118. : _a1( 0.0f )
  119. , _zm1( 0.0f )
  120. {}
  121. void Delay( float delay ){ //sample delay time
  122. _a1 = (1.0f - delay) / (1.0f + delay);
  123. }
  124. float Update( float inSamp ){
  125. float y = inSamp * -_a1 + _zm1;
  126. _zm1 = y * _a1 + inSamp;
  127. return y;
  128. }
  129. private:
  130. float _a1, _zm1;
  131. };
  132. AllpassDelay _alps[6];
  133. float _dmin, _dmax; //range
  134. float _fb; //feedback
  135. float _lfoPhase;
  136. float _lfoInc;
  137. float _depth;
  138. float _zm1;
  139. };
  140. Phaser *pha = new Phaser();
  141. void PhaserFx::step() {
  142. if (bypass_button_trig.process(params[BYPASS_SWITCH].value) || bypass_cv_trig.process(inputs[BYPASS_CV_INPUT].value) ){
  143. fx_bypass = !fx_bypass;
  144. resetFades();
  145. }
  146. lights[BYPASS_LED].value = fx_bypass ? 1.00 : 0.0;
  147. float rate = clamp(params[RATE_PARAM].value + inputs[RATE_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  148. float feedback = clamp(params[FBK_PARAM].value + inputs[FEEDBACK_CV_INPUT].value / 10.0f, 0.0f, 0.95f);
  149. float depth = clamp(params[DEPTH_PARAM].value + inputs[DEPTH_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  150. float input = inputs[INPUT].value / 5.0f;
  151. pha->Rate(rate);
  152. pha->Feedback(feedback);
  153. pha->Depth (depth);
  154. float out = pha->Update(input);
  155. //check bypass switch status
  156. /*
  157. if (fx_bypass){
  158. outputs[OUT].value = input * 5.0f;
  159. }else{
  160. outputs[OUT].value = out * 5.0f;
  161. }
  162. */
  163. if (fx_bypass){
  164. fade_in_dry += fade_speed;
  165. if ( fade_in_dry > 1.0f ) {
  166. fade_in_dry = 1.0f;
  167. }
  168. fade_out_fx -= fade_speed;
  169. if ( fade_out_fx < 0.0f ) {
  170. fade_out_fx = 0.0f;
  171. }
  172. outputs[OUT].value = ( (input * 5.0f) * fade_in_dry ) + ( (out*5.0f) * fade_out_fx );
  173. }else{
  174. fade_in_fx += fade_speed;
  175. if ( fade_in_fx > 1.0f ) {
  176. fade_in_fx = 1.0f;
  177. }
  178. fade_out_dry -= fade_speed;
  179. if ( fade_out_dry < 0.0f ) {
  180. fade_out_dry = 0.0f;
  181. }
  182. outputs[OUT].value = ( (input * 5.0f) * fade_out_dry ) + ( (out*5.0f) * fade_in_fx );
  183. }
  184. lights[RATE_LIGHT].value = clamp(params[RATE_PARAM].value + inputs[RATE_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  185. lights[FBK_LIGHT].value = clamp(params[FBK_PARAM].value + inputs[FEEDBACK_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  186. lights[DEPTH_LIGHT].value = clamp(params[DEPTH_PARAM].value + inputs[DEPTH_CV_INPUT].value / 10.0f, 0.0f, 1.0f);
  187. }
  188. struct PhaserFxWidget : ModuleWidget
  189. {
  190. PhaserFxWidget(PhaserFx *module);
  191. };
  192. PhaserFxWidget::PhaserFxWidget(PhaserFx *module) : ModuleWidget(module) {
  193. setPanel(SVG::load(assetPlugin(plugin, "res/Phaser.svg")));
  194. //SCREWS
  195. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, 0)));
  196. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  197. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  198. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  199. //KNOBS
  200. addParam(ParamWidget::create<as_FxKnobBlack>(Vec(43, 60), module, PhaserFx::RATE_PARAM, 0.0f, 1.0f, 0.0f));
  201. addParam(ParamWidget::create<as_FxKnobBlack>(Vec(43, 125), module, PhaserFx::FBK_PARAM, 0.0f, 0.95f, 0.0f));
  202. addParam(ParamWidget::create<as_FxKnobBlack>(Vec(43, 190), module, PhaserFx::DEPTH_PARAM, 0.0f, 1.0f, 0.0f));
  203. //LIGHTS
  204. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 57), module, PhaserFx::RATE_LIGHT));
  205. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 122), module, PhaserFx::FBK_LIGHT));
  206. addChild(ModuleLightWidget::create<SmallLight<YellowLight>>(Vec(39, 187), module, PhaserFx::DEPTH_LIGHT));
  207. //BYPASS SWITCH
  208. addParam(ParamWidget::create<LEDBezel>(Vec(55, 260), module, PhaserFx::BYPASS_SWITCH , 0.0f, 1.0f, 0.0f));
  209. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(57.2, 262), module, PhaserFx::BYPASS_LED));
  210. //INS/OUTS
  211. addInput(Port::create<as_PJ301MPort>(Vec(10, 310), Port::INPUT, module, PhaserFx::INPUT));
  212. addOutput(Port::create<as_PJ301MPort>(Vec(55, 310), Port::OUTPUT, module, PhaserFx::OUT));
  213. //CV INPUTS
  214. addInput(Port::create<as_PJ301MPort>(Vec(10, 67), Port::INPUT, module, PhaserFx::RATE_CV_INPUT));
  215. addInput(Port::create<as_PJ301MPort>(Vec(10, 132), Port::INPUT, module, PhaserFx::FEEDBACK_CV_INPUT));
  216. addInput(Port::create<as_PJ301MPort>(Vec(10, 197), Port::INPUT, module, PhaserFx::DEPTH_CV_INPUT));
  217. //BYPASS CV INPUT
  218. addInput(Port::create<as_PJ301MPort>(Vec(10, 259), Port::INPUT, module, PhaserFx::BYPASS_CV_INPUT));
  219. }
  220. RACK_PLUGIN_MODEL_INIT(AS, PhaserFx) {
  221. Model *modelPhaserFx = Model::create<PhaserFx, PhaserFxWidget>("AS", "PhaserFx", "Phaser FX", EFFECT_TAG);
  222. return modelPhaserFx;
  223. }