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.

252 lines
9.3KB

  1. //**************************************************************************************
  2. //TriLFO module for VCV Rack by Alfredo Santamaria - AS - https://github.com/AScustomWorks/AS
  3. //
  4. //Code adapted from the Fundamentals plugins by Andrew Belt http://www.vcvrack.com
  5. //**************************************************************************************
  6. #include "AS.hpp"
  7. #include "dsp/digital.hpp"
  8. struct LowFrequencyOscillator {
  9. float phase = 0.0f;
  10. float pw = 0.5f;
  11. float freq = 1.0f;
  12. bool offset = false;
  13. bool invert = false;
  14. SchmittTrigger resetTrigger;
  15. LowFrequencyOscillator() {
  16. //resetTrigger.setThresholds(0.0f, 0.01f);
  17. }
  18. void setPitch(float pitch) {
  19. pitch = fminf(pitch, 8.0f);
  20. freq = powf(2.0f, pitch);
  21. }
  22. void setPulseWidth(float pw_) {
  23. const float pwMin = 0.01f;
  24. pw = clamp(pw_, pwMin, 1.0f - pwMin);
  25. }
  26. void setReset(float reset) {
  27. if (resetTrigger.process(reset)) {
  28. phase = 0.0f;
  29. }
  30. }
  31. void step(float dt) {
  32. float deltaPhase = fminf(freq * dt, 0.5f);
  33. phase += deltaPhase;
  34. if (phase >= 1.0f)
  35. phase -= 1.0f;
  36. }
  37. float sin() {
  38. if (offset)
  39. return 1.0f - cosf(2*M_PI * phase) * (invert ? -1.0f : 1.0f);
  40. else
  41. return sinf(2.0f*M_PI * phase) * (invert ? -1.0f : 1.0f);
  42. }
  43. float tri(float x) {
  44. return 4.0f * fabsf(x - roundf(x));
  45. }
  46. float tri() {
  47. if (offset)
  48. return tri(invert ? phase - 0.5f : phase);
  49. else
  50. return -1.0f + tri(invert ? phase - 0.25f : phase - 0.75f);
  51. }
  52. float saw(float x) {
  53. return 2.0f * (x - roundf(x));
  54. }
  55. float saw() {
  56. if (offset)
  57. return invert ? 2.0f * (1.0f - phase) : 2.0f * phase;
  58. else
  59. return saw(phase) * (invert ? -1.0f : 1.0f);
  60. }
  61. float sqr() {
  62. float sqr = (phase < pw) ^ invert ? 1.0f : -1.0f;
  63. return offset ? sqr + 1.0f : sqr;
  64. }
  65. float light() {
  66. return sinf(2.0f*M_PI * phase);
  67. }
  68. };
  69. struct TriLFO : Module {
  70. enum ParamIds {
  71. OFFSET1_PARAM,
  72. INVERT1_PARAM,
  73. FREQ1_PARAM,
  74. OFFSET2_PARAM,
  75. INVERT2_PARAM,
  76. FREQ2_PARAM,
  77. OFFSET3_PARAM,
  78. INVERT3_PARAM,
  79. FREQ3_PARAM,
  80. //
  81. FM1_PARAM,
  82. FM2_PARAM,
  83. PW_PARAM,
  84. PWM_PARAM,
  85. //
  86. NUM_PARAMS
  87. };
  88. enum InputIds {
  89. FM1_INPUT,
  90. FM2_INPUT,
  91. RESET1_INPUT,
  92. RESET2_INPUT,
  93. RESET3_INPUT,
  94. PW_INPUT,
  95. NUM_INPUTS
  96. };
  97. enum OutputIds {
  98. SIN1_OUTPUT,
  99. TRI1_OUTPUT,
  100. SAW1_OUTPUT,
  101. SQR1_OUTPUT,
  102. SIN2_OUTPUT,
  103. TRI2_OUTPUT,
  104. SAW2_OUTPUT,
  105. SQR2_OUTPUT,
  106. SIN3_OUTPUT,
  107. TRI3_OUTPUT,
  108. SAW3_OUTPUT,
  109. SQR3_OUTPUT,
  110. NUM_OUTPUTS
  111. };
  112. enum LightIds {
  113. PHASE1_POS_LIGHT,
  114. PHASE1_NEG_LIGHT,
  115. PHASE2_POS_LIGHT,
  116. PHASE2_NEG_LIGHT,
  117. PHASE3_POS_LIGHT,
  118. PHASE3_NEG_LIGHT,
  119. NUM_LIGHTS
  120. };
  121. LowFrequencyOscillator oscillator1;
  122. LowFrequencyOscillator oscillator2;
  123. LowFrequencyOscillator oscillator3;
  124. TriLFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  125. void step() override;
  126. float pw_param = 0.5f;
  127. };
  128. void TriLFO::step() {
  129. //LFO1
  130. oscillator1.setPitch(params[FREQ1_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value);
  131. //oscillator1.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0);
  132. oscillator1.setPulseWidth(pw_param);
  133. oscillator1.offset = (params[OFFSET1_PARAM].value > 0.0f);
  134. oscillator1.invert = (params[INVERT1_PARAM].value <= 0.0f);
  135. oscillator1.step(1.0f / engineGetSampleRate());
  136. oscillator1.setReset(inputs[RESET1_INPUT].value);
  137. outputs[SIN1_OUTPUT].value = 5.0f * oscillator1.sin();
  138. outputs[TRI1_OUTPUT].value = 5.0f * oscillator1.tri();
  139. outputs[SAW1_OUTPUT].value = 5.0f * oscillator1.saw();
  140. outputs[SQR1_OUTPUT].value = 5.0f * oscillator1.sqr();
  141. lights[PHASE1_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0f, oscillator1.light()));
  142. lights[PHASE1_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0f, -oscillator1.light()));
  143. //LFO2
  144. oscillator2.setPitch(params[FREQ2_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value);
  145. //oscillator2.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0);
  146. oscillator2.setPulseWidth(pw_param);
  147. oscillator2.offset = (params[OFFSET2_PARAM].value > 0.0f);
  148. oscillator2.invert = (params[INVERT2_PARAM].value <= 0.0f);
  149. oscillator2.step(1.0f / engineGetSampleRate());
  150. oscillator2.setReset(inputs[RESET2_INPUT].value);
  151. outputs[SIN2_OUTPUT].value = 5.0f * oscillator2.sin();
  152. outputs[TRI2_OUTPUT].value = 5.0f * oscillator2.tri();
  153. outputs[SAW2_OUTPUT].value = 5.0f * oscillator2.saw();
  154. outputs[SQR2_OUTPUT].value = 5.0f * oscillator2.sqr();
  155. lights[PHASE2_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0f, oscillator2.light()));
  156. lights[PHASE2_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0f, -oscillator2.light()));
  157. //LFO3
  158. oscillator3.setPitch(params[FREQ3_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value);
  159. //oscillator3.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0);
  160. oscillator3.setPulseWidth(pw_param);
  161. oscillator3.offset = (params[OFFSET3_PARAM].value > 0.0f);
  162. oscillator3.invert = (params[INVERT3_PARAM].value <= 0.0f);
  163. oscillator3.step(1.0f / engineGetSampleRate());
  164. oscillator3.setReset(inputs[RESET3_INPUT].value);
  165. outputs[SIN3_OUTPUT].value = 5.0f * oscillator3.sin();
  166. outputs[TRI3_OUTPUT].value = 5.0f * oscillator3.tri();
  167. outputs[SAW3_OUTPUT].value = 5.0f * oscillator3.saw();
  168. outputs[SQR3_OUTPUT].value = 5.0f * oscillator3.sqr();
  169. lights[PHASE3_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0f, oscillator3.light()));
  170. lights[PHASE3_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0f, -oscillator3.light()));
  171. }
  172. struct TriLFOWidget : ModuleWidget
  173. {
  174. TriLFOWidget(TriLFO *module);
  175. };
  176. TriLFOWidget::TriLFOWidget(TriLFO *module) : ModuleWidget(module) {
  177. setPanel(SVG::load(assetPlugin(plugin, "res/as_LFO.svg")));
  178. //SCREWS
  179. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, 0)));
  180. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  181. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  182. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  183. //LFO 1
  184. addInput(Port::create<as_PJ301MPort>(Vec(10, 60), Port::INPUT, module, TriLFO::RESET1_INPUT));
  185. addParam(ParamWidget::create<as_KnobBlack>(Vec(41, 55), module, TriLFO::FREQ1_PARAM, -8.0f, 6.0f, -1.0f));
  186. //
  187. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(37, 52), module, TriLFO::PHASE1_POS_LIGHT));
  188. //
  189. addParam(ParamWidget::create<as_CKSS>(Vec(90, 60), module, TriLFO::OFFSET1_PARAM, 0.0f, 1.0f, 1.0f));
  190. addParam(ParamWidget::create<as_CKSS>(Vec(120, 60), module, TriLFO::INVERT1_PARAM, 0.0f, 1.0f, 1.0f));
  191. //
  192. addOutput(Port::create<as_PJ301MPort>(Vec(11, 120), Port::OUTPUT, module, TriLFO::SIN1_OUTPUT));
  193. addOutput(Port::create<as_PJ301MPort>(Vec(45, 120), Port::OUTPUT, module, TriLFO::TRI1_OUTPUT));
  194. addOutput(Port::create<as_PJ301MPort>(Vec(80, 120), Port::OUTPUT, module, TriLFO::SAW1_OUTPUT));
  195. addOutput(Port::create<as_PJ301MPort>(Vec(114, 120), Port::OUTPUT, module, TriLFO::SQR1_OUTPUT));
  196. //LFO 2
  197. static const int lfo2_y_offset = 100;
  198. addInput(Port::create<as_PJ301MPort>(Vec(10, 60+lfo2_y_offset), Port::INPUT, module, TriLFO::RESET2_INPUT));
  199. addParam(ParamWidget::create<as_KnobBlack>(Vec(41, 55+lfo2_y_offset), module, TriLFO::FREQ2_PARAM, -8.0f, 6.0f, -1.0f));
  200. //
  201. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(37, 52+lfo2_y_offset), module, TriLFO::PHASE2_POS_LIGHT));
  202. //
  203. addParam(ParamWidget::create<as_CKSS>(Vec(90, 60+lfo2_y_offset), module, TriLFO::OFFSET2_PARAM, 0.0f, 1.0f, 1.0f));
  204. addParam(ParamWidget::create<as_CKSS>(Vec(120, 60+lfo2_y_offset), module, TriLFO::INVERT2_PARAM, 0.0f, 1.0f, 1.0f));
  205. //
  206. addOutput(Port::create<as_PJ301MPort>(Vec(11, 120+lfo2_y_offset), Port::OUTPUT, module, TriLFO::SIN2_OUTPUT));
  207. addOutput(Port::create<as_PJ301MPort>(Vec(45, 120+lfo2_y_offset), Port::OUTPUT, module, TriLFO::TRI2_OUTPUT));
  208. addOutput(Port::create<as_PJ301MPort>(Vec(80, 120+lfo2_y_offset), Port::OUTPUT, module, TriLFO::SAW2_OUTPUT));
  209. addOutput(Port::create<as_PJ301MPort>(Vec(114, 120+lfo2_y_offset), Port::OUTPUT, module, TriLFO::SQR2_OUTPUT));
  210. //LFO 3
  211. static const int lfo3_y_offset = 200;
  212. addInput(Port::create<as_PJ301MPort>(Vec(10, 60+lfo3_y_offset), Port::INPUT, module, TriLFO::RESET3_INPUT));
  213. addParam(ParamWidget::create<as_KnobBlack>(Vec(41, 55+lfo3_y_offset), module, TriLFO::FREQ3_PARAM, -8.0f, 6.0f, -1.0f));
  214. //
  215. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(37, 52+lfo3_y_offset), module, TriLFO::PHASE3_POS_LIGHT));
  216. //
  217. addParam(ParamWidget::create<as_CKSS>(Vec(90, 60+lfo3_y_offset), module, TriLFO::OFFSET3_PARAM, 0.0f, 1.0f, 1.0f));
  218. addParam(ParamWidget::create<as_CKSS>(Vec(120, 60+lfo3_y_offset), module, TriLFO::INVERT3_PARAM, 0.0f, 1.0f, 1.0f));
  219. //
  220. addOutput(Port::create<as_PJ301MPort>(Vec(11, 120+lfo3_y_offset), Port::OUTPUT, module, TriLFO::SIN3_OUTPUT));
  221. addOutput(Port::create<as_PJ301MPort>(Vec(45, 120+lfo3_y_offset), Port::OUTPUT, module, TriLFO::TRI3_OUTPUT));
  222. addOutput(Port::create<as_PJ301MPort>(Vec(80, 120+lfo3_y_offset), Port::OUTPUT, module, TriLFO::SAW3_OUTPUT));
  223. addOutput(Port::create<as_PJ301MPort>(Vec(114, 120+lfo3_y_offset), Port::OUTPUT, module, TriLFO::SQR3_OUTPUT));
  224. }
  225. RACK_PLUGIN_MODEL_INIT(AS, TriLFO) {
  226. Model *modelTriLFO = Model::create<TriLFO, TriLFOWidget>("AS", "TriLFO", "Tri LFO", LFO_TAG);
  227. return modelTriLFO;
  228. }