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.

310 lines
10KB

  1. #include "M581.hpp"
  2. #include <sstream>
  3. namespace rack_plugin_TheXOR {
  4. void M581::on_loaded()
  5. {
  6. #ifdef DIGITAL_EXT
  7. connected = 0;
  8. #endif
  9. load();
  10. }
  11. void M581::load()
  12. {
  13. stepCounter.Set(&getter);
  14. cvControl.Set(&getter);
  15. gateControl.Set(&getter);
  16. getter.Set(this);
  17. _reset();
  18. }
  19. void M581::_reset()
  20. {
  21. cvControl.Reset();
  22. gateControl.Reset();
  23. stepCounter.Reset(&Timer);
  24. showCurStep(0, 0);
  25. }
  26. void M581::step()
  27. {
  28. if(resetTrigger.process(inputs[RESET].value))
  29. {
  30. _reset();
  31. } else
  32. {
  33. Timer.Step();
  34. if(clockTrigger.process(inputs[CLOCK].value) && any())
  35. beginNewStep();
  36. outputs[CV].value = cvControl.Play(Timer.Elapsed());
  37. outputs[GATE].value = gateControl.Play(&Timer, stepCounter.PulseCounter());
  38. }
  39. #ifdef DIGITAL_EXT
  40. bool dig_connected = false;
  41. #ifdef LAUNCHPAD
  42. if(drv->Connected())
  43. dig_connected = true;
  44. drv->ProcessLaunchpad();
  45. #endif
  46. #if defined(OSCTEST_MODULE)
  47. if(oscDrv->Connected())
  48. dig_connected = true;
  49. oscDrv->ProcessOSC();
  50. #endif
  51. connected = dig_connected ? 1.0 : 0.0;
  52. #endif
  53. }
  54. void M581::beginNewStep()
  55. {
  56. int cur_step;
  57. if(stepCounter.Play(&Timer, &cur_step)) // inizia un nuovo step?
  58. {
  59. gateControl.Begin(cur_step);
  60. cvControl.Begin(cur_step); // glide note increment in 1/10 di msec. param = new note value
  61. }
  62. showCurStep(cur_step, stepCounter.PulseCounter());
  63. }
  64. void M581::showCurStep(int cur_step, int sub_div)
  65. {
  66. int lled = cur_step;
  67. int sled = sub_div;
  68. for(int k = 0; k < 8; k++)
  69. {
  70. lights[LED_STEP + k].value = k == lled ? 1.0 : 0.0;
  71. lights[LED_SUBDIV + k].value = k == sled ? 1.0 : 0.0;
  72. }
  73. }
  74. bool M581::any()
  75. {
  76. for(int k = 0; k < 8; k++)
  77. {
  78. if(getter.IsEnabled(k)) // step on?
  79. return true;
  80. }
  81. return false;
  82. }
  83. M581Widget::M581Widget(M581 *module) : SequencerWidget(module)
  84. {
  85. #ifdef OSCTEST_MODULE
  86. char name[60];
  87. #endif
  88. box.size = Vec(29 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  89. SVGPanel *panel = new SVGPanel();
  90. panel->box.size = box.size;
  91. panel->setBackground(SVG::load(assetPlugin(plugin, "res/modules/M581Module.svg")));
  92. addChild(panel);
  93. addChild(Widget::create<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
  94. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 2*RACK_GRID_WIDTH, 0)));
  95. addChild(Widget::create<ScrewBlack>(Vec(RACK_GRID_WIDTH, box.size.y - RACK_GRID_WIDTH)));
  96. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 2*RACK_GRID_WIDTH, box.size.y - RACK_GRID_WIDTH)));
  97. float dist_h = 11.893;
  98. for(int k = 0; k < 8; k++)
  99. {
  100. // page #0 (Session): step enable/disable; gate mode
  101. // step enable
  102. ParamWidget *pwdg = ParamWidget::create<CKSSThreeFix>(Vec(mm2px(14.151+k*dist_h), yncscape(11.744,10.0)), module, M581::STEP_ENABLE + k, 0.0, 2.0, 1.0);
  103. addParam(pwdg);
  104. #ifdef LAUNCHPAD
  105. LaunchpadRadio *radio = new LaunchpadRadio(0, ILaunchpadPro::RC2Key(5, k), 3, LaunchpadLed::Color(43), LaunchpadLed::Color(32));
  106. module->drv->Add(radio, pwdg);
  107. #endif
  108. #ifdef OSCTEST_MODULE
  109. sprintf(name, "/Enable%i", k + 1);
  110. oscControl *oc = new oscControl(name);
  111. module->oscDrv->Add(oc, pwdg);
  112. #endif
  113. // Gate switches
  114. pwdg = ParamWidget::create<VerticalSwitch>(Vec(mm2px(14.930 + k*dist_h), yncscape(39.306, 13.2)), module, M581::GATE_SWITCH + k, 0.0, 3.0, 2.0);
  115. addParam(pwdg);
  116. #ifdef LAUNCHPAD
  117. radio = new LaunchpadRadio(0, ILaunchpadPro::RC2Key(1, k), 4, LaunchpadLed::Color(11), LaunchpadLed::Color(17));
  118. module->drv->Add(radio, pwdg);
  119. #endif
  120. #ifdef OSCTEST_MODULE
  121. sprintf(name, "/GateMode%i", k + 1);
  122. oc = new oscControl(name);
  123. module->oscDrv->Add(oc, pwdg);
  124. #endif
  125. // page #1 (Note): Notes
  126. // step notes
  127. pwdg = ParamWidget::create<BefacoSlidePotFix>(Vec(mm2px(14.943 + k*dist_h), yncscape(95.822, 27.517)), module, M581::STEP_NOTES + k, 0.0, 1.0, 0.5);
  128. addParam(pwdg);
  129. #ifdef LAUNCHPAD
  130. LaunchpadKnob *pknob = new LaunchpadKnob(1, ILaunchpadPro::RC2Key(6, k), LaunchpadLed::Rgb(10, 0, 0), LaunchpadLed::Rgb(63, 63, 63));
  131. module->drv->Add(pknob, pwdg);
  132. #endif
  133. #ifdef OSCTEST_MODULE
  134. sprintf(name, "/Knob%i", k + 1);
  135. oc = new oscControl(name);
  136. module->oscDrv->Add(oc, pwdg);
  137. #endif
  138. //page #2 (Device): Counters
  139. // Counter switches
  140. pwdg = ParamWidget::create<CounterSwitch>(Vec(mm2px(14.93 + k*dist_h), yncscape(60.897, 24.0)), module, M581::COUNTER_SWITCH + k, 0.0, 7.0, 0.0);
  141. addParam(pwdg);
  142. #ifdef LAUNCHPAD
  143. radio = new LaunchpadRadio(2, ILaunchpadPro::RC2Key(0, k), 8, LaunchpadLed::Color(1), LaunchpadLed::Color(58));
  144. module->drv->Add(radio, pwdg);
  145. #endif
  146. #ifdef OSCTEST_MODULE
  147. sprintf(name, "/Count%i", k + 1);
  148. oc = new oscControl(name);
  149. module->oscDrv->Add(oc, pwdg);
  150. #endif
  151. // step leds (all pages)
  152. ModuleLightWidget *plight = ModuleLightWidget::create<LargeLight<RedLight>>(Vec(mm2px(13.491 + k*dist_h), yncscape(27.412, 5.179)), module, M581::LED_STEP + k);
  153. addChild(plight);
  154. #ifdef LAUNCHPAD
  155. LaunchpadLight *ld1 = new LaunchpadLight(launchpadDriver::ALL_PAGES, ILaunchpadPro::RC2Key(0, k), LaunchpadLed::Off(), LaunchpadLed::Color(5));
  156. module->drv->Add(ld1, plight);
  157. #endif
  158. #ifdef OSCTEST_MODULE
  159. sprintf(name, "/Led%i", k + 1);
  160. oc = new oscControl(name);
  161. module->oscDrv->Add(oc, plight);
  162. #endif
  163. // subdiv leds (all pages)
  164. const float dv = 3.029;
  165. plight = ModuleLightWidget::create<TinyLight<RedLight>>(Vec(mm2px(11.642), yncscape(82.953-k*dv+0.272, 1.088)), module, M581::LED_SUBDIV + k);
  166. addChild(plight);
  167. #ifdef LAUNCHPAD
  168. ld1 = new LaunchpadLight(launchpadDriver::ALL_PAGES, ILaunchpadPro::RC2Key(8, k), LaunchpadLed::Off(), LaunchpadLed::Color(5)); // colonna PLAY
  169. module->drv->Add(ld1, plight);
  170. #endif
  171. #ifdef OSCTEST_MODULE
  172. sprintf(name, "/SubLed%i", k + 1);
  173. oc = new oscControl(name);
  174. module->oscDrv->Add(oc, plight);
  175. #endif
  176. }
  177. // Gate time
  178. ParamWidget *pwdg = ParamWidget::create<Davies1900hFixWhiteKnob>(Vec(mm2px(121.032), yncscape(112.942, 9.525)), module, M581::GATE_TIME, 0.005, 1.0, 0.25);
  179. #ifdef OSCTEST_MODULE
  180. sprintf(name, "/GateTime");
  181. oscControl *oc = new oscControl(name);
  182. module->oscDrv->Add(oc, pwdg);
  183. #endif
  184. addParam(pwdg); // in sec
  185. // Slide time
  186. pwdg = ParamWidget::create<Davies1900hFixWhiteKnob>(Vec(mm2px(121.032), yncscape(95.480, 9.525)), module, M581::SLIDE_TIME, 0.005, 2.0, 0.5);
  187. addParam(pwdg); // in sec
  188. #ifdef OSCTEST_MODULE
  189. sprintf(name, "/SlideTime");
  190. oc = new oscControl(name);
  191. module->oscDrv->Add(oc, pwdg);
  192. #endif
  193. // volt fondo scala
  194. pwdg = ParamWidget::create<CKSSFix>(Vec(mm2px(7.066), yncscape(114.224, 5.460)), module, M581::MAXVOLTS, 0.0, 1.0, 1.0);
  195. addParam(pwdg);
  196. #ifdef OSCTEST_MODULE
  197. sprintf(name, "/Voltage");
  198. oc = new oscControl(name);
  199. module->oscDrv->Add(oc, pwdg);
  200. #endif
  201. // step div
  202. pwdg = ParamWidget::create<VerticalSwitch>(Vec(mm2px(123.494), yncscape(75.482, 13.2)), module, M581::STEP_DIV, 0.0, 3.0, 0.0);
  203. addParam(pwdg);
  204. #ifdef OSCTEST_MODULE
  205. sprintf(name, "/StepDiv");
  206. oc = new oscControl(name);
  207. module->oscDrv->Add(oc, pwdg);
  208. #endif
  209. // input
  210. addInput(Port::create<PJ301RPort>(Vec(mm2px(113.864), yncscape(22.128, 8.255)), Port::INPUT, module, M581::CLOCK));
  211. addInput(Port::create<PJ301YPort>(Vec(mm2px(129.469), yncscape(22.128, 8.255)), Port::INPUT, module, M581::RESET));
  212. // OUTPUTS
  213. addOutput(Port::create<PJ301GPort>(Vec(mm2px(113.864), yncscape(7.228, 8.255)), Port::OUTPUT, module, M581::CV));
  214. addOutput(Port::create<PJ301WPort>(Vec(mm2px(129.469), yncscape(7.228, 8.255)), Port::OUTPUT, module, M581::GATE));
  215. // # STEPS
  216. SigDisplayWidget *display2 = new SigDisplayWidget(2);
  217. display2->box.pos = Vec(mm2px(127.229), yncscape(37.851, 9.525));
  218. display2->box.size = Vec(30, 20);
  219. display2->value = module->getAddress(1);
  220. addChild(display2);
  221. pwdg = ParamWidget::create<Davies1900hFixRedKnob>(Vec(mm2px(113.229), yncscape(38.851, 9.525)), module, M581::NUM_STEPS, 1.0, 31.0, 8.0);
  222. ((Davies1900hKnob *)pwdg)->snap = true;
  223. addParam(pwdg);
  224. // run mode
  225. RunModeDisplay *display = new RunModeDisplay();
  226. display->box.pos = Vec(mm2px(127.229), yncscape(57.259, 9.525));
  227. display->box.size = Vec(42, 20);
  228. display->mode = module->getAddress(0);
  229. addChild(display);
  230. pwdg = ParamWidget::create<Davies1900hFixBlackKnob>(Vec(mm2px(113.229), yncscape(58.259,9.525)), module, M581::RUN_MODE, 0.0, 4.0, 0.0);
  231. ((Davies1900hKnob *)pwdg)->snap = true;
  232. addParam(pwdg);
  233. #ifdef DIGITAL_EXT
  234. addChild(new DigitalLed(mm2px(92.540), yncscape(2.322,3.867), &module->connected));
  235. #endif
  236. }
  237. Menu *M581Widget::addContextMenu(Menu *menu)
  238. {
  239. menu->addChild(new SeqMenuItem<M581Widget>("Randomize Pitch", this, RANDOMIZE_PITCH));
  240. menu->addChild(new SeqMenuItem<M581Widget>("Randomize Counters", this, RANDOMIZE_COUNTER));
  241. menu->addChild(new SeqMenuItem<M581Widget>("Randomize Modes", this, RANDOMIZE_MODE));
  242. menu->addChild(new SeqMenuItem<M581Widget>("Randomize Enable/Slide", this, RANDOMIZE_ENABLE));
  243. return menu;
  244. }
  245. void M581Widget::onMenu(int action)
  246. {
  247. switch(action)
  248. {
  249. case RANDOMIZE_COUNTER: std_randomize(M581::COUNTER_SWITCH, M581::COUNTER_SWITCH + 8); break;
  250. case RANDOMIZE_PITCH: std_randomize(M581::STEP_NOTES, M581::STEP_NOTES + 8); break;
  251. case RANDOMIZE_MODE: std_randomize(M581::GATE_SWITCH, M581::GATE_SWITCH + 8); break;
  252. case RANDOMIZE_ENABLE: std_randomize(M581::STEP_ENABLE, M581::STEP_ENABLE + 8); break;
  253. }
  254. }
  255. bool ParamGetter::IsEnabled(int numstep) { return pModule->params[M581::STEP_ENABLE + numstep].value > 0.0; }
  256. bool ParamGetter::IsSlide(int numstep) { return pModule->params[M581::STEP_ENABLE + numstep].value > 1.0; }
  257. int ParamGetter::GateMode(int numstep) { return std::round(pModule->params[M581::GATE_SWITCH + numstep].value); }
  258. int ParamGetter::PulseCount(int numstep) { return std::round(pModule->params[M581::COUNTER_SWITCH + numstep].value); }
  259. float ParamGetter::Note(int numstep) { return pModule->params[M581::STEP_NOTES + numstep].value * (pModule->params[M581::MAXVOLTS].value > 0 ? 5.0 : 3.0); }
  260. int ParamGetter::RunMode() { return std::round(pModule->params[M581::RUN_MODE].value); }
  261. int ParamGetter::NumSteps() { return std::round(pModule->params[M581::NUM_STEPS].value); }
  262. float ParamGetter::SlideTime() { return pModule->params[M581::SLIDE_TIME].value; }
  263. float ParamGetter::GateTime() { return pModule->params[M581::GATE_TIME].value; }
  264. int ParamGetter::StepDivision() { return std::round(pModule->params[M581::STEP_DIV].value) + 1; }
  265. } // namespace rack_plugin_TheXOR
  266. using namespace rack_plugin_TheXOR;
  267. RACK_PLUGIN_MODEL_INIT(TheXOR, M581) {
  268. return Model::create<M581, M581Widget>("TheXOR", "M581", "581 Sequencer", SEQUENCER_TAG);
  269. }