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
7.2KB

  1. #include "Fundamental.hpp"
  2. #include "dsp/digital.hpp"
  3. struct LowFrequencyOscillator {
  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. LowFrequencyOscillator() {
  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_POS_LIGHT,
  91. PHASE_NEG_LIGHT,
  92. NUM_LIGHTS
  93. };
  94. LowFrequencyOscillator oscillator;
  95. LFO() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  96. void step() override;
  97. };
  98. void LFO::step() {
  99. oscillator.setPitch(params[FREQ_PARAM].value + params[FM1_PARAM].value * inputs[FM1_INPUT].value + params[FM2_PARAM].value * inputs[FM2_INPUT].value);
  100. oscillator.setPulseWidth(params[PW_PARAM].value + params[PWM_PARAM].value * inputs[PW_INPUT].value / 10.0);
  101. oscillator.offset = (params[OFFSET_PARAM].value > 0.0);
  102. oscillator.invert = (params[INVERT_PARAM].value <= 0.0);
  103. oscillator.step(1.0 / engineGetSampleRate());
  104. oscillator.setReset(inputs[RESET_INPUT].value);
  105. outputs[SIN_OUTPUT].value = 5.0 * oscillator.sin();
  106. outputs[TRI_OUTPUT].value = 5.0 * oscillator.tri();
  107. outputs[SAW_OUTPUT].value = 5.0 * oscillator.saw();
  108. outputs[SQR_OUTPUT].value = 5.0 * oscillator.sqr();
  109. lights[PHASE_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, oscillator.light()));
  110. lights[PHASE_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -oscillator.light()));
  111. }
  112. LFOWidget::LFOWidget() {
  113. LFO *module = new LFO();
  114. setModule(module);
  115. box.size = Vec(15*10, 380);
  116. {
  117. SVGPanel *panel = new SVGPanel();
  118. panel->box.size = box.size;
  119. panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO-1.svg")));
  120. addChild(panel);
  121. }
  122. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  123. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  124. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  125. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  126. addParam(createParam<CKSS>(Vec(15, 77), module, LFO::OFFSET_PARAM, 0.0, 1.0, 1.0));
  127. addParam(createParam<CKSS>(Vec(119, 77), module, LFO::INVERT_PARAM, 0.0, 1.0, 1.0));
  128. addParam(createParam<RoundHugeBlackKnob>(Vec(47, 61), module, LFO::FREQ_PARAM, -8.0, 6.0, -1.0));
  129. addParam(createParam<RoundBlackKnob>(Vec(23, 143), module, LFO::FM1_PARAM, 0.0, 1.0, 0.0));
  130. addParam(createParam<RoundBlackKnob>(Vec(91, 143), module, LFO::PW_PARAM, 0.0, 1.0, 0.5));
  131. addParam(createParam<RoundBlackKnob>(Vec(23, 208), module, LFO::FM2_PARAM, 0.0, 1.0, 0.0));
  132. addParam(createParam<RoundBlackKnob>(Vec(91, 208), module, LFO::PWM_PARAM, 0.0, 1.0, 0.0));
  133. addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO::FM1_INPUT));
  134. addInput(createInput<PJ301MPort>(Vec(45, 276), module, LFO::FM2_INPUT));
  135. addInput(createInput<PJ301MPort>(Vec(80, 276), module, LFO::RESET_INPUT));
  136. addInput(createInput<PJ301MPort>(Vec(114, 276), module, LFO::PW_INPUT));
  137. addOutput(createOutput<PJ301MPort>(Vec(11, 320), module, LFO::SIN_OUTPUT));
  138. addOutput(createOutput<PJ301MPort>(Vec(45, 320), module, LFO::TRI_OUTPUT));
  139. addOutput(createOutput<PJ301MPort>(Vec(80, 320), module, LFO::SAW_OUTPUT));
  140. addOutput(createOutput<PJ301MPort>(Vec(114, 320), module, LFO::SQR_OUTPUT));
  141. addChild(createLight<SmallLight<GreenRedLight>>(Vec(99, 42.5), module, LFO::PHASE_POS_LIGHT));
  142. }
  143. struct LFO2 : Module {
  144. enum ParamIds {
  145. OFFSET_PARAM,
  146. INVERT_PARAM,
  147. FREQ_PARAM,
  148. WAVE_PARAM,
  149. FM_PARAM,
  150. NUM_PARAMS
  151. };
  152. enum InputIds {
  153. FM_INPUT,
  154. RESET_INPUT,
  155. WAVE_INPUT,
  156. NUM_INPUTS
  157. };
  158. enum OutputIds {
  159. INTERP_OUTPUT,
  160. NUM_OUTPUTS
  161. };
  162. enum LightIds {
  163. PHASE_POS_LIGHT,
  164. PHASE_NEG_LIGHT,
  165. NUM_LIGHTS
  166. };
  167. LowFrequencyOscillator oscillator;
  168. LFO2() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  169. void step() override;
  170. };
  171. void LFO2::step() {
  172. oscillator.setPitch(params[FREQ_PARAM].value + params[FM_PARAM].value * inputs[FM_INPUT].value);
  173. oscillator.offset = (params[OFFSET_PARAM].value > 0.0);
  174. oscillator.invert = (params[INVERT_PARAM].value <= 0.0);
  175. oscillator.step(1.0 / engineGetSampleRate());
  176. oscillator.setReset(inputs[RESET_INPUT].value);
  177. float wave = params[WAVE_PARAM].value + inputs[WAVE_INPUT].value;
  178. wave = clampf(wave, 0.0, 3.0);
  179. float interp;
  180. if (wave < 1.0)
  181. interp = crossf(oscillator.sin(), oscillator.tri(), wave);
  182. else if (wave < 2.0)
  183. interp = crossf(oscillator.tri(), oscillator.saw(), wave - 1.0);
  184. else
  185. interp = crossf(oscillator.saw(), oscillator.sqr(), wave - 2.0);
  186. outputs[INTERP_OUTPUT].value = 5.0 * interp;
  187. lights[PHASE_POS_LIGHT].setBrightnessSmooth(fmaxf(0.0, oscillator.light()));
  188. lights[PHASE_NEG_LIGHT].setBrightnessSmooth(fmaxf(0.0, -oscillator.light()));
  189. }
  190. LFO2Widget::LFO2Widget() {
  191. LFO2 *module = new LFO2();
  192. setModule(module);
  193. box.size = Vec(15*6, 380);
  194. {
  195. SVGPanel *panel = new SVGPanel();
  196. panel->box.size = box.size;
  197. panel->setBackground(SVG::load(assetPlugin(plugin, "res/LFO-2.svg")));
  198. addChild(panel);
  199. }
  200. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  201. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 0)));
  202. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  203. addChild(createScrew<ScrewSilver>(Vec(box.size.x-30, 365)));
  204. addParam(createParam<CKSS>(Vec(62, 150), module, LFO2::OFFSET_PARAM, 0.0, 1.0, 1.0));
  205. addParam(createParam<CKSS>(Vec(62, 215), module, LFO2::INVERT_PARAM, 0.0, 1.0, 1.0));
  206. addParam(createParam<RoundHugeBlackKnob>(Vec(18, 60), module, LFO2::FREQ_PARAM, -8.0, 6.0, -1.0));
  207. addParam(createParam<RoundBlackKnob>(Vec(11, 142), module, LFO2::WAVE_PARAM, 0.0, 3.0, 1.5));
  208. addParam(createParam<RoundBlackKnob>(Vec(11, 207), module, LFO2::FM_PARAM, 0.0, 1.0, 0.5));
  209. addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO2::FM_INPUT));
  210. addInput(createInput<PJ301MPort>(Vec(54, 276), module, LFO2::RESET_INPUT));
  211. addInput(createInput<PJ301MPort>(Vec(11, 319), module, LFO2::WAVE_INPUT));
  212. addOutput(createOutput<PJ301MPort>(Vec(54, 319), module, LFO2::INTERP_OUTPUT));
  213. addChild(createLight<SmallLight<GreenRedLight>>(Vec(68, 42.5), module, LFO2::PHASE_POS_LIGHT));
  214. }