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.

599 lines
17KB

  1. ///////////////////////////
  2. // Bene2 - Big thx to Strum Mental and JW jeremywen for sharing their magic code !!
  3. // still some fix to do as usuall ;)
  4. //
  5. ///////////////////////
  6. #include "dBiz.hpp"
  7. #include "dsp/digital.hpp"
  8. using namespace std;
  9. namespace rack_plugin_dBiz {
  10. struct Bene2 : Module {
  11. enum ParamIds
  12. {
  13. RESET_LINE,
  14. RESET_COL,
  15. RUNL_PARAM,
  16. RUNC_PARAM,
  17. GATE_PARAM,
  18. KNOB_PARAM=GATE_PARAM+16,
  19. NUM_PARAMS = KNOB_PARAM + 16
  20. };
  21. enum InputIds
  22. {
  23. RESETL_INPUT,
  24. RESETC_INPUT,
  25. RUNC_INPUT,
  26. RUNL_INPUT,
  27. RESETL,
  28. RESETC = RESETL + 4,
  29. UP = RESETC + 4,
  30. DOWN = UP + 4,
  31. LEFT = DOWN + 4,
  32. RIGHT = LEFT + 4,
  33. NUM_INPUTS = RIGHT + 4
  34. };
  35. enum OutputIds
  36. {
  37. GATES_ROW_OUT,
  38. GATES_COL_OUT = GATES_ROW_OUT + 4,
  39. ROW_OUT = GATES_COL_OUT + 4,
  40. COLUMN_OUT = ROW_OUT + 4,
  41. NUM_OUTPUTS = COLUMN_OUT + 4
  42. };
  43. enum LightIds
  44. {
  45. RESETL_LIGHT,
  46. RESETC_LIGHT,
  47. RUNL_LIGHT,
  48. RUNC_LIGHT,
  49. GATE_LIGHT,
  50. STEPS_LIGHT = GATE_LIGHT + 16,
  51. NUM_LIGHTS = STEPS_LIGHT + 16
  52. };
  53. SchmittTrigger leftTrigger[4]={};
  54. SchmittTrigger rightTrigger[4]={};
  55. SchmittTrigger upTrigger[4]={};
  56. SchmittTrigger downTrigger[4]={};
  57. SchmittTrigger resetCoTrigger[4]={};
  58. SchmittTrigger resetLiTrigger[4]={};
  59. SchmittTrigger resetALTrigger;
  60. SchmittTrigger resetACTrigger;
  61. SchmittTrigger runningLTrigger;
  62. SchmittTrigger runningCTrigger;
  63. SchmittTrigger gateTriggers[16]={};
  64. SchmittTrigger button_triggers[4][4];
  65. float row_outs[4] = {0.0,0.0,0.0,0.0};
  66. float column_outs[4] = {0.0,0.0,0.0,0.0};
  67. int posX[4] = {};
  68. int posY[4] = {};
  69. int index[16]={};
  70. int indexl[4] = {};
  71. bool gateState[16] = {};
  72. bool runningL = true;
  73. bool runningC = true;
  74. bool ignoreGateOnPitchOut = false;
  75. enum GateMode
  76. {
  77. TRIGGER,
  78. RETRIGGER,
  79. CONTINUOUS
  80. };
  81. GateMode gateMode = TRIGGER;
  82. PulseGenerator gatePulse;
  83. Bene2() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  84. void step() override;
  85. json_t *toJson() override
  86. {
  87. json_t *rootJ = json_object();
  88. json_object_set_new(rootJ, "running Line", json_boolean(runningL));
  89. json_object_set_new(rootJ, "running Column", json_boolean(runningC));
  90. json_object_set_new(rootJ, "ignoreGateOnPitchOut", json_boolean(ignoreGateOnPitchOut));
  91. // gates
  92. json_t *gatesJ = json_array();
  93. for (int i = 0; i < 16; i++)
  94. {
  95. json_t *gateJ = json_integer((int)gateState[i]);
  96. json_array_append_new(gatesJ, gateJ);
  97. }
  98. json_object_set_new(rootJ, "gates", gatesJ);
  99. // gateMode
  100. json_t *gateModeJ = json_integer((int)gateMode);
  101. json_object_set_new(rootJ, "gateMode", gateModeJ);
  102. return rootJ;
  103. }
  104. void fromJson(json_t *rootJ) override
  105. {
  106. json_t *runningLJ = json_object_get(rootJ, "running Line");
  107. if (runningLJ)
  108. runningL = json_is_true(runningLJ);
  109. json_t *runningCJ = json_object_get(rootJ, "running Column");
  110. if (runningCJ)
  111. runningC = json_is_true(runningCJ);
  112. json_t *ignoreGateOnPitchOutJ = json_object_get(rootJ, "ignoreGateOnPitchOut");
  113. if (ignoreGateOnPitchOutJ)
  114. ignoreGateOnPitchOut = json_is_true(ignoreGateOnPitchOutJ);
  115. // gates
  116. json_t *gatesJ = json_object_get(rootJ, "gates");
  117. if (gatesJ)
  118. {
  119. for (int i = 0; i < 16; i++)
  120. {
  121. json_t *gateJ = json_array_get(gatesJ, i);
  122. if (gateJ)
  123. gateState[i] = !!json_integer_value(gateJ);
  124. }
  125. }
  126. // gateMode
  127. json_t *gateModeJ = json_object_get(rootJ, "gateMode");
  128. if (gateModeJ)
  129. gateMode = (GateMode)json_integer_value(gateModeJ);
  130. }
  131. void reset() override
  132. {
  133. for (int i = 0; i < 16; i++)
  134. {
  135. gateState[i] = false;
  136. }
  137. }
  138. void randomize() override
  139. {
  140. randomizeGateStates();
  141. }
  142. void randomizeGateStates()
  143. {
  144. for (int i = 0; i < 16; i++)
  145. {
  146. gateState[i] = (randomUniform() > 0.50);
  147. }
  148. }
  149. void handleMoveRight() {
  150. for (int i=0; i<4; i++)
  151. {
  152. posX[i] = posX[i] == 3 ? 0 : posX[i] + 1;
  153. }
  154. }
  155. void handleMoveLeft() {
  156. for (int i=0; i<4; i++)
  157. {
  158. posX[i] = posX[i] == 0 ? 3 : posX[i] - 1;
  159. }
  160. }
  161. void handleMoveDown() {
  162. for (int i=0; i<4; i++)
  163. {
  164. posY[i] = posY[i] == 3 ? 0 : posY[i] + 1;
  165. }
  166. }
  167. void handleMoveUp() {
  168. for (int i=0; i<4; i++)
  169. {
  170. posY[i] = posY[i] == 0 ? 3 : posY[i] - 1;
  171. }
  172. }
  173. };
  174. ///////////////////////////////////////////////////////////////////////////////////////////////////
  175. // STEP
  176. ///////////////////////////////////////////////////////////////////////////////////////////////////
  177. void Bene2::step()
  178. {
  179. bool step_right[4] = {false};
  180. bool step_left[4] = {false};
  181. bool step_up[4] = {false};
  182. bool step_down[4] = {false};
  183. const float lightLambda = 0.1;
  184. ///////////////////////////////////////////////////////////////////////////////
  185. // Running Buttons
  186. /////////////////////////////////////////////////////////////////////////////
  187. if (runningLTrigger.process(params[RUNL_PARAM].value+inputs[RUNL_INPUT].value))
  188. {
  189. runningL = !runningL;
  190. }
  191. lights[RUNL_LIGHT].value = runningL ? 1.0 : 0.0;
  192. if (runningCTrigger.process(params[RUNC_PARAM].value))
  193. {
  194. runningC = !runningC;
  195. }
  196. lights[RUNC_LIGHT].value = runningC ? 1.0 : 0.0;
  197. ///////////////////////////////////////////////////////////////////////////////
  198. // RESET
  199. /////////////////////////////////////////////////////////////////////////////
  200. for (int i = 0; i < 4; i++)
  201. {
  202. if (resetLiTrigger[i].process(inputs[RESETL + i].value))
  203. {
  204. posX[i] = 0;
  205. step_right[i] = false;
  206. step_left[i] = false;
  207. lights[STEPS_LIGHT + posX[i] + i * 4].value = 0.8;
  208. }
  209. if (resetCoTrigger[i].process(inputs[RESETC + i].value))
  210. {
  211. posY[i] = 0;
  212. step_up[i] = false;
  213. step_down[i] = false;
  214. lights[STEPS_LIGHT + i + posY[i] * 4].value = 0.8;
  215. }
  216. }
  217. if(resetALTrigger.process(params[RESET_LINE].value+inputs[RESETL_INPUT].value))
  218. {
  219. lights[RESETL_LIGHT].value = 1.0;
  220. for (int i=0;i<4;i++)
  221. {
  222. posX[i] = 0;
  223. step_right[i] = false;
  224. step_left[i] = false;
  225. lights[STEPS_LIGHT + posX[i] + i * 4].value = 0.8;
  226. }
  227. }
  228. if(resetACTrigger.process(params[RESET_COL].value+inputs[RESETC_INPUT].value))
  229. {
  230. lights[RESETC_LIGHT].value = 1.0;
  231. for (int i = 0; i < 4; i++)
  232. {
  233. posY[i] = 0;
  234. step_up[i] = false;
  235. step_down[i] = false;
  236. lights[STEPS_LIGHT + i + posY[i] * 4].value = 0.8;
  237. }
  238. }
  239. if (lights[RESETL_LIGHT].value > 0)
  240. {
  241. lights[RESETL_LIGHT].value -= lights[RESETL_LIGHT].value / lightLambda / engineGetSampleRate();
  242. }
  243. if (lights[RESETC_LIGHT].value > 0)
  244. {
  245. lights[RESETC_LIGHT].value -= lights[RESETC_LIGHT].value / lightLambda / engineGetSampleRate();
  246. }
  247. ///////////////////////////////////////////////////////////////////////////////
  248. // RUN
  249. /////////////////////////////////////////////////////////////////////////////
  250. if (runningL)
  251. {
  252. for (int i = 0; i < 4; i++)
  253. {
  254. // handle clock inputs
  255. if (inputs[RIGHT + i].active)
  256. {
  257. if (rightTrigger[i].process(inputs[RIGHT + i].value))
  258. {
  259. step_right[i] = true;
  260. }
  261. }
  262. if (inputs[LEFT + i].active)
  263. {
  264. if (leftTrigger[i].process(inputs[LEFT + i].value))
  265. {
  266. step_left[i] = true;
  267. }
  268. }
  269. }
  270. }
  271. if (runningC)
  272. {
  273. for (int i = 0; i < 4; i++)
  274. {
  275. if (inputs[DOWN + i].active)
  276. {
  277. if (downTrigger[i].process(inputs[DOWN + i].value))
  278. {
  279. step_down[i] = true;
  280. }
  281. }
  282. if (inputs[UP + i].active)
  283. {
  284. if (upTrigger[i].process(inputs[UP + i].value))
  285. {
  286. step_up[i] = true;
  287. }
  288. }
  289. }
  290. }
  291. for (int i = 0; i < 4; i++)
  292. {
  293. index[i]=posX[i]+(posY[i]*4);
  294. }
  295. // change x and y
  296. for (int i = 0; i < 4; i++)
  297. {
  298. if (step_right[i])
  299. {
  300. posX[i] += 1;
  301. if (posX[i] > 3)
  302. posX[i] = 0;
  303. lights[STEPS_LIGHT + posX[i] + i * 4].value = 0.8;
  304. gatePulse.trigger(1e-3);
  305. }
  306. if (step_left[i])
  307. {
  308. posX[i] -= 1;
  309. if (posX[i] < 0)
  310. posX[i] = 3;
  311. lights[STEPS_LIGHT + posX[i] + i * 4].value = 0.8;
  312. gatePulse.trigger(1e-3);
  313. }
  314. if (step_down[i])
  315. {
  316. posY[i] += 1;
  317. if (posY[i] > 3)
  318. posY[i] = 0;
  319. lights[STEPS_LIGHT + i + posY[i] * 4].value = 0.8;
  320. gatePulse.trigger(1e-3);
  321. }
  322. if (step_up[i])
  323. {
  324. posY[i] -= 1;
  325. if (posY[i] < 0)
  326. posY[i] = 3;
  327. lights[STEPS_LIGHT + i + posY[i] * 4].value = 0.8;
  328. gatePulse.trigger(1e-3);
  329. }
  330. }
  331. bool pulse = gatePulse.process(1.0 / engineGetSampleRate());
  332. for (int i = 0; i < 16; i++)
  333. {
  334. if (gateTriggers[i].process(params[GATE_PARAM + i].value))
  335. {
  336. gateState[i] = !gateState[i];
  337. }
  338. if (lights[STEPS_LIGHT + i].value > 0)
  339. {
  340. lights[STEPS_LIGHT + i].value -= lights[STEPS_LIGHT + i].value / lightLambda / engineGetSampleRate();
  341. }
  342. lights[GATE_LIGHT + i].value = gateState[i] ? 1.0 - lights[STEPS_LIGHT + i].value : lights[STEPS_LIGHT + i].value;
  343. }
  344. // Outputs
  345. for (int i=0;i<4;i++)
  346. {
  347. bool gatesOnL = (runningL && gateState[i + posY[i] * 4]);
  348. if (gateMode == TRIGGER)
  349. gatesOnL = gatesOnL && pulse;
  350. else if (gateMode == RETRIGGER)
  351. gatesOnL = gatesOnL && !pulse;
  352. bool gatesOnC = (runningC && gateState[posX[i] + i * 4]);
  353. if (gateMode == TRIGGER)
  354. gatesOnC = gatesOnC && pulse;
  355. else if (gateMode == RETRIGGER)
  356. gatesOnC = gatesOnC && !pulse;
  357. row_outs[i] = (params[KNOB_PARAM + i + posY[i] * 4].value);
  358. column_outs[i] = (params[KNOB_PARAM + posX[i] + i * 4].value);
  359. if (gatesOnL || ignoreGateOnPitchOut)
  360. {
  361. outputs[ROW_OUT + i].value = row_outs[i];
  362. }
  363. if (gatesOnC || ignoreGateOnPitchOut)
  364. {
  365. outputs[COLUMN_OUT + i].value = column_outs[i];
  366. }
  367. outputs[GATES_COL_OUT + i].value = gatesOnC ? 10.0 : 0.0;
  368. outputs[GATES_ROW_OUT + i].value = gatesOnL ? 10.0 : 0.0;
  369. }
  370. }
  371. template <typename BASE>
  372. struct RunLight : BASE
  373. {
  374. RunLight()
  375. {
  376. this->box.size = mm2px(Vec(5.5, 5.5));
  377. }
  378. };
  379. struct Bene2Widget : ModuleWidget
  380. {
  381. void appendContextMenu(Menu *menu) override;
  382. Bene2Widget(Bene2 *module) : ModuleWidget(module)
  383. {
  384. box.size = Vec(15*20, 380);
  385. int top = 90;
  386. int top2 = 35;
  387. int left = 118;
  388. int column_spacing = 37;
  389. int jacks=30;
  390. int row_spacing = 37;
  391. int lb=18;
  392. {
  393. SVGPanel *panel = new SVGPanel();
  394. panel->box.size = box.size;
  395. panel->setBackground(SVG::load(assetPlugin(plugin,"res/Bene2.svg")));
  396. addChild(panel);
  397. }
  398. for (int i=0;i<4;i++)
  399. {
  400. addInput(Port::create<PJ301MCPort>(Vec(lb, top+jacks*i), Port::INPUT, module, Bene2::LEFT+i));
  401. addInput(Port::create<PJ301MCPort>(Vec(lb+27, top+jacks*i), Port::INPUT, module, Bene2::RIGHT+i));
  402. addInput(Port::create<PJ301MCPort>(Vec(lb + 27 + 27, top + jacks * i), Port::INPUT, module, Bene2::RESETL + i));
  403. addInput(Port::create<PJ301MCPort>(Vec(lb, top+jacks*i + 140), Port::INPUT, module, Bene2::UP+i));
  404. addInput(Port::create<PJ301MCPort>(Vec(lb + 27, top + jacks * i + 140), Port::INPUT, module, Bene2::DOWN + i));
  405. addInput(Port::create<PJ301MCPort>(Vec(lb + 27 + 27, top + jacks * i + 140), Port::INPUT, module, Bene2::RESETC + i));
  406. }
  407. addParam(ParamWidget::create<LEDBezel>(Vec(lb,5+ 10 ), module, Bene2::RUNL_PARAM, 0.0, 1.0, 0.0));
  408. addParam(ParamWidget::create<LEDBezel>(Vec(lb,5+ 10+30), module, Bene2::RUNC_PARAM, 0.0, 1.0, 0.0));
  409. addChild(GrayModuleLightWidget::create<RunLight<OrangeLight>>(Vec(lb+3,5+ 10+3), module, Bene2::RUNL_LIGHT));
  410. addChild(GrayModuleLightWidget::create<RunLight<OrangeLight>>(Vec(lb+3,5+ 10+3+30), module, Bene2::RUNC_LIGHT));
  411. addInput(Port::create<PJ301MCPort>(Vec(lb+30,5+ 9), Port::INPUT, module, Bene2::RUNL_INPUT));
  412. addInput(Port::create<PJ301MCPort>(Vec(lb+ 30,5+ 9 + 30), Port::INPUT, module, Bene2::RUNC_INPUT));
  413. addParam(ParamWidget::create<LEDBezel>(Vec(lb+ 120, 5 + 10), module, Bene2::RESET_LINE, 0.0, 1.0, 0.0));
  414. addParam(ParamWidget::create<LEDBezel>(Vec(lb+ 120, 5 + 10 + 30), module, Bene2::RESET_COL, 0.0, 1.0, 0.0));
  415. addChild(GrayModuleLightWidget::create<RunLight<OrangeLight>>(Vec(lb + 120+3, 5 + 10 + 3), module, Bene2::RESETL_LIGHT));
  416. addChild(GrayModuleLightWidget::create<RunLight<OrangeLight>>(Vec(lb + 120+3, 5 + 10 + 3 + 30), module, Bene2::RESETC_LIGHT));
  417. addInput(Port::create<PJ301MCPort>(Vec(lb + 150, 5 + 9), Port::INPUT, module, Bene2::RESETL_INPUT));
  418. addInput(Port::create<PJ301MCPort>(Vec(lb + 150, 5 + 9 + 30), Port::INPUT, module, Bene2::RESETC_INPUT));
  419. //addInput(Port::create<PJ301MCPort>(Vec(left + column_spacing * 3, top ), Port::INPUT, module, Bene2::RESET));
  420. for ( int i = 0 ; i < 4 ; i++)
  421. {
  422. for ( int j = 0 ; j < 4 ; j++)
  423. {
  424. addParam(ParamWidget::create<Rogan2PWhite>(Vec(left + column_spacing * i, top2 + row_spacing * j + 70), module, Bene2::KNOB_PARAM + i + j * 4, 0.0, 2.0, 1.0));
  425. addParam(ParamWidget::create<LEDBezel>(Vec(left + column_spacing * i + 7.0, top2 + row_spacing * j + 70 + 7.0), module, Bene2::GATE_PARAM + i + j * 4, 0.0, 1.0, 0.0));
  426. addChild(GrayModuleLightWidget::create<RunLight<OrangeLight>>(Vec(left + column_spacing * i + 10, top2 + row_spacing * j + 70 + 10), module, Bene2::STEPS_LIGHT + i + j * 4));
  427. addChild(GrayModuleLightWidget::create<RunLight<OrangeLight>>(Vec(left + column_spacing * i + 10, top2 + row_spacing * j + 70 + 10), module, Bene2::GATE_LIGHT + i + j * 4));
  428. }
  429. addOutput(Port::create<PJ301MOPort>(Vec(left+column_spacing * i+5, top2 + row_spacing * 4 + 75 ), Port::OUTPUT, module, Bene2::ROW_OUT + i));
  430. addOutput(Port::create<PJ301MOPort>(Vec(left+column_spacing * 4+5, top2 + row_spacing * i + 75 ), Port::OUTPUT, module, Bene2::COLUMN_OUT + i));
  431. addOutput(Port::create<PJ301MOPort>(Vec(left + column_spacing*i,300), Port::OUTPUT, module, Bene2::GATES_COL_OUT + i));
  432. addOutput(Port::create<PJ301MOPort>(Vec(left + column_spacing * i,330), Port::OUTPUT, module, Bene2::GATES_ROW_OUT + i));
  433. }
  434. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  435. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  436. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  437. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  438. }
  439. };
  440. struct Bene2PitchMenuItem : MenuItem
  441. {
  442. Bene2 *bene2;
  443. void onAction(EventAction &e) override
  444. {
  445. bene2->ignoreGateOnPitchOut = !bene2->ignoreGateOnPitchOut;
  446. }
  447. void step() override
  448. {
  449. rightText = (bene2->ignoreGateOnPitchOut) ? "✔" : "";
  450. }
  451. };
  452. struct Bene2GateModeItem : MenuItem
  453. {
  454. Bene2 *bene2;
  455. Bene2::GateMode gateMode;
  456. void onAction(EventAction &e) override
  457. {
  458. bene2->gateMode = gateMode;
  459. }
  460. void step() override
  461. {
  462. rightText = (bene2->gateMode == gateMode) ? "✔" : "";
  463. }
  464. };
  465. void Bene2Widget::appendContextMenu(Menu *menu) {
  466. MenuLabel *spacerLabel = new MenuLabel();
  467. menu->addChild(spacerLabel);
  468. Bene2 *bene2 = dynamic_cast<Bene2 *>(module);
  469. assert(bene2);
  470. menu->addChild(MenuLabel::create("Gate Mode"));
  471. Bene2GateModeItem *triggerItem = MenuItem::create<Bene2GateModeItem>("Trigger");
  472. triggerItem->bene2 = bene2;
  473. triggerItem->gateMode = Bene2::TRIGGER;
  474. menu->addChild(triggerItem);
  475. Bene2GateModeItem *retriggerItem = MenuItem::create<Bene2GateModeItem>("Retrigger");
  476. retriggerItem->bene2 = bene2;
  477. retriggerItem->gateMode = Bene2::RETRIGGER;
  478. menu->addChild(retriggerItem);
  479. Bene2GateModeItem *continuousItem = MenuItem::create<Bene2GateModeItem>("Continuous");
  480. continuousItem->bene2 = bene2;
  481. continuousItem->gateMode = Bene2::CONTINUOUS;
  482. menu->addChild(continuousItem);
  483. MenuLabel *spacerLabel2 = new MenuLabel();
  484. menu->addChild(spacerLabel2);
  485. Bene2PitchMenuItem *pitchMenuItem = MenuItem::create<Bene2PitchMenuItem>("Ignore Gate for V/OCT Out");
  486. pitchMenuItem->bene2 = bene2;
  487. menu->addChild(pitchMenuItem);
  488. }
  489. } // namespace rack_plugin_dBiz
  490. using namespace rack_plugin_dBiz;
  491. RACK_PLUGIN_MODEL_INIT(dBiz, Bene2) {
  492. Model *modelBene2 = Model::create<Bene2, Bene2Widget>("dBiz", "Bene2", "Bene2", SEQUENCER_TAG);
  493. return modelBene2;
  494. }