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.

248 lines
6.9KB

  1. #include "Fundamental.hpp"
  2. #include "dsp/digital.hpp"
  3. struct LFOGenerator {
  4. float phase = 0.0;
  5. float pw = 0.5;
  6. float freq = 1.0;
  7. bool offset = false;
  8. bool invert = false;
  9. SchmittTrigger resetTrigger;
  10. LFOGenerator() {
  11. resetTrigger.setThresholds(0.0, 0.01);
  12. }
  13. void setPitch(float pitch) {
  14. pitch = fminf(pitch, 8.0);
  15. freq = powf(2.0, pitch);
  16. }
  17. void setPulseWidth(float pw_) {
  18. const float pwMin = 0.01;
  19. pw = clampf(pw_, pwMin, 1.0 - pwMin);
  20. }
  21. void setReset(float reset) {
  22. if (resetTrigger.process(reset)) {
  23. phase = 0.0;
  24. }
  25. }
  26. void step(float dt) {
  27. float deltaPhase = fminf(freq * dt, 0.5);
  28. phase += deltaPhase;
  29. if (phase >= 1.0)
  30. phase -= 1.0;
  31. }
  32. float sin() {
  33. if (offset)
  34. return 1.0 - cosf(2*M_PI * phase) * (invert ? -1.0 : 1.0);
  35. else
  36. return sinf(2*M_PI * phase) * (invert ? -1.0 : 1.0);
  37. }
  38. float tri(float x) {
  39. return 4.0 * fabsf(x - roundf(x));
  40. }
  41. float tri() {
  42. if (offset)
  43. return tri(invert ? phase - 0.5 : phase);
  44. else
  45. return -1.0 + tri(invert ? phase - 0.25 : phase - 0.75);
  46. }
  47. float saw(float x) {
  48. return 2.0 * (x - roundf(x));
  49. }
  50. float saw() {
  51. if (offset)
  52. return invert ? 2.0 * (1.0 - phase) : 2.0 * phase;
  53. else
  54. return saw(phase) * (invert ? -1.0 : 1.0);
  55. }
  56. float sqr() {
  57. float sqr = (phase < pw) ^ invert ? 1.0 : -1.0;
  58. return offset ? sqr + 1.0 : sqr;
  59. }
  60. float light() {
  61. return sinf(2*M_PI * phase);
  62. }
  63. };
  64. struct LFO : Module {
  65. enum ParamIds {
  66. OFFSET_PARAM,
  67. INVERT_PARAM,
  68. FREQ_PARAM,
  69. FM1_PARAM,
  70. FM2_PARAM,
  71. PW_PARAM,
  72. PWM_PARAM,
  73. NUM_PARAMS
  74. };
  75. enum InputIds {
  76. FM1_INPUT,
  77. FM2_INPUT,
  78. RESET_INPUT,
  79. PW_INPUT,
  80. NUM_INPUTS
  81. };
  82. enum OutputIds {
  83. SIN_OUTPUT,
  84. TRI_OUTPUT,
  85. SAW_OUTPUT,
  86. SQR_OUTPUT,
  87. NUM_OUTPUTS
  88. };
  89. enum LightIds {
  90. PHASE_LIGHT,
  91. NUM_LIGHTS
  92. };
  93. LFOGenerator generator;
  94. LFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  95. void step() override;
  96. };
  97. void LFO::step() {
  98. generator.setPitch(params[FREQ_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value);
  99. generator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0);
  100. generator.offset = (params[OFFSET_PARAM].value > 0.0);
  101. generator.invert = (params[INVERT_PARAM].value <= 0.0);
  102. generator.step(1.0 / engineGetSampleRate());
  103. generator.setReset(inputs[RESET_INPUT].value);
  104. outputs[SIN_OUTPUT].value = 5.0 * generator.sin();
  105. outputs[TRI_OUTPUT].value = 5.0 * generator.tri();
  106. outputs[SAW_OUTPUT].value = 5.0 * generator.saw();
  107. outputs[SQR_OUTPUT].value = 5.0 * generator.sqr();
  108. lights[PHASE_LIGHT].value = generator.light();
  109. }
  110. LFOWidget::LFOWidget() {
  111. LFO *module = new LFO();
  112. setModule(module);
  113. box.size = Vec(15*10, 380);
  114. {
  115. SVGPanel *panel = new SVGPanel();
  116. panel->box.size = box.size;
  117. panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO-1.svg")));
  118. addChild(panel);
  119. }
  120. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  121. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  122. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  123. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  124. addParam(createParam<CKSS>(Vec(15, 77), module, LFO::OFFSET_PARAM, 0.0, 1.0, 1.0));
  125. addParam(createParam<CKSS>(Vec(119, 77), module, LFO::INVERT_PARAM, 0.0, 1.0, 1.0));
  126. addParam(createParam<RoundHugeBlackKnob>(Vec(47, 61), module, LFO::FREQ_PARAM, -8.0, 6.0, -1.0));
  127. addParam(createParam<RoundBlackKnob>(Vec(23, 143), module, LFO::FM1_PARAM, 0.0, 1.0, 0.0));
  128. addParam(createParam<RoundBlackKnob>(Vec(91, 143), module, LFO::PW_PARAM, 0.0, 1.0, 0.5));
  129. addParam(createParam<RoundBlackKnob>(Vec(23, 208), module, LFO::FM2_PARAM, 0.0, 1.0, 0.0));
  130. addParam(createParam<RoundBlackKnob>(Vec(91, 208), module, LFO::PWM_PARAM, 0.0, 1.0, 0.0));
  131. addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO::FM1_INPUT));
  132. addInput(createInput<PJ301MPort>(Vec(45, 276), module, LFO::FM2_INPUT));
  133. addInput(createInput<PJ301MPort>(Vec(80, 276), module, LFO::RESET_INPUT));
  134. addInput(createInput<PJ301MPort>(Vec(114, 276), module, LFO::PW_INPUT));
  135. addOutput(createOutput<PJ301MPort>(Vec(11, 320), module, LFO::SIN_OUTPUT));
  136. addOutput(createOutput<PJ301MPort>(Vec(45, 320), module, LFO::TRI_OUTPUT));
  137. addOutput(createOutput<PJ301MPort>(Vec(80, 320), module, LFO::SAW_OUTPUT));
  138. addOutput(createOutput<PJ301MPort>(Vec(114, 320), module, LFO::SQR_OUTPUT));
  139. addChild(createLight<SmallLight<GreenRedLight>>(Vec(99, 42), module, LFO::PHASE_LIGHT));
  140. }
  141. struct LFO2 : Module {
  142. enum ParamIds {
  143. OFFSET_PARAM,
  144. INVERT_PARAM,
  145. FREQ_PARAM,
  146. WAVE_PARAM,
  147. FM_PARAM,
  148. NUM_PARAMS
  149. };
  150. enum InputIds {
  151. FM_INPUT,
  152. RESET_INPUT,
  153. WAVE_INPUT,
  154. NUM_INPUTS
  155. };
  156. enum OutputIds {
  157. INTERP_OUTPUT,
  158. NUM_OUTPUTS
  159. };
  160. enum LightIds {
  161. PHASE_LIGHT,
  162. NUM_LIGHTS
  163. };
  164. LFOGenerator generator;
  165. LFO2() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  166. void step() override;
  167. };
  168. void LFO2::step() {
  169. generator.setPitch(params[FREQ_PARAM].value + params[FM_PARAM].value * inputs[FM_INPUT].value);
  170. generator.offset = (params[OFFSET_PARAM].value > 0.0);
  171. generator.invert = (params[INVERT_PARAM].value <= 0.0);
  172. generator.step(1.0 / engineGetSampleRate());
  173. generator.setReset(inputs[RESET_INPUT].value);
  174. float wave = params[WAVE_PARAM].value + inputs[WAVE_INPUT].value;
  175. wave = clampf(wave, 0.0, 3.0);
  176. float interp;
  177. if (wave < 1.0)
  178. interp = crossf(generator.sin(), generator.tri(), wave);
  179. else if (wave < 2.0)
  180. interp = crossf(generator.tri(), generator.saw(), wave - 1.0);
  181. else
  182. interp = crossf(generator.saw(), generator.sqr(), wave - 2.0);
  183. outputs[INTERP_OUTPUT].value = 5.0 * interp;
  184. lights[PHASE_LIGHT].value = generator.light();
  185. }
  186. LFO2Widget::LFO2Widget() {
  187. LFO2 *module = new LFO2();
  188. setModule(module);
  189. box.size = Vec(15*6, 380);
  190. {
  191. SVGPanel *panel = new SVGPanel();
  192. panel->box.size = box.size;
  193. panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO-2.svg")));
  194. addChild(panel);
  195. }
  196. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  197. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  198. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  199. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  200. addParam(createParam<CKSS>(Vec(62, 150), module, LFO2::OFFSET_PARAM, 0.0, 1.0, 1.0));
  201. addParam(createParam<CKSS>(Vec(62, 215), module, LFO2::INVERT_PARAM, 0.0, 1.0, 1.0));
  202. addParam(createParam<RoundHugeBlackKnob>(Vec(18, 60), module, LFO2::FREQ_PARAM, -8.0, 6.0, -1.0));
  203. addParam(createParam<RoundBlackKnob>(Vec(11, 142), module, LFO2::WAVE_PARAM, 0.0, 3.0, 0.0));
  204. addParam(createParam<RoundBlackKnob>(Vec(11, 207), module, LFO2::FM_PARAM, 0.0, 1.0, 0.5));
  205. addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO2::FM_INPUT));
  206. addInput(createInput<PJ301MPort>(Vec(54, 276), module, LFO2::RESET_INPUT));
  207. addInput(createInput<PJ301MPort>(Vec(11, 319), module, LFO2::WAVE_INPUT));
  208. addOutput(createOutput<PJ301MPort>(Vec(54, 319), module, LFO2::INTERP_OUTPUT));
  209. addChild(createLight<SmallLight<GreenRedLight>>(Vec(68, 41), module, LFO2::PHASE_LIGHT));
  210. }