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.

360 lines
11KB

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