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.

485 lines
19KB

  1. #include "Bidoo.hpp"
  2. #include "BidooComponents.hpp"
  3. #include "dsp/digital.hpp"
  4. using namespace std;
  5. namespace rack_plugin_Bidoo {
  6. struct MU : Module {
  7. enum ParamIds {
  8. BPM_PARAM,
  9. BPMFINE_PARAM,
  10. STEPLENGTH_PARAM,
  11. STEPLENGTHFINE_PARAM,
  12. NOTELENGTH_PARAM,
  13. STEPPROBA_PARAM,
  14. ALTEOSTEPPROBA_PARAM,
  15. NUMTRIGS_PARAM,
  16. DISTTRIGS_PARAM,
  17. CV_PARAM,
  18. START_PARAM,
  19. CVSTACK_PARAM,
  20. TRIGSTACK_PARAM,
  21. MUTE_PARAM,
  22. OFFSET_PARAM,
  23. NUM_PARAMS
  24. };
  25. enum InputIds {
  26. ACTIVATE_INPUT,
  27. INHIBIT_INPUT,
  28. GATEBRIDGE_INPUT,
  29. CVBRIDGE_INPUT,
  30. BPM_INPUT,
  31. NOTELENGTH_INPUT,
  32. CV_INPUT,
  33. NUMTRIGS_INPUT,
  34. DISTTRIGS_INPUT,
  35. OFFSET_INPUT,
  36. NUM_INPUTS
  37. };
  38. enum OutputIds {
  39. EOSTEP_OUTPUT,
  40. ALTEOSTEP_OUTPUT,
  41. GATEBRIDGE_OUTPUT,
  42. CVBRIDGE_OUTPUT,
  43. BPM_OUTPUT,
  44. NUM_OUTPUTS
  45. };
  46. enum LightIds {
  47. NORMEOS_LIGHT,
  48. ALTEOS_LIGHT,
  49. CVSTACK_LIGHT,
  50. TRIGSTACK_LIGHT,
  51. START_LIGHT,
  52. MUTE_LIGHT,
  53. GATE_LIGHT,
  54. NUM_LIGHTS = GATE_LIGHT + 3
  55. };
  56. PulseGenerator eosPulse;
  57. SchmittTrigger activateTrigger;
  58. SchmittTrigger inhibateTrigger;
  59. SchmittTrigger cvModeTrigger;
  60. SchmittTrigger trigModeTrigger;
  61. SchmittTrigger muteTrigger;
  62. SchmittTrigger startTrigger;
  63. bool isActive = false;
  64. int ticks = 0;
  65. int initTicks = 0;
  66. int gateTicks = 0;
  67. float bpm = 0.1f;
  68. int numTrigs = 1;
  69. int distRetrig = 0;
  70. bool play = false;
  71. bool alt = false;
  72. int count = 0;
  73. float displayLength = 0.0f;
  74. float displayNoteLength = 0.0f;
  75. float displayStepProba = 0.0f;
  76. float displayAltProba = 0.0f;
  77. float displayNumTrigs = 0.0f;
  78. float displayDistTrigs = 0.0f;
  79. float displayCV = 0.0f;
  80. float displayOffset = 0.0f;
  81. bool cvStack = false;
  82. bool trigStack = false;
  83. bool mute = false;
  84. MU() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  85. }
  86. void step() override;
  87. };
  88. void MU::step() {
  89. const float lightLambda = 0.075f;
  90. bpm = inputs[BPM_INPUT].active ? rescale(clamp(inputs[BPM_INPUT].value,0.0f,10.0f),0.0f,10.0f,1.0f,800.99f) : (round(params[BPM_PARAM].value)+round(100*params[BPMFINE_PARAM].value)/100);
  91. displayLength = round(params[STEPLENGTH_PARAM].value) + round(params[STEPLENGTHFINE_PARAM].value*100)/100;
  92. bool wasActive = isActive;
  93. if (startTrigger.process(params[START_PARAM].value))
  94. {
  95. lights[START_LIGHT].value = 10.0f;
  96. isActive = true;
  97. }
  98. if (activateTrigger.process(inputs[ACTIVATE_INPUT].value))
  99. {
  100. isActive = true;
  101. }
  102. if (!wasActive && isActive) {
  103. initTicks = (displayLength/100) * engineGetSampleRate() * 60 / bpm;
  104. ticks = initTicks;
  105. count = 0;
  106. play = (randomUniform() + params[STEPPROBA_PARAM].value)>=1;
  107. alt = (randomUniform() + params[ALTEOSTEPPROBA_PARAM].value)>1;
  108. lights[GATE_LIGHT].value = 0.0f;
  109. lights[GATE_LIGHT+1].value = 0.0f;
  110. lights[GATE_LIGHT+2].value = 10.0f;
  111. }
  112. if (cvModeTrigger.process(params[CVSTACK_PARAM].value))
  113. {
  114. cvStack = !cvStack;
  115. }
  116. if (trigModeTrigger.process(params[TRIGSTACK_PARAM].value))
  117. {
  118. trigStack = !trigStack;
  119. }
  120. if (muteTrigger.process(params[MUTE_PARAM].value))
  121. {
  122. mute = !mute;
  123. }
  124. numTrigs = clamp(params[NUMTRIGS_PARAM].value + rescale(clamp(inputs[NUMTRIGS_INPUT].value,-10.0f,10.0f),-10.0f,10.0f,-64.0f,64.0f),0.0f,64.0f);
  125. distRetrig = clamp(params[DISTTRIGS_PARAM].value + rescale(clamp(inputs[DISTTRIGS_INPUT].value,-10.0f,10.0f),-10.0f,10.0f,-1.0f,1.0f), 0.0f,1.0f) * initTicks;
  126. gateTicks = initTicks * clamp(params[NOTELENGTH_PARAM].value + rescale(clamp(inputs[NOTELENGTH_INPUT].value,-10.0f,10.0f),-10.0f,10.0f,-1.0f,1.0f),0.0f,1.0f);
  127. displayNoteLength = clamp(params[NOTELENGTH_PARAM].value + rescale(clamp(inputs[NOTELENGTH_INPUT].value,-10.0f,10.0f),-10.0f,10.0f,-1.0f,1.0f),0.0f,1.0f) * 100;
  128. displayStepProba = params[STEPPROBA_PARAM].value * 100;
  129. displayAltProba = params[ALTEOSTEPPROBA_PARAM].value * 100;
  130. displayDistTrigs = params[DISTTRIGS_PARAM].value * 100;
  131. displayNumTrigs = numTrigs;
  132. displayOffset = clamp(params[OFFSET_PARAM].value + rescale(clamp(inputs[OFFSET_INPUT].value, 0.0f,10.0f), 0.0f, 10.0f, 0.0f,1.0f), 0.0f, 1.0f) * 100;
  133. if (inhibateTrigger.process(inputs[INHIBIT_INPUT].value))
  134. {
  135. isActive = false;
  136. }
  137. if (isActive && (ticks >= 0)) {
  138. if (ticks <= 0) {
  139. isActive = false;
  140. eosPulse.trigger(10 / engineGetSampleRate());
  141. outputs[GATEBRIDGE_OUTPUT].value = 0.0f;
  142. outputs[CVBRIDGE_OUTPUT].value = 0.0f;
  143. }
  144. else {
  145. int offset = displayOffset * initTicks / 100;
  146. int mult = ((distRetrig > 0) && (count>offset)) ? ((count-offset) / distRetrig) : 0;
  147. if (play && (mult < numTrigs) && (count >= (offset + mult * distRetrig)) && (count <= (offset + (mult * distRetrig) + gateTicks))) {
  148. outputs[GATEBRIDGE_OUTPUT].value = mute ? 0.0f : 10.0f;
  149. lights[GATE_LIGHT].value = mute ? 0.0f : 10.0f;
  150. lights[GATE_LIGHT+1].value = 0.0f;
  151. lights[GATE_LIGHT+2].value = !mute ? 0.0f : 10.0f;
  152. }
  153. else {
  154. outputs[GATEBRIDGE_OUTPUT].value = (trigStack && !mute && (inputs[GATEBRIDGE_INPUT].value > 0.0f)) ? clamp(inputs[GATEBRIDGE_INPUT].value,0.0f,10.0f) : 0.0f;
  155. lights[GATE_LIGHT].value = 0.0f;
  156. lights[GATE_LIGHT+1].value = 0.0f;
  157. lights[GATE_LIGHT+2].value = 10.0f;
  158. }
  159. outputs[CVBRIDGE_OUTPUT].value = clamp(params[CV_PARAM].value + clamp(inputs[CV_INPUT].value,-10.0f,10.0f) + (cvStack ? inputs[CVBRIDGE_INPUT].value : 0.0f),0.0f,10.0f);
  160. }
  161. ticks--;
  162. count++;
  163. }
  164. else {
  165. outputs[GATEBRIDGE_OUTPUT].value = clamp(inputs[GATEBRIDGE_INPUT].value,0.0f,10.0f);
  166. outputs[CVBRIDGE_OUTPUT].value = inputs[CVBRIDGE_INPUT].value;
  167. }
  168. bool pulse = eosPulse.process(1 / engineGetSampleRate());
  169. outputs[EOSTEP_OUTPUT].value = !alt ? (pulse ? 10.0f : 0.0f) : 0.0f;
  170. outputs[ALTEOSTEP_OUTPUT].value = alt ? (pulse ? 10.0f : 0.0f) : 0.0f;
  171. outputs[BPM_OUTPUT].value = rescale(bpm,1.0f,800.99f,0.0f,10.0f);
  172. lights[NORMEOS_LIGHT].value = (!alt && pulse) ? 10.0f : (lights[NORMEOS_LIGHT].value - lights[NORMEOS_LIGHT].value / lightLambda / engineGetSampleRate());
  173. lights[ALTEOS_LIGHT].value = (alt && pulse) ? 10.0f : (lights[ALTEOS_LIGHT].value - lights[ALTEOS_LIGHT].value / lightLambda / engineGetSampleRate());
  174. lights[START_LIGHT].value = lights[START_LIGHT].value - lights[START_LIGHT].value / lightLambda / engineGetSampleRate();
  175. if (outputs[GATEBRIDGE_OUTPUT].value == 0.0f) lights[GATE_LIGHT].value -= 4 * lights[GATE_LIGHT].value / lightLambda / engineGetSampleRate();
  176. if (!isActive) lights[GATE_LIGHT+2].value -= 4 * lights[GATE_LIGHT+2].value / lightLambda / engineGetSampleRate();
  177. if (!isActive) lights[GATE_LIGHT].value -= 4 * lights[GATE_LIGHT].value / lightLambda / engineGetSampleRate();
  178. lights[MUTE_LIGHT].value = mute ? 10.0f : 0.0f;
  179. lights[CVSTACK_LIGHT].value = cvStack ? 10.0f : 0.0f;
  180. lights[TRIGSTACK_LIGHT].value = trigStack ? 10.0f : 0.0f;
  181. }
  182. struct LabelMICROWidget : TransparentWidget {
  183. float *value = NULL;
  184. const char *format = NULL;
  185. const char *header = "Have fun !!!";
  186. std::shared_ptr<Font> font;
  187. LabelMICROWidget() {
  188. font = Font::load(assetPlugin(plugin, "res/DejaVuSansMono.ttf"));
  189. };
  190. void draw(NVGcontext *vg) override
  191. {
  192. nvgFontFaceId(vg, font->handle);
  193. nvgTextLetterSpacing(vg, -2.0f);
  194. nvgFillColor(vg, YELLOW_BIDOO);
  195. nvgTextAlign(vg, NVG_ALIGN_LEFT);
  196. if (header) {
  197. nvgFontSize(vg, 12.0f);
  198. nvgText(vg, 0.0f, 0.0f, header, NULL);
  199. }
  200. if (value && format) {
  201. char display[128];
  202. snprintf(display, sizeof(display), format, *value);
  203. nvgFontSize(vg, 16.0f);
  204. nvgText(vg, 0.0f, 15.0f, display, NULL);
  205. }
  206. }
  207. };
  208. struct BidooBlueTrimpotWithDisplay : BidooBlueTrimpot {
  209. LabelMICROWidget *lblDisplay = NULL;
  210. float *valueForDisplay = NULL;
  211. const char *format = NULL;
  212. const char *header = NULL;
  213. void onMouseEnter(EventMouseEnter &e) override {
  214. if (lblDisplay && valueForDisplay && format) {
  215. lblDisplay->value = valueForDisplay;
  216. lblDisplay->format = format;
  217. }
  218. if (lblDisplay && header) lblDisplay->header = header;
  219. BidooBlueTrimpot::onMouseEnter(e);
  220. }
  221. };
  222. struct TinyPJ301MPortWithDisplay : TinyPJ301MPort {
  223. LabelMICROWidget *lblDisplay = NULL;
  224. float *valueForDisplay = NULL;
  225. const char *format = NULL;
  226. const char *header = NULL;
  227. void onMouseEnter(EventMouseEnter &e) override {
  228. if (lblDisplay && valueForDisplay && format) {
  229. lblDisplay->value = valueForDisplay;
  230. lblDisplay->format = format;
  231. }
  232. if (lblDisplay && header) lblDisplay->header = header;
  233. TinyPJ301MPort::onMouseEnter(e);
  234. }
  235. };
  236. struct MUWidget : ModuleWidget {
  237. MUWidget(MU *module) : ModuleWidget(module) {
  238. setPanel(SVG::load(assetPlugin(plugin, "res/MU.svg")));
  239. LabelMICROWidget *display = new LabelMICROWidget();
  240. display->box.pos = Vec(4,37);
  241. addChild(display);
  242. addChild(ModuleLightWidget::create<SmallLight<RedGreenBlueLight>>(Vec(40, 15), module, MU::GATE_LIGHT));
  243. addParam(ParamWidget::create<LEDButton>(Vec(5, 5), module, MU::START_PARAM, 0.0f, 10.0f, 0.0f));
  244. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(11, 11), module, MU::START_LIGHT));
  245. addParam(ParamWidget::create<LEDButton>(Vec(52, 5), module, MU::MUTE_PARAM, 0.0f, 10.0f, 0.0f));
  246. addChild(ModuleLightWidget::create<SmallLight<RedLight>>(Vec(58, 11), module, MU::MUTE_LIGHT));
  247. static const float portX0[2] = {14.0f, 41.0f};
  248. static const float portY0[5] = {60.0f, 83.0f, 106.0f, 145.0f, 166.0f};
  249. static const float portX1[2] = {15.0f, 45.0f};
  250. static const float portY1[8] = {191.0f, 215.0f, 239.0f, 263.0f, 287.0f, 311.0f, 335.0f, 359.0f};
  251. BidooBlueTrimpotWithDisplay* bpm = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[0], portY0[0]), module, MU::BPM_PARAM, 1.0f, 800.0f, 117.0f);
  252. bpm->lblDisplay = display;
  253. bpm->valueForDisplay = &module->bpm;
  254. bpm->format = "%2.2f";
  255. bpm->header = "BPM";
  256. addParam(bpm);
  257. BidooBlueTrimpotWithDisplay* bpmFine = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[0], portY0[1]), module, MU::BPMFINE_PARAM, 0.0f, 0.99f, 0.0f);
  258. bpmFine->lblDisplay = display;
  259. bpmFine->valueForDisplay = &module->bpm;
  260. bpmFine->format = "%2.2f";
  261. bpmFine->header = "BPM";
  262. addParam(bpmFine);
  263. BidooBlueTrimpotWithDisplay* stepLength = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[1], portY0[0]), module, MU::STEPLENGTH_PARAM, 0.0f, 1600.0f, 100.0f);
  264. stepLength->lblDisplay = display;
  265. stepLength->valueForDisplay = &module->displayLength;
  266. stepLength->format = "%2.2f %%";
  267. stepLength->header = "Step len.";
  268. addParam(stepLength);
  269. BidooBlueTrimpotWithDisplay* stepLengthFine = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[1], portY0[1]), module, MU::STEPLENGTHFINE_PARAM, -0.5f, 0.5f, 0.0f);
  270. stepLengthFine->lblDisplay = display;
  271. stepLengthFine->valueForDisplay = &module->displayLength;
  272. stepLengthFine->format = "%2.2f %%";
  273. stepLengthFine->header = "Step len.";
  274. addParam(stepLengthFine);
  275. BidooBlueTrimpotWithDisplay* noteLength = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[0], portY0[2]), module, MU::NOTELENGTH_PARAM, 0.0f, 1.0f, 1.0f);
  276. noteLength->lblDisplay = display;
  277. noteLength->valueForDisplay = &module->displayNoteLength;
  278. noteLength->format = "%2.2f %%";
  279. noteLength->header = "Trigs len.";
  280. addParam(noteLength);
  281. BidooBlueTrimpotWithDisplay* offset = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[1], portY0[2]), module, MU::OFFSET_PARAM, 0.0f, 1.0f, 0.0f);
  282. offset->lblDisplay = display;
  283. offset->valueForDisplay = &module->displayOffset;
  284. offset->format = "%2.2f %%";
  285. offset->header = "Trigs offset";
  286. addParam(offset);
  287. BidooBlueTrimpotWithDisplay* cv = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[0]+14, portY0[2]+19), module, MU::CV_PARAM, 0.0f, 10.0f, 0.0f);
  288. cv->lblDisplay = display;
  289. cv->valueForDisplay = &module->params[MU::CV_PARAM].value;
  290. cv->format = "%2.2f V";
  291. cv->header = "CV";
  292. addParam(cv);
  293. BidooBlueTrimpotWithDisplay* stepProb = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[0], portY0[3]), module, MU::STEPPROBA_PARAM, 0.0f, 1.0f, 1.0f);
  294. stepProb->lblDisplay = display;
  295. stepProb->valueForDisplay = &module->displayStepProba;
  296. stepProb->format = "%2.2f %%";
  297. stepProb->header = "Step prob.";
  298. addParam(stepProb);
  299. BidooBlueTrimpotWithDisplay* altOutProb = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[1], portY0[3]), module, MU::ALTEOSTEPPROBA_PARAM, 0.0f, 1.0f, 0.0f);
  300. altOutProb->lblDisplay = display;
  301. altOutProb->valueForDisplay = &module->displayAltProba;
  302. altOutProb->format = "%2.2f %%";
  303. altOutProb->header = "Alt out prob.";
  304. addParam(altOutProb);
  305. BidooBlueTrimpotWithDisplay* numTrig = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[0], portY0[4]), module, MU::NUMTRIGS_PARAM, 1.0f, 64.0f, 1.0f);
  306. numTrig->lblDisplay = display;
  307. numTrig->valueForDisplay = &module->displayNumTrigs;
  308. numTrig->format = "%2.0f";
  309. numTrig->header = "Trigs count";
  310. addParam(numTrig);
  311. BidooBlueTrimpotWithDisplay* distTrig = ParamWidget::create<BidooBlueTrimpotWithDisplay>(Vec(portX0[1], portY0[4]), module, MU::DISTTRIGS_PARAM, 0.0f, 1.0f, 1.0f);
  312. distTrig->lblDisplay = display;
  313. distTrig->valueForDisplay = &module->displayDistTrigs;
  314. distTrig->format = "%2.2f %%";
  315. distTrig->header = "Trigs Dist.";
  316. addParam(distTrig);
  317. TinyPJ301MPortWithDisplay* bpmIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[0]), Port::INPUT, module, MU::BPM_INPUT);
  318. bpmIn->lblDisplay = display;
  319. bpmIn->valueForDisplay = &module->inputs[MU::BPM_INPUT].value;
  320. bpmIn->format = "%2.2f V";
  321. bpmIn->header = "BPM";
  322. addInput(bpmIn);
  323. TinyPJ301MPortWithDisplay* bpmOut = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[0]), Port::OUTPUT, module, MU::BPM_OUTPUT);
  324. bpmOut->lblDisplay = display;
  325. bpmOut->valueForDisplay = &module->outputs[MU::BPM_OUTPUT].value;
  326. bpmOut->format = "%2.2f V";
  327. bpmOut->header = "BPM";
  328. addOutput(bpmOut);
  329. TinyPJ301MPortWithDisplay* activateIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[1]), Port::INPUT, module, MU::ACTIVATE_INPUT);
  330. activateIn->lblDisplay = display;
  331. activateIn->valueForDisplay = &module->inputs[MU::ACTIVATE_INPUT].value;
  332. activateIn->format = "%2.2f V";
  333. activateIn->header = "Step start";
  334. addInput(activateIn);
  335. TinyPJ301MPortWithDisplay* activateOUT = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[1]), Port::OUTPUT, module, MU::EOSTEP_OUTPUT);
  336. activateOUT->lblDisplay = display;
  337. activateOUT->valueForDisplay = &module->outputs[MU::BPM_OUTPUT].value;
  338. activateOUT->format = "%2.2f V";
  339. activateOUT->header = "Step end";
  340. addOutput(activateOUT);
  341. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(portX1[1]-11, portY1[1]+5), module, MU::NORMEOS_LIGHT));
  342. TinyPJ301MPortWithDisplay* activateAltOUT = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[2]), Port::OUTPUT, module, MU::ALTEOSTEP_OUTPUT);
  343. activateAltOUT->lblDisplay = display;
  344. activateAltOUT->valueForDisplay = &module->outputs[MU::ALTEOSTEP_OUTPUT].value;
  345. activateAltOUT->format = "%2.2f V";
  346. activateAltOUT->header = "Alt step end";
  347. addOutput(activateAltOUT);
  348. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(portX1[1]-11, portY1[2]+5), module, MU::ALTEOS_LIGHT));
  349. TinyPJ301MPortWithDisplay* inhibitIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[2]), Port::INPUT, module, MU::INHIBIT_INPUT);
  350. inhibitIn->lblDisplay = display;
  351. inhibitIn->valueForDisplay = &module->inputs[MU::INHIBIT_INPUT].value;
  352. inhibitIn->format = "%2.2f V";
  353. inhibitIn->header = "Inhibit step";
  354. addInput(inhibitIn);
  355. TinyPJ301MPortWithDisplay* noteLengthIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[3]), Port::INPUT, module, MU::NOTELENGTH_INPUT);
  356. noteLengthIn->lblDisplay = display;
  357. noteLengthIn->valueForDisplay = &module->inputs[MU::NOTELENGTH_INPUT].value;
  358. noteLengthIn->format = "%2.2f V";
  359. noteLengthIn->header = "Trigs len.";
  360. addInput(noteLengthIn);
  361. TinyPJ301MPortWithDisplay* offsetIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[3]), Port::INPUT, module, MU::OFFSET_INPUT);
  362. offsetIn->lblDisplay = display;
  363. offsetIn->valueForDisplay = &module->inputs[MU::OFFSET_INPUT].value;
  364. offsetIn->format = "%2.2f V";
  365. offsetIn->header = "Offset mod";
  366. addInput(offsetIn);
  367. TinyPJ301MPortWithDisplay* cvIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0]+14, portY1[4]), Port::INPUT, module, MU::CV_INPUT);
  368. cvIn->lblDisplay = display;
  369. cvIn->valueForDisplay = &module->inputs[MU::CV_INPUT].value;
  370. cvIn->format = "%2.2f V";
  371. cvIn->header = "CV mod";
  372. addInput(cvIn);
  373. TinyPJ301MPortWithDisplay* numTrigsIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[5]), Port::INPUT, module, MU::NUMTRIGS_INPUT);
  374. numTrigsIn->lblDisplay = display;
  375. numTrigsIn->valueForDisplay = &module->inputs[MU::NUMTRIGS_INPUT].value;
  376. numTrigsIn->format = "%2.2f V";
  377. numTrigsIn->header = "Trigs count";
  378. addInput(numTrigsIn);
  379. TinyPJ301MPortWithDisplay* distTrigsIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[5]), Port::INPUT, module, MU::DISTTRIGS_INPUT);
  380. distTrigsIn->lblDisplay = display;
  381. distTrigsIn->valueForDisplay = &module->inputs[MU::DISTTRIGS_INPUT].value;
  382. distTrigsIn->format = "%2.2f V";
  383. distTrigsIn->header = "Trigs Dist.";
  384. addInput(distTrigsIn);
  385. TinyPJ301MPortWithDisplay* gateBridgeIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[6]), Port::INPUT, module, MU::GATEBRIDGE_INPUT);
  386. gateBridgeIn->lblDisplay = display;
  387. gateBridgeIn->valueForDisplay = &module->inputs[MU::GATEBRIDGE_INPUT].value;
  388. gateBridgeIn->format = "%2.2f V";
  389. gateBridgeIn->header = "Gate";
  390. addInput(gateBridgeIn);
  391. TinyPJ301MPortWithDisplay* gateBridgeOut = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[6]), Port::OUTPUT, module, MU::GATEBRIDGE_OUTPUT);
  392. gateBridgeOut->lblDisplay = display;
  393. gateBridgeOut->valueForDisplay = &module->outputs[MU::GATEBRIDGE_OUTPUT].value;
  394. gateBridgeOut->format = "%2.2f V";
  395. gateBridgeOut->header = "Gate";
  396. addOutput(gateBridgeOut);
  397. addParam(ParamWidget::create<MiniLEDButton>(Vec(portX1[1]-11, portY1[6]+5), module, MU::TRIGSTACK_PARAM, 0.0f, 10.0f, 0.0f));
  398. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(portX1[1]-11, portY1[6]+5), module, MU::TRIGSTACK_LIGHT));
  399. TinyPJ301MPortWithDisplay* cvBridgeIn = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[0], portY1[7]), Port::INPUT, module, MU::CVBRIDGE_INPUT);
  400. cvBridgeIn->lblDisplay = display;
  401. cvBridgeIn->valueForDisplay = &module->inputs[MU::CVBRIDGE_INPUT].value;
  402. cvBridgeIn->format = "%2.2f V";
  403. cvBridgeIn->header = "CV";
  404. addInput(cvBridgeIn);
  405. TinyPJ301MPortWithDisplay* cvBridgeOut = Port::create<TinyPJ301MPortWithDisplay>(Vec(portX1[1], portY1[7]), Port::OUTPUT, module, MU::CVBRIDGE_OUTPUT);
  406. cvBridgeOut->lblDisplay = display;
  407. cvBridgeOut->valueForDisplay = &module->outputs[MU::CVBRIDGE_OUTPUT].value;
  408. cvBridgeOut->format = "%2.2f V";
  409. cvBridgeOut->header = "CV";
  410. addOutput(cvBridgeOut);
  411. addParam(ParamWidget::create<MiniLEDButton>(Vec(portX1[1]-11, portY1[7]+5), module, MU::CVSTACK_PARAM, 0.0f, 10.0f, 0.0f));
  412. addChild(ModuleLightWidget::create<SmallLight<BlueLight>>(Vec(portX1[1]-11, portY1[7]+5), module, MU::CVSTACK_LIGHT));
  413. }
  414. };
  415. } // namespace rack_plugin_Bidoo
  416. using namespace rack_plugin_Bidoo;
  417. RACK_PLUGIN_MODEL_INIT(Bidoo, MU) {
  418. Model *modelMU= Model::create<MU, MUWidget>("Bidoo", "µ", "µ synced pulse generator", SEQUENCER_TAG);
  419. return modelMU;
  420. }