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.

600 lines
22KB

  1. #include "dsp/digital.hpp"
  2. #include "moDllz.hpp"
  3. #include "dsp/filter.hpp"
  4. /*
  5. * XBender
  6. */
  7. namespace rack_plugin_moDllz {
  8. struct XBender : Module {
  9. enum ParamIds {
  10. XBEND_PARAM,
  11. XBENDCVTRIM_PARAM,
  12. XBENDRANGE_PARAM,
  13. BEND_PARAM,
  14. BENDCVTRIM_PARAM,
  15. AXISXFADE_PARAM,
  16. AXISSLEW_PARAM,
  17. AXISTRNSUP_PARAM,
  18. AXISTRNSDWN_PARAM,
  19. AXISSHIFTTRIM_PARAM,
  20. AXISSELECT_PARAM = 10,
  21. AXISSELECTCV_PARAM = 18,
  22. SNAPAXIS_PARAM,
  23. YCENTER_PARAM,
  24. YZOOM_PARAM,
  25. AUTOZOOM_PARAM,
  26. NUM_PARAMS
  27. };
  28. enum InputIds {
  29. IN_INPUT,
  30. XBENDCV_INPUT = 8,
  31. XBENDRANGE_INPUT,
  32. BENDCV_INPUT,
  33. AXISSELECT_INPUT,
  34. AXISEXT_INPUT,
  35. AXISXFADE_INPUT,
  36. AXISSHIFT_INPUT,
  37. AXISSLEW_INPUT,
  38. NUM_INPUTS
  39. };
  40. enum OutputIds {
  41. OUT_OUTPUT,
  42. AXIS_OUTPUT = 8,
  43. NUM_OUTPUTS
  44. };
  45. enum LightIds {
  46. AXIS_LIGHT,
  47. AUTOZOOM_LIGHT = 8,
  48. SNAPAXIS_LIGHT,
  49. NUM_LIGHTS
  50. };
  51. float inaxis = 0.f;
  52. float slewaxis = 0.f;
  53. int axisTransParam = 0;
  54. float finalAxis = 0.f;
  55. float AxisShift = 0.f;
  56. float axisxfade;
  57. float selectedAxisF = 0.f;
  58. int selectedAxisI = 0;
  59. float dZoom = 1.f;
  60. float dCenter = 0.5f;
  61. int frameAutoZoom = 0;
  62. float slewchanged = 0.f;
  63. SchmittTrigger axisTransUpTrigger;
  64. SchmittTrigger axisTransDwnTrigger;
  65. SchmittTrigger axisSelectTrigger[8];
  66. struct ioXBended {
  67. float inx = 0.0f;
  68. float xout = 0.0f;
  69. bool iactive = false;
  70. };
  71. ioXBended ioxbended[8];
  72. SlewLimiter slewlimiter;
  73. XBender() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  74. void step() override;
  75. void onReset() override {
  76. for (int ix = 0; ix < 8 ; ix++){
  77. outputs[OUT_OUTPUT + ix].value = inputs[IN_INPUT + ix].value;
  78. }
  79. }
  80. json_t *toJson() override {
  81. json_t *rootJ = json_object();
  82. json_object_set_new(rootJ, "selectedAxisI", json_integer(selectedAxisI));
  83. json_object_set_new(rootJ, "axisTransParam", json_integer(axisTransParam));
  84. return rootJ;
  85. }
  86. void fromJson(json_t *rootJ) override {
  87. json_t *selectedAxisIJ = json_object_get(rootJ,("selectedAxisI"));
  88. selectedAxisI = json_integer_value(selectedAxisIJ);
  89. json_t *axisTransParamJ = json_object_get(rootJ,("axisTransParam"));
  90. axisTransParam = json_integer_value(axisTransParamJ);
  91. }
  92. };
  93. ///////////////////////////////////////////
  94. ///////////////STEP //////////////////
  95. /////////////////////////////////////////////
  96. void XBender::step() {
  97. if(inputs[AXISSELECT_INPUT].active) {
  98. if (params[SNAPAXIS_PARAM].value > 0.5f){
  99. selectedAxisI = (clamp(static_cast<int>(inputs[AXISSELECT_INPUT].value * 0.7), 0, 7));
  100. selectedAxisF = static_cast<float>(selectedAxisI);
  101. inaxis = inputs[selectedAxisI].value;
  102. } else {
  103. selectedAxisF = clamp(inputs[AXISSELECT_INPUT].value * 0.7, 0.f, 7.f);
  104. selectedAxisI = static_cast<int>(selectedAxisF);
  105. float ax_float = selectedAxisF - static_cast<float>(selectedAxisI);
  106. inaxis = (inputs[selectedAxisI].value * (1.f - ax_float) + (inputs[selectedAxisI + 1].value * ax_float));
  107. }
  108. }else{
  109. inaxis = inputs[selectedAxisI].value;
  110. }
  111. lights[SNAPAXIS_LIGHT].value = (params[SNAPAXIS_PARAM].value > 0.5f)? 1.f : 0.f;
  112. axisxfade = clamp((params[AXISXFADE_PARAM].value + inputs[AXISXFADE_INPUT].value/ 10.f), 0.f, 1.f);
  113. if (inputs[AXISEXT_INPUT].active){
  114. float axisext = inputs[AXISEXT_INPUT].value;
  115. slewaxis = crossfade(axisext, inaxis, axisxfade);
  116. }else slewaxis = inaxis;
  117. float slewsum = clamp((params[AXISSLEW_PARAM].value + inputs[AXISSLEW_INPUT].value * .1f), 0.f , 1.f);
  118. if (slewchanged != slewsum) {
  119. float slewfloat = 1.0f/(5.0f + slewsum * engineGetSampleRate());
  120. slewlimiter.setRiseFall(slewfloat,slewfloat);
  121. }
  122. finalAxis = slewlimiter.process(slewaxis) + (inputs[AXISSHIFT_INPUT].value * params[AXISSHIFTTRIM_PARAM].value);
  123. AxisShift = (static_cast<float>(axisTransParam)/12.f);
  124. finalAxis += clamp(AxisShift, -12.f,12.f);
  125. float range = clamp((params[XBENDRANGE_PARAM].value + inputs[XBENDRANGE_INPUT].value/2.f), 1.f,5.f);
  126. float xbend = clamp((params[XBEND_PARAM].value + (inputs[XBENDCV_INPUT].value /5.f) * (params[XBENDCVTRIM_PARAM].value /24.f)),-1.f, 1.f);
  127. float bend = clamp((params[BEND_PARAM].value + (inputs[BENDCV_INPUT].value /5.f) * (params[BENDCVTRIM_PARAM].value /60.f)),-1.f, 1.f);
  128. for (int i = 0; i < 8; i++){
  129. if (inputs[IN_INPUT + i].active) {
  130. if (axisSelectTrigger[i].process(params[AXISSELECT_PARAM + i].value)) {
  131. selectedAxisI = i;
  132. selectedAxisF = static_cast<float>(i); // float for display
  133. }
  134. ioxbended[i].iactive= true;
  135. lights[AXIS_LIGHT + i].value = (selectedAxisI == i)? 1.f : 0.01f;
  136. ioxbended[i].inx = inputs[IN_INPUT + i].value;
  137. float diff = (finalAxis - ioxbended[i].inx) * xbend * range;
  138. ioxbended[i].xout = clamp((ioxbended[i].inx + diff + bend * 6.f),-12.f,12.f);
  139. outputs[OUT_OUTPUT + i].value = ioxbended[i].xout;
  140. }else{
  141. lights[AXIS_LIGHT + i].value = 0;
  142. ioxbended[i].iactive=false;
  143. }
  144. } //for loop ix
  145. outputs[AXIS_OUTPUT].value = finalAxis;
  146. if (axisTransUpTrigger.process(params[AXISTRNSUP_PARAM].value))
  147. if (axisTransParam < 48) axisTransParam ++;
  148. if (axisTransDwnTrigger.process(params[AXISTRNSDWN_PARAM].value))
  149. if (axisTransParam > -48) axisTransParam --;
  150. bool autoZoom = (params[AUTOZOOM_PARAM].value > 0.f);
  151. if (autoZoom){
  152. frameAutoZoom ++;
  153. if (frameAutoZoom > 128) {
  154. frameAutoZoom = 0;
  155. float autoZoomMin = 12.f , autoZoomMax = -12.f;
  156. int active = 0;
  157. for (int i = 0; i < 8; i++){
  158. if (inputs[IN_INPUT + i].active) {
  159. active ++;
  160. if (ioxbended[i].inx < autoZoomMin)
  161. autoZoomMin = ioxbended[i].inx;
  162. if (ioxbended[i].xout < autoZoomMin)
  163. autoZoomMin = ioxbended[i].xout;
  164. if (ioxbended[i].inx > autoZoomMax)
  165. autoZoomMax = ioxbended[i].inx;
  166. if (ioxbended[i].xout > autoZoomMax)
  167. autoZoomMax = ioxbended[i].xout;
  168. }
  169. }
  170. if (finalAxis < autoZoomMin)
  171. autoZoomMin = finalAxis;
  172. if (finalAxis > autoZoomMax)
  173. autoZoomMax = finalAxis;
  174. float autoZ = 22.f / clamp((autoZoomMax - autoZoomMin),1.f,24.f);
  175. float autoCenter = 10.f * (autoZoomMin + (autoZoomMax - autoZoomMin) / 2.f);
  176. dZoom = clamp(autoZ, 1.f, 15.f);
  177. dCenter = clamp(autoCenter, -120.f, 120.f);
  178. }
  179. lights[AUTOZOOM_LIGHT].value = 10.f;
  180. }
  181. else {
  182. dCenter = params[XBender::YCENTER_PARAM].value;
  183. dZoom = params[XBender::YZOOM_PARAM].value;
  184. lights[AUTOZOOM_LIGHT].value = 0.f;
  185. }
  186. }//closing STEP
  187. ///Displays
  188. struct BenderDisplay : TransparentWidget {
  189. BenderDisplay() {
  190. }
  191. XBender::ioXBended *ioxB;// = new XBender::ioXBended[8];
  192. float *pAxis = NULL;
  193. float *pyCenter ;
  194. float *pyZoom ;
  195. float *pAxisIx;
  196. float *pAxisXfade;
  197. void draw(NVGcontext* vg)
  198. {
  199. const float dispHeight = 228.f;
  200. const float dispCenter = dispHeight / 2.f;
  201. float yZoom = *pyZoom;
  202. float yCenter = *pyCenter * yZoom + dispCenter;
  203. float AxisIx = *pAxisIx;
  204. float keyw = 10.f * yZoom /12.f;
  205. // crop drawing to display
  206. nvgScissor(vg, 0.f, 0.f, 152.f, dispHeight);
  207. nvgBeginPath(vg);
  208. nvgFillColor(vg, nvgRGB(0x2a, 0x2a, 0x2a));
  209. nvgRect(vg, 20.f, yCenter - 120.f * yZoom, 110.f, 20.f * yZoom);
  210. nvgRect(vg, 20.f, yCenter + 100.f * yZoom, 110.f, 20.f * yZoom);
  211. nvgFill(vg);
  212. nvgBeginPath(vg);
  213. if (yZoom > 2.5f) nvgFillColor(vg, nvgRGB(0x2d, 0x2d, 0x2d));
  214. else nvgFillColor(vg, nvgRGB(0x1a, 0x1a, 0x1a));
  215. nvgRect(vg, 20.f, yCenter - 50.f * yZoom, 110.f, 100.f * yZoom );
  216. nvgFill(vg);
  217. for (int i = 0; i < 11; i++){
  218. if (yZoom < 2.5f){
  219. // 1V lines
  220. nvgBeginPath(vg);
  221. nvgStrokeColor(vg, nvgRGB(0x2d,0x2d,0x2d));
  222. nvgMoveTo(vg, 20.f, yCenter - 10.f * yZoom * i);
  223. nvgLineTo(vg, 130.f,yCenter - 10.f * yZoom * i);
  224. nvgMoveTo(vg, 20.f, yCenter + 10.f * yZoom * i);
  225. nvgLineTo(vg, 130.f,yCenter + 10.f * yZoom * i);
  226. nvgStroke(vg);
  227. }else if (i < 5){
  228. // keyboard
  229. float keyPos = yCenter + 10.f * yZoom * i;
  230. // C's highlight
  231. nvgBeginPath(vg);
  232. nvgFillColor(vg, nvgRGB(0x44, 0x44, 0x44));
  233. nvgRect(vg, 20.f, yCenter - 10.f * yZoom * i - keyw * 0.5f, 110.f, keyw);
  234. nvgFill(vg);
  235. /// > center
  236. nvgBeginPath(vg);
  237. nvgFillColor(vg, nvgRGB(0x0, 0x0, 0x0));
  238. nvgRect(vg, 20.f, keyPos + keyw * 1.5f, 110.f, keyw);
  239. nvgFill(vg);
  240. nvgBeginPath(vg);
  241. nvgRect(vg, 20.f, keyPos + keyw * 3.5f , 110.f, keyw);
  242. nvgFill(vg);
  243. nvgBeginPath(vg);
  244. nvgRect(vg, 20.f, keyPos + keyw * 5.5f, 110.f, keyw);
  245. nvgFill(vg);
  246. nvgBeginPath(vg);
  247. nvgRect(vg, 20.f, keyPos + keyw * 8.5f, 110.f, keyw);
  248. nvgFill(vg);
  249. nvgBeginPath(vg);
  250. nvgRect(vg, 20.f, keyPos + keyw * 10.5f, 110.f, keyw);
  251. nvgFill(vg);
  252. /// C's highlight
  253. nvgBeginPath(vg);
  254. nvgFillColor(vg, nvgRGB(0x44, 0x44, 0x44));
  255. nvgRect(vg, 20.f, yCenter + 10.f * yZoom * i - keyw * 0.5f, 110.f, keyw);
  256. nvgFill(vg);
  257. /// < center
  258. keyPos = yCenter - 10.f * yZoom * i;
  259. nvgBeginPath(vg);
  260. nvgFillColor(vg, nvgRGB(0x0, 0x0, 0x0));
  261. nvgRect(vg, 20.f, keyPos - keyw * 1.5f, 110.f, keyw);
  262. nvgFill(vg);
  263. nvgBeginPath(vg);
  264. nvgRect(vg, 20.f, keyPos - keyw * 3.5f , 110.f, keyw);
  265. nvgFill(vg);
  266. nvgBeginPath(vg);
  267. nvgRect(vg, 20.f, keyPos - keyw * 6.5f, 110.f, keyw);
  268. nvgFill(vg);
  269. nvgBeginPath(vg);
  270. nvgRect(vg, 20.f, keyPos - keyw * 8.5f, 110.f, keyw);
  271. nvgFill(vg);
  272. nvgBeginPath(vg);
  273. nvgRect(vg, 20.f, keyPos - keyw * 10.5f, 110.f, keyw);
  274. nvgFill(vg);
  275. }
  276. }
  277. // center 0v...
  278. nvgBeginPath(vg);
  279. if (yZoom < 2.5f){
  280. nvgStrokeColor(vg,nvgRGBA(0x80, 0x00, 0x00 ,0x77));
  281. nvgStrokeWidth(vg,1.f);
  282. nvgMoveTo(vg, 20.f, yCenter);
  283. nvgLineTo(vg, 130.f, yCenter);
  284. nvgStroke(vg);
  285. }//... center C
  286. else {
  287. nvgFillColor(vg, nvgRGBA(0x80, 0x00, 0x00 ,0x77));
  288. nvgRect(vg, 20.f, yCenter - keyw * 0.5f, 110.f, keyw);
  289. nvgFill(vg);
  290. }
  291. float Axis = *pAxis;
  292. ///// Bend Lines
  293. const float yfirst = 10.5f;
  294. const float ystep = 26.f;
  295. for (int i = 0; i < 8 ; i++){
  296. //nowactive =;
  297. if (ioxB[i].iactive){
  298. float yport = yfirst + i * ystep;
  299. float yi = yZoom * ioxB[i].inx * -10.f + yCenter ;
  300. float yo = yZoom * ioxB[i].xout * -10.f + yCenter ;
  301. nvgBeginPath(vg);
  302. nvgStrokeWidth(vg,1.f);
  303. nvgStrokeColor(vg,nvgRGBA(0xff, 0xff, 0xff,0x80));
  304. nvgMoveTo(vg, 0.f, yport);
  305. nvgLineTo(vg, 20.f, yi);
  306. nvgLineTo(vg, 130.f, yo);
  307. nvgLineTo(vg, 150.f, yport);
  308. nvgStroke(vg);
  309. if (yZoom > 2.5f){
  310. nvgBeginPath(vg);
  311. nvgFillColor(vg, nvgRGBA(0xff, 0xff, 0xff,0x60));
  312. nvgRoundedRect(vg, 20.f, yi - keyw * 0.5f, 10.f, keyw, 2.f);
  313. nvgFill(vg);
  314. nvgBeginPath(vg);
  315. nvgRoundedRect(vg, 120.f, yo - keyw * 0.5f, 10.f, keyw, 2.f);
  316. nvgFill(vg);
  317. }
  318. }
  319. }
  320. /// Axis Line
  321. NVGcolor extColor = nvgRGBA(0xee, 0xee, 0x00, (1.f - *pAxisXfade) * 0xff);
  322. NVGcolor intColor = nvgRGBA(0xee, 0x00, 0x00, *pAxisXfade * 0xff);
  323. NVGcolor axisColor = nvgRGB(0xee, (1.f - *pAxisXfade) * 0xee, 0x00);
  324. Axis = yZoom * Axis * -10.f + yCenter;
  325. nvgStrokeWidth(vg,1.f);
  326. //ext
  327. nvgBeginPath(vg);
  328. nvgStrokeColor(vg,extColor);
  329. nvgMoveTo(vg, 0.f, 228.f);
  330. nvgLineTo(vg, 20.f, Axis);
  331. nvgStroke(vg);
  332. // int
  333. nvgBeginPath(vg);
  334. nvgStrokeColor(vg,intColor);
  335. nvgMoveTo(vg, 0.f, yfirst + AxisIx * ystep);
  336. nvgLineTo(vg, 20.f, Axis);
  337. nvgStroke(vg);
  338. // axis
  339. nvgBeginPath(vg);
  340. nvgStrokeColor(vg,axisColor);
  341. nvgMoveTo(vg, 20.f, Axis);
  342. nvgLineTo(vg, 130.f, Axis);
  343. nvgLineTo(vg, 150.f, 222.f);
  344. nvgStroke(vg);
  345. }
  346. };
  347. struct AxisDisplay : TransparentWidget {
  348. AxisDisplay() {
  349. font = Font::load(FONT_FILE);
  350. }
  351. float mdfontSize = 11.f;
  352. std::string s;
  353. std::shared_ptr<Font> font;
  354. int *pAxisTransP = 0;
  355. int frame = 0 ;
  356. void draw(NVGcontext* vg)
  357. {
  358. if (frame ++ > 8 )
  359. {
  360. s = std::to_string(*pAxisTransP);
  361. frame = 0;
  362. }
  363. NVGcolor backgroundColor = nvgRGB(0x22, 0x22, 0x22);
  364. nvgBeginPath(vg);
  365. nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 3.0f);
  366. nvgFillColor(vg, backgroundColor);
  367. nvgFill(vg);
  368. nvgFillColor(vg, nvgRGB(0xff,0xff,0xff));
  369. nvgFontSize(vg, mdfontSize);
  370. nvgFontFaceId(vg, font->handle);
  371. nvgTextAlign(vg, NVG_ALIGN_CENTER);
  372. nvgTextLetterSpacing(vg, 0.0f);
  373. nvgTextBox(vg, 0.f, 14.0f,box.size.x, s.c_str(), NULL);
  374. }
  375. };
  376. struct RangeSelector: moDllzSmSelector{
  377. RangeSelector(){
  378. minAngle = -0.4*M_PI;
  379. maxAngle = 0.4*M_PI;
  380. }
  381. };
  382. struct xbendKnob : SVGKnob {
  383. xbendKnob() {
  384. minAngle = -0.83*M_PI;
  385. maxAngle = 0.83*M_PI;
  386. setSVG(SVG::load(assetPlugin(plugin, "res/xbendKnob.svg")));
  387. shadow->opacity = 0.f;
  388. }
  389. };
  390. struct zTTrim : SVGKnob {
  391. zTTrim() {
  392. minAngle = 0;
  393. maxAngle = 1.75*M_PI;
  394. setSVG(SVG::load(assetPlugin(plugin, "res/zTTrim.svg")));
  395. shadow->opacity = 0.f;
  396. }
  397. };
  398. struct cTTrim : SVGKnob {
  399. cTTrim() {
  400. minAngle = -0.83*M_PI;
  401. maxAngle = 0.83*M_PI;
  402. snap = true;
  403. setSVG(SVG::load(assetPlugin(plugin, "res/cTTrim.svg")));
  404. shadow->opacity = 0.f;
  405. }
  406. };
  407. struct autoZoom : SVGSwitch, ToggleSwitch {
  408. autoZoom() {
  409. addFrame(SVG::load(assetPlugin(plugin, "res/autoButton.svg")));
  410. addFrame(SVG::load(assetPlugin(plugin, "res/autoButton.svg")));
  411. }
  412. };
  413. struct snapAxisButton : SVGSwitch, ToggleSwitch {
  414. snapAxisButton() {
  415. addFrame(SVG::load(assetPlugin(plugin, "res/snapButton.svg")));
  416. addFrame(SVG::load(assetPlugin(plugin, "res/snapButton.svg")));
  417. }
  418. };
  419. struct XBenderWidget : ModuleWidget {
  420. XBenderWidget(XBender *module): ModuleWidget(module){
  421. setPanel(SVG::load(assetPlugin(plugin, "res/XBender.svg")));
  422. float xPos;
  423. float yPos;
  424. float xyStep = 26.f ;
  425. //Screws
  426. addChild(Widget::create<ScrewBlack>(Vec(0, 0)));
  427. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 15, 0)));
  428. addChild(Widget::create<ScrewBlack>(Vec(0, 365)));
  429. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 15, 365)));
  430. xPos = 73.f;
  431. yPos = 22.f;
  432. {
  433. BenderDisplay *benderDisplay = new BenderDisplay();
  434. benderDisplay->box.pos = Vec(xPos, yPos);
  435. benderDisplay->box.size = {152.f, 228.f};
  436. benderDisplay->ioxB = &(module->ioxbended[0]);
  437. benderDisplay->pAxis = &(module->finalAxis);
  438. benderDisplay->pAxisIx = &(module->selectedAxisF);
  439. benderDisplay->pyCenter = &(module->dCenter);
  440. benderDisplay->pyZoom = &(module->dZoom);
  441. benderDisplay->pAxisXfade = &(module->axisxfade);
  442. addChild(benderDisplay);
  443. }
  444. xPos = 170.f;
  445. yPos = 252.f;
  446. /// View Center Zoom
  447. addParam(ParamWidget::create<cTTrim>(Vec(xPos,yPos), module, XBender::YCENTER_PARAM, -120.f, 120.f, 0.f));
  448. xPos = 203;
  449. addParam(ParamWidget::create<zTTrim>(Vec(xPos,yPos), module, XBender::YZOOM_PARAM, 1.f, 15.f, 1.f));
  450. yPos += 1.5f;
  451. xPos = 125.f;
  452. addParam(ParamWidget::create<autoZoom>(Vec(xPos, yPos ), module, XBender::AUTOZOOM_PARAM, 0.0f, 1.0f, 1.0f));
  453. addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(xPos + 17.f, yPos + 4.f), module, XBender::AUTOZOOM_LIGHT));
  454. /// IN - Axis select - OUTS
  455. xPos = 12.f;
  456. yPos = 22.f;
  457. for (int i = 0; i < 8; i++){
  458. // IN leds OUT
  459. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, XBender::IN_INPUT + i));
  460. addParam(ParamWidget::create<moDllzRoundButton>(Vec(xPos + 37.f, yPos + 5.f), module, XBender::AXISSELECT_PARAM + i, 0.0f, 1.0f, 0.0f));
  461. addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(xPos + 42.5f, yPos + 10.5f), module, XBender::AXIS_LIGHT + i));
  462. addOutput(Port::create<moDllzPort>(Vec(234.8f, yPos), Port::OUTPUT, module, XBender::OUT_OUTPUT + i));
  463. yPos += xyStep;
  464. }
  465. yPos = 248.f;
  466. //// AXIS out >>>> on the Right
  467. addOutput(Port::create<moDllzPort>(Vec(234.8f, yPos), Port::OUTPUT, module, XBender::AXIS_OUTPUT));
  468. yPos = 249.f;
  469. /// AXIS select in
  470. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, XBender::AXISSELECT_INPUT));
  471. addParam(ParamWidget::create<snapAxisButton>(Vec(xPos + 22.5f, yPos + 2.f ), module, XBender::SNAPAXIS_PARAM, 0.0f, 1.0f, 0.0f));
  472. addChild(ModuleLightWidget::create<TinyLight<RedLight>>(Vec(xPos + 40.f, yPos + 4.f), module, XBender::SNAPAXIS_LIGHT));
  473. /// AXIS EXT - XFADE
  474. yPos += 25.f;
  475. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, XBender::AXISXFADE_INPUT));
  476. addParam(ParamWidget::create<moDllzKnob26>(Vec(36.f,280.f), module, XBender::AXISXFADE_PARAM, 0.f, 1.f, 1.f));
  477. yPos += 25.f;
  478. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, XBender::AXISEXT_INPUT));
  479. /// AXIS Slew
  480. yPos += 25.f;
  481. addInput(Port::create<moDllzPort>(Vec(xPos, yPos), Port::INPUT, module, XBender::AXISSLEW_INPUT));
  482. addParam(ParamWidget::create<moDllzKnob26>(Vec(34.f, 324.f), module, XBender::AXISSLEW_PARAM, 0.f, 1.f, 0.f));
  483. //AXIS Mod Shift
  484. addInput(Port::create<moDllzPort>(Vec(xPos + 53.f,yPos), Port::INPUT, module, XBender::AXISSHIFT_INPUT));
  485. addParam(ParamWidget::create<moDllzKnob26>(Vec(87.f, 324.f), module, XBender::AXISSHIFTTRIM_PARAM, 0.0f, 1.0f, 0.f));
  486. //AXIS Transp
  487. xPos = 73.5f;
  488. yPos = 278.5f;
  489. addParam(ParamWidget::create<moDllzPulseUp>(Vec(xPos + 31.f,yPos - 1.f), module, XBender::AXISTRNSUP_PARAM, 0.0f, 1.0f, 0.0f));
  490. addParam(ParamWidget::create<moDllzPulseDwn>(Vec(xPos + 31.f ,yPos + 10.f), module, XBender::AXISTRNSDWN_PARAM, 0.0f, 1.0f, 0.0f));
  491. {
  492. AxisDisplay *axisDisplay = new AxisDisplay();
  493. axisDisplay->box.pos = Vec(xPos, yPos);
  494. axisDisplay->box.size = {30.f, 20};
  495. axisDisplay->pAxisTransP = &(module->axisTransParam);
  496. addChild(axisDisplay);
  497. }
  498. /// Knobs
  499. //XBEND
  500. xPos = 124.f;
  501. yPos = 272.f;
  502. addParam(ParamWidget::create<xbendKnob>(Vec(xPos, yPos), module, XBender::XBEND_PARAM, -1.f, 1.f, 0.f));
  503. xPos = 127.5f;
  504. yPos = 328.f;
  505. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, XBender::XBENDCV_INPUT));
  506. addParam(ParamWidget::create<TTrimSnap>(Vec(xPos + 26.5f,yPos + 7.f), module, XBender::XBENDCVTRIM_PARAM, 0.f, 24.f, 24.f));
  507. //XBEND RANGE
  508. xPos = 181.f;
  509. yPos = 288.f;
  510. addParam(ParamWidget::create<RangeSelector>(Vec(xPos, yPos), module, XBender::XBENDRANGE_PARAM, 1.f, 5.f, 1.f));
  511. xPos = 187.5f;
  512. yPos = 328.f;
  513. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, XBender::XBENDRANGE_INPUT));
  514. //BEND
  515. xPos = 219.f;
  516. yPos = 288.f;
  517. addParam(ParamWidget::create<moDllzKnobM>(Vec(xPos, yPos), module, XBender::BEND_PARAM, -1.f, 1.f, 0.f));
  518. xPos = 218.5f;
  519. yPos = 328.f;
  520. addInput(Port::create<moDllzPort>(Vec(xPos,yPos), Port::INPUT, module, XBender::BENDCV_INPUT));
  521. addParam(ParamWidget::create<TTrimSnap>(Vec(xPos + 26.5f,yPos + 7.f), module, XBender::BENDCVTRIM_PARAM, 0.f, 60.f, 12.f));
  522. }
  523. };
  524. // Specify the Module and ModuleWidget subclass, human-readable
  525. // manufacturer name for categorization, module slug (should never
  526. // change), human-readable module name, and any number of tags
  527. // (found in `include/tags.hpp`) separated by commas.
  528. } // namespace rack_plugin_moDllz
  529. using namespace rack_plugin_moDllz;
  530. RACK_PLUGIN_MODEL_INIT(moDllz, XBender) {
  531. Model *modelXBender = Model::create<XBender, XBenderWidget>("moDllz", "XBender", "Poly X Bender",MULTIPLE_TAG ,EFFECT_TAG);
  532. return modelXBender;
  533. }