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.

335 lines
10KB

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