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.

246 lines
7.6KB

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