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.

231 lines
6.4KB

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