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.

259 lines
7.6KB

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