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.

LFO.cpp 10KB

5 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
5 years ago
5 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. #include "plugin.hpp"
  2. using simd::float_4;
  3. template <typename T>
  4. struct LowFrequencyOscillator {
  5. T phase = 0.f;
  6. T pw = 0.5f;
  7. T freq = 1.f;
  8. bool invert = false;
  9. bool bipolar = false;
  10. T resetState = T::mask();
  11. void setPitch(T pitch) {
  12. pitch = simd::fmin(pitch, 10.f);
  13. freq = dsp::approxExp2_taylor5(pitch + 30) / 1073741824;
  14. }
  15. void setPulseWidth(T pw) {
  16. const T pwMin = 0.01f;
  17. this->pw = clamp(pw, pwMin, 1.f - pwMin);
  18. }
  19. void setReset(T reset) {
  20. reset = simd::rescale(reset, 0.1f, 2.f, 0.f, 1.f);
  21. T on = (reset >= 1.f);
  22. T off = (reset <= 0.f);
  23. T triggered = ~resetState & on;
  24. resetState = simd::ifelse(off, 0.f, resetState);
  25. resetState = simd::ifelse(on, T::mask(), resetState);
  26. phase = simd::ifelse(triggered, 0.f, phase);
  27. }
  28. void step(float dt) {
  29. T deltaPhase = simd::fmin(freq * dt, 0.5f);
  30. phase += deltaPhase;
  31. phase -= (phase >= 1.f) & 1.f;
  32. }
  33. T sin() {
  34. T p = phase;
  35. if (!bipolar)
  36. p -= 0.25f;
  37. T v = simd::sin(2 * M_PI * p);
  38. if (invert)
  39. v *= -1.f;
  40. if (!bipolar)
  41. v += 1.f;
  42. return v;
  43. }
  44. T tri() {
  45. T p = phase;
  46. if (bipolar)
  47. p += 0.25f;
  48. T v = 4.f * simd::fabs(p - simd::round(p)) - 1.f;
  49. if (invert)
  50. v *= -1.f;
  51. if (!bipolar)
  52. v += 1.f;
  53. return v;
  54. }
  55. T saw() {
  56. T p = phase;
  57. if (!bipolar)
  58. p -= 0.5f;
  59. T v = 2.f * (p - simd::round(p));
  60. if (invert)
  61. v *= -1.f;
  62. if (!bipolar)
  63. v += 1.f;
  64. return v;
  65. }
  66. T sqr() {
  67. T v = simd::ifelse(phase < pw, 1.f, -1.f);
  68. if (invert)
  69. v *= -1.f;
  70. if (!bipolar)
  71. v += 1.f;
  72. return v;
  73. }
  74. T light() {
  75. return simd::sin(2 * T(M_PI) * phase);
  76. }
  77. };
  78. struct LFO : Module {
  79. enum ParamIds {
  80. OFFSET_PARAM,
  81. INVERT_PARAM,
  82. FREQ_PARAM,
  83. FM1_PARAM,
  84. FM2_PARAM,
  85. PW_PARAM,
  86. PWM_PARAM,
  87. NUM_PARAMS
  88. };
  89. enum InputIds {
  90. FM1_INPUT,
  91. FM2_INPUT,
  92. RESET_INPUT,
  93. PW_INPUT,
  94. NUM_INPUTS
  95. };
  96. enum OutputIds {
  97. SIN_OUTPUT,
  98. TRI_OUTPUT,
  99. SAW_OUTPUT,
  100. SQR_OUTPUT,
  101. NUM_OUTPUTS
  102. };
  103. enum LightIds {
  104. ENUMS(PHASE_LIGHT, 3),
  105. NUM_LIGHTS
  106. };
  107. LowFrequencyOscillator<float_4> oscillators[4];
  108. dsp::ClockDivider lightDivider;
  109. LFO() {
  110. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  111. configParam(OFFSET_PARAM, 0.f, 1.f, 1.f, "Offset");
  112. configParam(INVERT_PARAM, 0.f, 1.f, 1.f, "Invert");
  113. configParam(FREQ_PARAM, -8.f, 10.f, 1.f, "Frequency", " Hz", 2, 1);
  114. configParam(FM1_PARAM, 0.f, 1.f, 0.f, "Frequency modulation 1", "%", 0.f, 100.f);
  115. configParam(PW_PARAM, 0.01f, 0.99f, 0.5f, "Pulse width", "%", 0.f, 100.f);
  116. configParam(FM2_PARAM, 0.f, 1.f, 0.f, "Frequency modulation 2", "%", 0.f, 100.f);
  117. configParam(PWM_PARAM, 0.f, 1.f, 0.f, "Pulse width modulation", "%", 0.f, 100.f);
  118. lightDivider.setDivision(16);
  119. }
  120. void process(const ProcessArgs& args) override {
  121. float freqParam = params[FREQ_PARAM].getValue();
  122. float fm1Param = params[FM1_PARAM].getValue();
  123. float fm2Param = params[FM2_PARAM].getValue();
  124. float pwParam = params[PW_PARAM].getValue();
  125. float pwmParam = params[PWM_PARAM].getValue();
  126. int channels = std::max(1, inputs[FM1_INPUT].getChannels());
  127. for (int c = 0; c < channels; c += 4) {
  128. auto* oscillator = &oscillators[c / 4];
  129. oscillator->invert = (params[INVERT_PARAM].getValue() == 0.f);
  130. oscillator->bipolar = (params[OFFSET_PARAM].getValue() == 0.f);
  131. float_4 pitch = freqParam;
  132. // FM1, polyphonic
  133. pitch += inputs[FM1_INPUT].getVoltageSimd<float_4>(c) * fm1Param;
  134. // FM2, polyphonic or monophonic
  135. pitch += inputs[FM2_INPUT].getPolyVoltageSimd<float_4>(c) * fm2Param;
  136. oscillator->setPitch(pitch);
  137. // Pulse width
  138. float_4 pw = pwParam + inputs[PW_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * pwmParam;
  139. oscillator->setPulseWidth(pw);
  140. oscillator->step(args.sampleTime);
  141. oscillator->setReset(inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c));
  142. // Outputs
  143. if (outputs[SIN_OUTPUT].isConnected())
  144. outputs[SIN_OUTPUT].setVoltageSimd(5.f * oscillator->sin(), c);
  145. if (outputs[TRI_OUTPUT].isConnected())
  146. outputs[TRI_OUTPUT].setVoltageSimd(5.f * oscillator->tri(), c);
  147. if (outputs[SAW_OUTPUT].isConnected())
  148. outputs[SAW_OUTPUT].setVoltageSimd(5.f * oscillator->saw(), c);
  149. if (outputs[SQR_OUTPUT].isConnected())
  150. outputs[SQR_OUTPUT].setVoltageSimd(5.f * oscillator->sqr(), c);
  151. }
  152. outputs[SIN_OUTPUT].setChannels(channels);
  153. outputs[TRI_OUTPUT].setChannels(channels);
  154. outputs[SAW_OUTPUT].setChannels(channels);
  155. outputs[SQR_OUTPUT].setChannels(channels);
  156. // Light
  157. if (lightDivider.process()) {
  158. if (channels == 1) {
  159. float lightValue = oscillators[0].light().s[0];
  160. lights[PHASE_LIGHT + 0].setSmoothBrightness(-lightValue, args.sampleTime * lightDivider.getDivision());
  161. lights[PHASE_LIGHT + 1].setSmoothBrightness(lightValue, args.sampleTime * lightDivider.getDivision());
  162. lights[PHASE_LIGHT + 2].setBrightness(0.f);
  163. }
  164. else {
  165. lights[PHASE_LIGHT + 0].setBrightness(0.f);
  166. lights[PHASE_LIGHT + 1].setBrightness(0.f);
  167. lights[PHASE_LIGHT + 2].setBrightness(1.f);
  168. }
  169. }
  170. }
  171. };
  172. struct LFOWidget : ModuleWidget {
  173. LFOWidget(LFO* module) {
  174. setModule(module);
  175. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/LFO-1.svg")));
  176. addChild(createWidget<ScrewSilver>(Vec(15, 0)));
  177. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0)));
  178. addChild(createWidget<ScrewSilver>(Vec(15, 365)));
  179. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365)));
  180. addParam(createParam<CKSS>(Vec(15, 77), module, LFO::OFFSET_PARAM));
  181. addParam(createParam<CKSS>(Vec(119, 77), module, LFO::INVERT_PARAM));
  182. addParam(createParam<RoundHugeBlackKnob>(Vec(47, 61), module, LFO::FREQ_PARAM));
  183. addParam(createParam<RoundLargeBlackKnob>(Vec(23, 143), module, LFO::FM1_PARAM));
  184. addParam(createParam<RoundLargeBlackKnob>(Vec(91, 143), module, LFO::PW_PARAM));
  185. addParam(createParam<RoundLargeBlackKnob>(Vec(23, 208), module, LFO::FM2_PARAM));
  186. addParam(createParam<RoundLargeBlackKnob>(Vec(91, 208), module, LFO::PWM_PARAM));
  187. addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO::FM1_INPUT));
  188. addInput(createInput<PJ301MPort>(Vec(45, 276), module, LFO::FM2_INPUT));
  189. addInput(createInput<PJ301MPort>(Vec(80, 276), module, LFO::RESET_INPUT));
  190. addInput(createInput<PJ301MPort>(Vec(114, 276), module, LFO::PW_INPUT));
  191. addOutput(createOutput<PJ301MPort>(Vec(11, 320), module, LFO::SIN_OUTPUT));
  192. addOutput(createOutput<PJ301MPort>(Vec(45, 320), module, LFO::TRI_OUTPUT));
  193. addOutput(createOutput<PJ301MPort>(Vec(80, 320), module, LFO::SAW_OUTPUT));
  194. addOutput(createOutput<PJ301MPort>(Vec(114, 320), module, LFO::SQR_OUTPUT));
  195. addChild(createLight<SmallLight<RedGreenBlueLight>>(Vec(99, 42.5f), module, LFO::PHASE_LIGHT));
  196. }
  197. };
  198. Model* modelLFO = createModel<LFO, LFOWidget>("LFO");
  199. struct LFO2 : Module {
  200. enum ParamIds {
  201. OFFSET_PARAM,
  202. INVERT_PARAM,
  203. FREQ_PARAM,
  204. WAVE_PARAM,
  205. FM_PARAM,
  206. NUM_PARAMS
  207. };
  208. enum InputIds {
  209. FM_INPUT,
  210. RESET_INPUT,
  211. WAVE_INPUT,
  212. NUM_INPUTS
  213. };
  214. enum OutputIds {
  215. INTERP_OUTPUT,
  216. NUM_OUTPUTS
  217. };
  218. enum LightIds {
  219. ENUMS(PHASE_LIGHT, 3),
  220. NUM_LIGHTS
  221. };
  222. LowFrequencyOscillator<float_4> oscillators[4];
  223. dsp::ClockDivider lightDivider;
  224. LFO2() {
  225. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  226. configParam(OFFSET_PARAM, 0.f, 1.f, 1.f, "Offset");
  227. configParam(INVERT_PARAM, 0.f, 1.f, 1.f, "Invert");
  228. configParam(FREQ_PARAM, -8.f, 10.f, 1.f, "Frequency", " Hz", 2, 1);
  229. configParam(WAVE_PARAM, 0.f, 3.f, 1.5f, "Wave");
  230. configParam(FM_PARAM, 0.f, 1.f, 0.5f, "Frequency modulation", "%", 0.f, 100.f);
  231. lightDivider.setDivision(16);
  232. }
  233. void process(const ProcessArgs& args) override {
  234. float freqParam = params[FREQ_PARAM].getValue();
  235. float fmParam = params[FM_PARAM].getValue();
  236. float waveParam = params[WAVE_PARAM].getValue();
  237. int channels = std::max(1, inputs[FM_INPUT].getChannels());
  238. for (int c = 0; c < channels; c += 4) {
  239. auto* oscillator = &oscillators[c / 4];
  240. oscillator->invert = (params[INVERT_PARAM].getValue() == 0.f);
  241. oscillator->bipolar = (params[OFFSET_PARAM].getValue() == 0.f);
  242. float_4 pitch = freqParam + inputs[FM_INPUT].getVoltageSimd<float_4>(c) * fmParam;
  243. oscillator->setPitch(pitch);
  244. oscillator->step(args.sampleTime);
  245. oscillator->setReset(inputs[RESET_INPUT].getPolyVoltageSimd<float_4>(c));
  246. // Outputs
  247. if (outputs[INTERP_OUTPUT].isConnected()) {
  248. float_4 wave = simd::clamp(waveParam + inputs[WAVE_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * 3.f, 0.f, 3.f);
  249. float_4 v = 0.f;
  250. v += oscillator->sin() * simd::fmax(0.f, 1.f - simd::fabs(wave - 0.f));
  251. v += oscillator->tri() * simd::fmax(0.f, 1.f - simd::fabs(wave - 1.f));
  252. v += oscillator->saw() * simd::fmax(0.f, 1.f - simd::fabs(wave - 2.f));
  253. v += oscillator->sqr() * simd::fmax(0.f, 1.f - simd::fabs(wave - 3.f));
  254. outputs[INTERP_OUTPUT].setVoltageSimd(5.f * v, c);
  255. }
  256. }
  257. outputs[INTERP_OUTPUT].setChannels(channels);
  258. // Light
  259. if (lightDivider.process()) {
  260. if (channels == 1) {
  261. float lightValue = oscillators[0].light().s[0];
  262. lights[PHASE_LIGHT + 0].setSmoothBrightness(-lightValue, args.sampleTime * lightDivider.getDivision());
  263. lights[PHASE_LIGHT + 1].setSmoothBrightness(lightValue, args.sampleTime * lightDivider.getDivision());
  264. lights[PHASE_LIGHT + 2].setBrightness(0.f);
  265. }
  266. else {
  267. lights[PHASE_LIGHT + 0].setBrightness(0.f);
  268. lights[PHASE_LIGHT + 1].setBrightness(0.f);
  269. lights[PHASE_LIGHT + 2].setBrightness(1.f);
  270. }
  271. }
  272. }
  273. };
  274. struct LFO2Widget : ModuleWidget {
  275. LFO2Widget(LFO2* module) {
  276. setModule(module);
  277. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/LFO-2.svg")));
  278. addChild(createWidget<ScrewSilver>(Vec(15, 0)));
  279. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 0)));
  280. addChild(createWidget<ScrewSilver>(Vec(15, 365)));
  281. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 30, 365)));
  282. addParam(createParam<CKSS>(Vec(62, 150), module, LFO2::OFFSET_PARAM));
  283. addParam(createParam<CKSS>(Vec(62, 215), module, LFO2::INVERT_PARAM));
  284. addParam(createParam<RoundHugeBlackKnob>(Vec(18, 60), module, LFO2::FREQ_PARAM));
  285. addParam(createParam<RoundLargeBlackKnob>(Vec(11, 142), module, LFO2::WAVE_PARAM));
  286. addParam(createParam<RoundLargeBlackKnob>(Vec(11, 207), module, LFO2::FM_PARAM));
  287. addInput(createInput<PJ301MPort>(Vec(11, 276), module, LFO2::FM_INPUT));
  288. addInput(createInput<PJ301MPort>(Vec(54, 276), module, LFO2::RESET_INPUT));
  289. addInput(createInput<PJ301MPort>(Vec(11, 319), module, LFO2::WAVE_INPUT));
  290. addOutput(createOutput<PJ301MPort>(Vec(54, 319), module, LFO2::INTERP_OUTPUT));
  291. addChild(createLight<SmallLight<RedGreenBlueLight>>(Vec(68, 42.5f), module, LFO2::PHASE_LIGHT));
  292. }
  293. };
  294. Model* modelLFO2 = createModel<LFO2, LFO2Widget>("LFO2");