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.

510 lines
19KB

  1. #include "SubmarineFree.hpp"
  2. #include "dsp/functions.hpp"
  3. namespace rack_plugin_SubmarineFree {
  4. struct PO_Util {
  5. static constexpr float deg0 = 0.0f;
  6. static constexpr float deg30 = M_PI / 6.0f;
  7. static constexpr float deg45 = M_PI / 4.0f;
  8. static constexpr float deg60 = M_PI / 3.0f;
  9. static constexpr float deg90 = M_PI / 2.0f;
  10. static constexpr float deg120 = 2.0f * M_PI / 3.0f;
  11. static constexpr float deg135 = 3.0f * M_PI / 4.0f;
  12. static constexpr float deg150 = 5.0f * M_PI / 6.0f;
  13. static constexpr float ph0 = 0.0f;
  14. static constexpr float ph30 = 1.0f / 12.0f;
  15. static constexpr float ph45 = 0.125f;
  16. static constexpr float ph60 = 1.0f / 6.0f;
  17. static constexpr float ph90 = 0.25f;
  18. static constexpr float ph120 = 1.0f / 3.0f;
  19. static constexpr float ph135 = 0.375f;
  20. static constexpr float ph150 = 5.0f / 12.0f;
  21. static constexpr float ph180 = 0.5f;
  22. static constexpr float ph210 = 7.0f / 12.0f;
  23. static constexpr float ph225 = 0.625;
  24. static constexpr float ph240 = 2.0f / 3.0f;
  25. static constexpr float ph270 = 0.75f;
  26. static constexpr float ph300 = 5.0f / 6.0f;
  27. static constexpr float ph315 = 0.875f;
  28. static constexpr float ph330 = 11.0f / 12.0f;
  29. float sin(float phase);
  30. float tri(float phase);
  31. float saw(float phase);
  32. float sqr(float phase);
  33. float rsn(float phase);
  34. };
  35. float PO_Util::sin(float phase) {
  36. return 5.0f * sinf(phase);
  37. }
  38. float PO_Util::tri(float phase) {
  39. phase -= floor(phase);
  40. if (phase < 0.25f)
  41. return 20.0f * phase;
  42. if (phase < 0.75f)
  43. return 20.0f * (0.5f - phase);
  44. return 20.0f * (phase - 1.0f);
  45. }
  46. float PO_Util::saw(float phase) {
  47. phase -= floor(phase);
  48. if (phase < 0.5f)
  49. return 10.0f * phase;
  50. return 10.0f * (phase - 1.0f);
  51. }
  52. float PO_Util::sqr(float phase) {
  53. phase -= floor(phase);
  54. return (phase < 0.5f)?5.0f:-5.0f;
  55. }
  56. float PO_Util::rsn(float phase) {
  57. return 10.0f * fabs(sinf(phase)) - 5.0f;
  58. }
  59. struct PO_101 : Module, PO_Util {
  60. enum ParamIds {
  61. PARAM_TUNE,
  62. PARAM_FINE,
  63. PARAM_WAVE,
  64. PARAM_PHASE_1,
  65. PARAM_PHASE_2,
  66. PARAM_PHASE_3,
  67. PARAM_PHASE_4,
  68. NUM_PARAMS
  69. };
  70. enum InputIds {
  71. INPUT_NOTE_CV,
  72. INPUT_PHASE_1,
  73. INPUT_PHASE_2,
  74. INPUT_PHASE_3,
  75. INPUT_PHASE_4,
  76. NUM_INPUTS
  77. };
  78. enum OutputIds {
  79. OUTPUT_1,
  80. OUTPUT_2,
  81. OUTPUT_3,
  82. OUTPUT_4,
  83. OUTPUT_5,
  84. OUTPUT_6,
  85. OUTPUT_7,
  86. OUTPUT_8,
  87. OUTPUT_9,
  88. OUTPUT_10,
  89. OUTPUT_11,
  90. OUTPUT_12,
  91. OUTPUT_13,
  92. OUTPUT_14,
  93. OUTPUT_15,
  94. OUTPUT_16,
  95. OUTPUT_17,
  96. OUTPUT_18,
  97. OUTPUT_19,
  98. OUTPUT_20,
  99. NUM_OUTPUTS
  100. };
  101. enum LightIds {
  102. NUM_LIGHTS
  103. };
  104. PO_101() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  105. void step() override;
  106. void sin(float phase);
  107. void tri(float phase);
  108. void saw(float phase);
  109. void sqr(float phase);
  110. void rsn(float phase);
  111. float phase = 0.0f;
  112. float baseFreq = 261.626f;
  113. };
  114. void PO_101::sin(float phase) {
  115. phase *= (2 * M_PI);
  116. if (outputs[OUTPUT_1].active || outputs[OUTPUT_9].active)
  117. outputs[OUTPUT_9].value = -(outputs[OUTPUT_1].value = PO_Util::sin(phase + deg0));
  118. if (outputs[OUTPUT_2].active || outputs[OUTPUT_10].active)
  119. outputs[OUTPUT_10].value = -(outputs[OUTPUT_2].value = PO_Util::sin(phase + deg30));
  120. if (outputs[OUTPUT_3].active || outputs[OUTPUT_11].active)
  121. outputs[OUTPUT_11].value = -(outputs[OUTPUT_3].value = PO_Util::sin(phase + deg45));
  122. if (outputs[OUTPUT_4].active || outputs[OUTPUT_12].active)
  123. outputs[OUTPUT_12].value = -(outputs[OUTPUT_4].value = PO_Util::sin(phase + deg60));
  124. if (outputs[OUTPUT_5].active || outputs[OUTPUT_13].active)
  125. outputs[OUTPUT_13].value = -(outputs[OUTPUT_5].value = PO_Util::sin(phase + deg90));
  126. if (outputs[OUTPUT_6].active || outputs[OUTPUT_14].active)
  127. outputs[OUTPUT_14].value = -(outputs[OUTPUT_6].value = PO_Util::sin(phase + deg120));
  128. if (outputs[OUTPUT_7].active || outputs[OUTPUT_15].active)
  129. outputs[OUTPUT_15].value = -(outputs[OUTPUT_7].value = PO_Util::sin(phase + deg135));
  130. if (outputs[OUTPUT_8].active || outputs[OUTPUT_16].active)
  131. outputs[OUTPUT_16].value = -(outputs[OUTPUT_8].value = PO_Util::sin(phase + deg150));
  132. for (int i = 0; i < 4; i++) {
  133. if (outputs[OUTPUT_17 + i].active) {
  134. float offset = params[PARAM_PHASE_1 + i].value;
  135. if (inputs[INPUT_PHASE_1 + i].active)
  136. offset += inputs[INPUT_PHASE_1 + i].value * 0.4f;
  137. offset *= 2 * M_PI;
  138. outputs[OUTPUT_17 + i].value = PO_Util::sin(phase + offset);
  139. }
  140. }
  141. }
  142. void PO_101::tri(float phase) {
  143. if (outputs[OUTPUT_1].active || outputs[OUTPUT_9].active)
  144. outputs[OUTPUT_9].value = -(outputs[OUTPUT_1].value = PO_Util::tri(phase + ph0));
  145. if (outputs[OUTPUT_2].active || outputs[OUTPUT_10].active)
  146. outputs[OUTPUT_10].value = -(outputs[OUTPUT_2].value = PO_Util::tri(phase + ph30));
  147. if (outputs[OUTPUT_3].active || outputs[OUTPUT_11].active)
  148. outputs[OUTPUT_11].value = -(outputs[OUTPUT_3].value = PO_Util::tri(phase + ph45));
  149. if (outputs[OUTPUT_4].active || outputs[OUTPUT_12].active)
  150. outputs[OUTPUT_12].value = -(outputs[OUTPUT_4].value = PO_Util::tri(phase + ph60));
  151. if (outputs[OUTPUT_5].active || outputs[OUTPUT_13].active)
  152. outputs[OUTPUT_13].value = -(outputs[OUTPUT_5].value = PO_Util::tri(phase + ph90));
  153. if (outputs[OUTPUT_6].active || outputs[OUTPUT_14].active)
  154. outputs[OUTPUT_14].value = -(outputs[OUTPUT_6].value = PO_Util::tri(phase + ph120));
  155. if (outputs[OUTPUT_7].active || outputs[OUTPUT_15].active)
  156. outputs[OUTPUT_15].value = -(outputs[OUTPUT_7].value = PO_Util::tri(phase + ph135));
  157. if (outputs[OUTPUT_8].active || outputs[OUTPUT_16].active)
  158. outputs[OUTPUT_16].value = -(outputs[OUTPUT_8].value = PO_Util::tri(phase + ph150));
  159. for (int i = 0; i < 4; i++) {
  160. if (outputs[OUTPUT_17 + i].active) {
  161. float offset = params[PARAM_PHASE_1 + i].value;
  162. if (inputs[INPUT_PHASE_1 + i].active)
  163. offset += inputs[INPUT_PHASE_1 + i].value * 0.4f;
  164. outputs[OUTPUT_17 + i].value = PO_Util::tri(phase + offset);
  165. }
  166. }
  167. }
  168. void PO_101::saw(float phase) {
  169. if (outputs[OUTPUT_1].active)
  170. outputs[OUTPUT_1].value = PO_Util::saw(phase + ph0);
  171. if (outputs[OUTPUT_2].active)
  172. outputs[OUTPUT_2].value = PO_Util::saw(phase + ph30);
  173. if (outputs[OUTPUT_3].active)
  174. outputs[OUTPUT_3].value = PO_Util::saw(phase + ph45);
  175. if (outputs[OUTPUT_4].active)
  176. outputs[OUTPUT_4].value = PO_Util::saw(phase + ph60);
  177. if (outputs[OUTPUT_5].active)
  178. outputs[OUTPUT_5].value = PO_Util::saw(phase + ph90);
  179. if (outputs[OUTPUT_6].active)
  180. outputs[OUTPUT_6].value = PO_Util::saw(phase + ph120);
  181. if (outputs[OUTPUT_7].active)
  182. outputs[OUTPUT_7].value = PO_Util::saw(phase + ph135);
  183. if (outputs[OUTPUT_8].active)
  184. outputs[OUTPUT_8].value = PO_Util::saw(phase + ph150);
  185. if (outputs[OUTPUT_9].active)
  186. outputs[OUTPUT_9].value = PO_Util::saw(phase + ph180);
  187. if (outputs[OUTPUT_10].active)
  188. outputs[OUTPUT_10].value = PO_Util::saw(phase + ph210);
  189. if (outputs[OUTPUT_11].active)
  190. outputs[OUTPUT_11].value = PO_Util::saw(phase + ph225);
  191. if (outputs[OUTPUT_12].active)
  192. outputs[OUTPUT_12].value = PO_Util::saw(phase + ph240);
  193. if (outputs[OUTPUT_13].active)
  194. outputs[OUTPUT_13].value = PO_Util::saw(phase + ph270);
  195. if (outputs[OUTPUT_14].active)
  196. outputs[OUTPUT_14].value = PO_Util::saw(phase + ph300);
  197. if (outputs[OUTPUT_15].active)
  198. outputs[OUTPUT_15].value = PO_Util::saw(phase + ph315);
  199. if (outputs[OUTPUT_16].active)
  200. outputs[OUTPUT_16].value = PO_Util::saw(phase + ph330);
  201. for (int i = 0; i < 4; i++) {
  202. if (outputs[OUTPUT_17 + i].active) {
  203. float offset = params[PARAM_PHASE_1 + i].value;
  204. if (inputs[INPUT_PHASE_1 + i].active)
  205. offset += inputs[INPUT_PHASE_1 + i].value * 0.4f;
  206. outputs[OUTPUT_17 + i].value = PO_Util::saw(phase + offset);
  207. }
  208. }
  209. }
  210. void PO_101::sqr(float phase) {
  211. if (outputs[OUTPUT_1].active || outputs[OUTPUT_9].active)
  212. outputs[OUTPUT_9].value = -(outputs[OUTPUT_1].value = PO_Util::sqr(phase + ph0));
  213. if (outputs[OUTPUT_2].active || outputs[OUTPUT_10].active)
  214. outputs[OUTPUT_10].value = -(outputs[OUTPUT_2].value = PO_Util::sqr(phase + ph30));
  215. if (outputs[OUTPUT_3].active || outputs[OUTPUT_11].active)
  216. outputs[OUTPUT_11].value = -(outputs[OUTPUT_3].value = PO_Util::sqr(phase + ph45));
  217. if (outputs[OUTPUT_4].active || outputs[OUTPUT_12].active)
  218. outputs[OUTPUT_12].value = -(outputs[OUTPUT_4].value = PO_Util::sqr(phase + ph60));
  219. if (outputs[OUTPUT_5].active || outputs[OUTPUT_13].active)
  220. outputs[OUTPUT_13].value = -(outputs[OUTPUT_5].value = PO_Util::sqr(phase + ph90));
  221. if (outputs[OUTPUT_6].active || outputs[OUTPUT_14].active)
  222. outputs[OUTPUT_14].value = -(outputs[OUTPUT_6].value = PO_Util::sqr(phase + ph120));
  223. if (outputs[OUTPUT_7].active || outputs[OUTPUT_15].active)
  224. outputs[OUTPUT_15].value = -(outputs[OUTPUT_7].value = PO_Util::sqr(phase + ph135));
  225. if (outputs[OUTPUT_8].active || outputs[OUTPUT_16].active)
  226. outputs[OUTPUT_16].value = -(outputs[OUTPUT_8].value = PO_Util::sqr(phase + ph150));
  227. for (int i = 0; i < 4; i++) {
  228. if (outputs[OUTPUT_17 + i].active) {
  229. float offset = params[PARAM_PHASE_1 + i].value;
  230. if (inputs[INPUT_PHASE_1 + i].active)
  231. offset += inputs[INPUT_PHASE_1 + i].value * 0.4f;
  232. outputs[OUTPUT_17 + i].value = PO_Util::sqr(phase + offset);
  233. }
  234. }
  235. }
  236. void PO_101::rsn(float phase) {
  237. phase *= (2 * M_PI);
  238. if (outputs[OUTPUT_1].active || outputs[OUTPUT_9].active)
  239. outputs[OUTPUT_9].value = (outputs[OUTPUT_1].value = PO_Util::rsn(phase + deg0));
  240. if (outputs[OUTPUT_2].active || outputs[OUTPUT_10].active)
  241. outputs[OUTPUT_10].value = (outputs[OUTPUT_2].value = PO_Util::rsn(phase + deg30));
  242. if (outputs[OUTPUT_3].active || outputs[OUTPUT_11].active)
  243. outputs[OUTPUT_11].value = (outputs[OUTPUT_3].value = PO_Util::rsn(phase + deg45));
  244. if (outputs[OUTPUT_4].active || outputs[OUTPUT_12].active)
  245. outputs[OUTPUT_12].value = (outputs[OUTPUT_4].value = PO_Util::rsn(phase + deg60));
  246. if (outputs[OUTPUT_5].active || outputs[OUTPUT_13].active)
  247. outputs[OUTPUT_13].value = (outputs[OUTPUT_5].value = PO_Util::rsn(phase + deg90));
  248. if (outputs[OUTPUT_6].active || outputs[OUTPUT_14].active)
  249. outputs[OUTPUT_14].value = (outputs[OUTPUT_6].value = PO_Util::rsn(phase + deg120));
  250. if (outputs[OUTPUT_7].active || outputs[OUTPUT_15].active)
  251. outputs[OUTPUT_15].value = (outputs[OUTPUT_7].value = PO_Util::rsn(phase + deg135));
  252. if (outputs[OUTPUT_8].active || outputs[OUTPUT_16].active)
  253. outputs[OUTPUT_16].value = (outputs[OUTPUT_8].value = PO_Util::rsn(phase + deg150));
  254. for (int i = 0; i < 4; i++) {
  255. if (outputs[OUTPUT_17 + i].active) {
  256. float offset = params[PARAM_PHASE_1 + i].value;
  257. if (inputs[INPUT_PHASE_1 + i].active)
  258. offset += inputs[INPUT_PHASE_1 + i].value * 0.4f;
  259. offset *= 2 * M_PI;
  260. outputs[OUTPUT_17 + i].value = PO_Util::rsn(phase + offset);
  261. }
  262. }
  263. }
  264. void PO_101::step() {
  265. float freq = baseFreq * powf(2.0f, (params[PARAM_TUNE].value + 3.0f * quadraticBipolar(params[PARAM_FINE].value)) / 12.0f + (inputs[INPUT_NOTE_CV].active?inputs[INPUT_NOTE_CV].value:0.0f));
  266. float deltaTime = freq / engineGetSampleRate();
  267. phase += deltaTime;
  268. double intPart;
  269. phase = modf(phase, &intPart);
  270. {
  271. float waveShape = clamp(params[PARAM_WAVE].value, 0.0f, 4.0f);
  272. if (waveShape < 0.5f)
  273. sin(phase);
  274. else if (waveShape < 1.5f)
  275. tri(phase);
  276. else if (waveShape < 2.5f)
  277. saw(phase);
  278. else if (waveShape < 3.5f)
  279. sqr(phase);
  280. else
  281. rsn(phase);
  282. }
  283. }
  284. struct PO_204 : Module, PO_Util {
  285. enum ParamIds {
  286. PARAM_TUNE,
  287. PARAM_FINE,
  288. PARAM_WAVE_1,
  289. PARAM_WAVE_2,
  290. PARAM_WAVE_3,
  291. PARAM_WAVE_4,
  292. PARAM_PHASE_1,
  293. PARAM_PHASE_2,
  294. PARAM_PHASE_3,
  295. PARAM_PHASE_4,
  296. PARAM_MULT_1,
  297. PARAM_MULT_2,
  298. PARAM_MULT_3,
  299. PARAM_MULT_4,
  300. NUM_PARAMS
  301. };
  302. enum InputIds {
  303. INPUT_TUNE,
  304. INPUT_WAVE_1,
  305. INPUT_WAVE_2,
  306. INPUT_WAVE_3,
  307. INPUT_WAVE_4,
  308. INPUT_PHASE_1,
  309. INPUT_PHASE_2,
  310. INPUT_PHASE_3,
  311. INPUT_PHASE_4,
  312. INPUT_MULT_1,
  313. INPUT_MULT_2,
  314. INPUT_MULT_3,
  315. INPUT_MULT_4,
  316. NUM_INPUTS
  317. };
  318. enum OutputIds {
  319. OUTPUT_1,
  320. OUTPUT_2,
  321. OUTPUT_3,
  322. OUTPUT_4,
  323. NUM_OUTPUTS
  324. };
  325. enum LightIds {
  326. NUM_LIGHTS
  327. };
  328. PO_204() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  329. void step() override;
  330. float phase = 0.0f;
  331. float baseFreq = 261.626f;
  332. };
  333. void PO_204::step() {
  334. float freq = baseFreq * powf(2.0f, (params[PARAM_TUNE].value + 3.0f * quadraticBipolar(params[PARAM_FINE].value)) / 12.0f + (inputs[INPUT_TUNE].active?inputs[INPUT_TUNE].value:0.0f));
  335. float deltaTime = freq / engineGetSampleRate();
  336. phase += deltaTime;
  337. double intPart;
  338. phase = modf(phase, &intPart);
  339. for (int i = 0; i < 4; i++) {
  340. if (outputs[OUTPUT_1 + i].active) {
  341. float offset = phase + params[PARAM_PHASE_1 + i].value;
  342. if (inputs[INPUT_PHASE_1 + i].active)
  343. offset += inputs[INPUT_PHASE_1 + i].value * 0.4f;
  344. offset *= floor(clamp(params[PARAM_MULT_1 + i].value + (inputs[INPUT_MULT_1 + i].active?inputs[INPUT_MULT_1 + i].value:0.0f) * 16.0f / 10.0f, 1.0f, 16.5f));
  345. float wave = params[PARAM_WAVE_1 + i].value + (inputs[INPUT_WAVE_1 + i].active?inputs[INPUT_WAVE_1 + i].value:0.0f);
  346. double waveSection;
  347. wave = modf(clamp(wave, 0.0f, 10.0f), &waveSection);
  348. float w1 = 0.0f;
  349. float w2 = 0.0f;
  350. switch ((int)waveSection) {
  351. case 0:
  352. w1 = PO_Util::sin(offset * 2 * M_PI);
  353. w2 = PO_Util::saw(offset);
  354. break;
  355. case 1:
  356. w1 = PO_Util::saw(offset);
  357. w2 = PO_Util::rsn(offset * 2 * M_PI);
  358. break;
  359. case 2:
  360. w1 = PO_Util::rsn(offset * 2 * M_PI);
  361. w2 = PO_Util::tri(offset);
  362. break;
  363. case 3:
  364. w1 = PO_Util::tri(offset);
  365. w2 = PO_Util::sqr(offset);
  366. break;
  367. case 4:
  368. w1 = PO_Util::sqr(offset);
  369. w2 = PO_Util::sin(offset * 2 * M_PI);
  370. break;
  371. case 5:
  372. w1 = PO_Util::sin(offset * 2 * M_PI);
  373. w2 = PO_Util::tri(offset);
  374. break;
  375. case 6:
  376. w1 = PO_Util::tri(offset);
  377. w2 = PO_Util::saw(offset);
  378. break;
  379. case 7:
  380. w1 = PO_Util::saw(offset);
  381. w2 = PO_Util::sqr(offset);
  382. break;
  383. case 8:
  384. w1 = PO_Util::sqr(offset);
  385. w2 = PO_Util::rsn(offset * 2 * M_PI);
  386. break;
  387. case 9:
  388. w1 = PO_Util::rsn(offset * 2 * M_PI);
  389. w2 = PO_Util::sin(offset * 2 * M_PI);
  390. break;
  391. default:
  392. w2 = w1 = PO_Util::sin(offset * 2 * M_PI);
  393. break;
  394. }
  395. outputs[OUTPUT_1 + i].value = w1 * (1.0f - wave) + w2 * wave;
  396. }
  397. }
  398. }
  399. struct PO_Layout : ModuleWidget {
  400. PO_Layout(PO_101 *module) : ModuleWidget(module) {}
  401. void Layout() {
  402. addParam(ParamWidget::create<MedKnob<LightKnob>>(Vec(66, 39), module, PO_101::PARAM_FINE, -1.0f, +1.0f, 0.0f));
  403. addParam(ParamWidget::create<NarrowKnob<SnapKnob<MedKnob<LightKnob>>>>(Vec(121, 39), module, PO_101::PARAM_WAVE, 0.0f, +4.0f, 0.0f));
  404. addInput(Port::create<SilverPort>(Vec(45,19), Port::INPUT, module, PO_101::INPUT_NOTE_CV));
  405. addOutput(Port::create<SilverPort>(Vec(77.5,100), Port::OUTPUT, module, PO_101::OUTPUT_1));
  406. addOutput(Port::create<SilverPort>(Vec(110,109), Port::OUTPUT, module, PO_101::OUTPUT_2));
  407. addOutput(Port::create<SilverPort>(Vec(142.5,100), Port::OUTPUT, module, PO_101::OUTPUT_3));
  408. addOutput(Port::create<SilverPort>(Vec(133.5,132.5), Port::OUTPUT, module, PO_101::OUTPUT_4));
  409. addOutput(Port::create<SilverPort>(Vec(142.5,165), Port::OUTPUT, module, PO_101::OUTPUT_5));
  410. addOutput(Port::create<SilverPort>(Vec(133.5,197.5), Port::OUTPUT, module, PO_101::OUTPUT_6));
  411. addOutput(Port::create<SilverPort>(Vec(142.5,230), Port::OUTPUT, module, PO_101::OUTPUT_7));
  412. addOutput(Port::create<SilverPort>(Vec(110,221), Port::OUTPUT, module, PO_101::OUTPUT_8));
  413. addOutput(Port::create<SilverPort>(Vec(77.5,230), Port::OUTPUT, module, PO_101::OUTPUT_9));
  414. addOutput(Port::create<SilverPort>(Vec(45,221), Port::OUTPUT, module, PO_101::OUTPUT_10));
  415. addOutput(Port::create<SilverPort>(Vec(12.5,230), Port::OUTPUT, module, PO_101::OUTPUT_11));
  416. addOutput(Port::create<SilverPort>(Vec(21.5,197.5), Port::OUTPUT, module, PO_101::OUTPUT_12));
  417. addOutput(Port::create<SilverPort>(Vec(12.5,165), Port::OUTPUT, module, PO_101::OUTPUT_13));
  418. addOutput(Port::create<SilverPort>(Vec(21.5,132.5), Port::OUTPUT, module, PO_101::OUTPUT_14));
  419. addOutput(Port::create<SilverPort>(Vec(12.5,100), Port::OUTPUT, module, PO_101::OUTPUT_15));
  420. addOutput(Port::create<SilverPort>(Vec(45,109), Port::OUTPUT, module, PO_101::OUTPUT_16));
  421. for (int i = 0; i < 4; i++) {
  422. addInput(Port::create<SilverPort>(Vec(10 + 45 * i,260), Port::INPUT, module, PO_101::INPUT_PHASE_1 + i));
  423. addParam(ParamWidget::create<MedKnob<LightKnob>>(Vec(3.5 + 45 * i, 290), module, PO_101::PARAM_PHASE_1 + i, -1.0f, +1.0f, 0.0f));
  424. addOutput(Port::create<SilverPort>(Vec(10 + 45 * i,333), Port::OUTPUT, module, PO_101::OUTPUT_17 + i));
  425. }
  426. }
  427. };
  428. struct PO101 : PO_Layout {
  429. PO101(PO_101 *module) : PO_Layout(module) {
  430. setPanel(SVG::load(assetPlugin(plugin, "res/PO-101.svg")));
  431. addParam(ParamWidget::create<MedKnob<LightKnob>>(Vec(11, 39), module, PO_101::PARAM_TUNE, -54.0f, +54.0f, 0.0f));
  432. Layout();
  433. }
  434. };
  435. struct PO102 : PO_Layout {
  436. PO102(PO_101 *module) : PO_Layout(module) {
  437. setPanel(SVG::load(assetPlugin(plugin, "res/PO-102.svg")));
  438. addParam(ParamWidget::create<MedKnob<LightKnob>>(Vec(11, 39), module, PO_101::PARAM_TUNE, -96.0f, 72.0f, -12.0f));
  439. module->baseFreq = 1.0f;
  440. Layout();
  441. }
  442. };
  443. struct PO204 : ModuleWidget {
  444. PO204(PO_204 *module) : ModuleWidget(module) {
  445. setPanel(SVG::load(assetPlugin(plugin, "res/PO-204.svg")));
  446. addParam(ParamWidget::create<MedKnob<LightKnob>>(Vec(60, 19), module, PO_204::PARAM_TUNE, -90.0f, +54.0f, 0.0f));
  447. addParam(ParamWidget::create<MedKnob<LightKnob>>(Vec(105, 19), module, PO_204::PARAM_FINE, -1.0f, +1.0f, 0.0f));
  448. addInput(Port::create<SilverPort>(Vec(17.5, 25.5), Port::INPUT, module, PO_204::INPUT_TUNE));
  449. for (int i = 0; i < 4; i++) {
  450. addParam(ParamWidget::create<SmallKnob<LightKnob>>(Vec(5, 89 + 70 * i), module, PO_204::PARAM_WAVE_1 + i, 0.0f, 10.0f, 5.0f));
  451. addParam(ParamWidget::create<SmallKnob<LightKnob>>(Vec(45, 89 + 70 * i), module, PO_204::PARAM_PHASE_1 + i, -1.0f, +1.0f, 0.0f));
  452. addParam(ParamWidget::create<SnapKnob<SmallKnob<LightKnob>>>(Vec(85, 89 + 70 * i), module, PO_204::PARAM_MULT_1 + i, 1.0f, 16.0f, 1.0f));
  453. addInput(Port::create<SilverPort>(Vec(4.5, 125 + 70 * i), Port::INPUT, module, PO_204::INPUT_WAVE_1 + i));
  454. addInput(Port::create<SilverPort>(Vec(44.5, 125 + 70 * i), Port::INPUT, module, PO_204::INPUT_PHASE_1 + i));
  455. addInput(Port::create<SilverPort>(Vec(84.5, 125 + 70 * i), Port::INPUT, module, PO_204::INPUT_MULT_1 + i));
  456. addOutput(Port::create<SilverPort>(Vec(120.5, 125 + 70 * i), Port::OUTPUT, module, PO_204::OUTPUT_1 + i));
  457. }
  458. }
  459. };
  460. } // namespace rack_plugin_SubmarineFree
  461. using namespace rack_plugin_SubmarineFree;
  462. RACK_PLUGIN_MODEL_INIT(SubmarineFree, PO101) {
  463. Model *modelPO101 = Model::create<PO_101, PO101>("Submarine (Free)", "PO-101", "PO-101 Phased VCO", OSCILLATOR_TAG, MULTIPLE_TAG, DIGITAL_TAG);
  464. return modelPO101;
  465. }
  466. RACK_PLUGIN_MODEL_INIT(SubmarineFree, PO102) {
  467. Model *modelPO102 = Model::create<PO_101, PO102>("Submarine (Free)", "PO-102", "PO-102 Phased LFO", OSCILLATOR_TAG, MULTIPLE_TAG, DIGITAL_TAG);
  468. return modelPO102;
  469. }
  470. RACK_PLUGIN_MODEL_INIT(SubmarineFree, PO204) {
  471. Model *modelPO204 = Model::create<PO_204, PO204>("Submarine (Free)", "PO-204", "PO-204 Phase Modulation Engine", OSCILLATOR_TAG, QUAD_TAG, DIGITAL_TAG);
  472. return modelPO204;
  473. }