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.

515 lines
21KB

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include "widgets.hpp"
  4. using namespace rack;
  5. #include "trowaSoft.hpp"
  6. #include "dsp/digital.hpp"
  7. #include "trowaSoftComponents.hpp"
  8. #include "trowaSoftUtilities.hpp"
  9. #include "TSSequencerModuleBase.hpp"
  10. #include "TSOSCConfigWidget.hpp"
  11. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  12. // TSSequencerWidgetBase() - Base constructor.
  13. // Instantiate a trowaSoft Sequencer widget. v0.60 must have module as param.
  14. // @seqModule : (IN) Pointer to the sequencer module.
  15. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  16. TSSequencerWidgetBase::TSSequencerWidgetBase(TSSequencerModuleBase* seqModule) : TSSModuleWidgetBase(seqModule)
  17. {
  18. box.size = Vec(26 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  19. return;
  20. }
  21. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  22. // Add common controls to the UI widget for trowaSoft sequencers.
  23. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  24. void TSSequencerWidgetBase::addBaseControls(bool addGridLines)
  25. {
  26. TSSequencerModuleBase *thisModule = NULL;
  27. if (this->module != NULL)
  28. thisModule = dynamic_cast<TSSequencerModuleBase*>(this->module);
  29. bool isPreview = thisModule == NULL;
  30. ////////////////////////////////////
  31. // DISPLAY
  32. ////////////////////////////////////
  33. {
  34. display = new TSSeqDisplay();
  35. display->box.pos = Vec(13, 24);
  36. display->box.size = Vec(363, 48);
  37. display->module = thisModule;
  38. addChild(display);
  39. }
  40. ////////////////////////////////////
  41. // OSC configuration screen.
  42. // Should be a popup but J just wants it of the screen.
  43. ////////////////////////////////////
  44. if (!isPreview)
  45. {
  46. TSOSCConfigWidget* oscConfig = new TSOSCConfigWidget(thisModule, TSSequencerModuleBase::ParamIds::OSC_SAVE_CONF_PARAM, TSSequencerModuleBase::ParamIds::OSC_AUTO_RECONNECT_PARAM,
  47. thisModule->oscCurrentClient,
  48. thisModule->currentOSCSettings.oscTxIpAddress.c_str(), thisModule->currentOSCSettings.oscTxPort, thisModule->currentOSCSettings.oscRxPort);
  49. oscConfig->setVisible(false);
  50. oscConfig->box.pos = display->box.pos;
  51. oscConfig->box.size = display->box.size;
  52. //oscConfig->module = thisModule;
  53. this->oscConfigurationScreen = oscConfig;
  54. addChild(oscConfig);
  55. }
  56. ////////////////////////////////////
  57. // Labels
  58. ////////////////////////////////////
  59. {
  60. TSSeqLabelArea *area = new TSSeqLabelArea();
  61. area->box.pos = Vec(0, 0);
  62. area->box.size = Vec(box.size.x, 380);
  63. area->module = thisModule;
  64. area->drawGridLines = addGridLines;
  65. addChild(area);
  66. }
  67. // Screws:
  68. addChild(Widget::create<ScrewBlack>(Vec(0, 0)));
  69. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 15, 0)));
  70. addChild(Widget::create<ScrewBlack>(Vec(0, box.size.y - 15)));
  71. addChild(Widget::create<ScrewBlack>(Vec(box.size.x - 15, box.size.y - 15)));
  72. // Inputs ==================================================
  73. // Run (Toggle)
  74. Vec btnSize = Vec(50,22);
  75. addParam(ParamWidget::create<TS_PadBtn>(Vec(15, 320), thisModule, TSSequencerModuleBase::ParamIds::RUN_PARAM, 0.0, 1.0, 0.0));
  76. TS_LightString* item = dynamic_cast<TS_LightString*>(TS_createColorValueLight<TS_LightString>(/*pos */ Vec(15, 320),
  77. /*thisModule*/ thisModule,
  78. /*lightId*/ TSSequencerModuleBase::LightIds::RUNNING_LIGHT,
  79. /* size */ btnSize, /* color */ COLOR_WHITE));
  80. item->lightString = "RUN";
  81. addChild(item);
  82. // Reset (Momentary)
  83. addParam(ParamWidget::create<TS_PadBtn>(Vec(15, 292), thisModule, TSSequencerModuleBase::ParamIds::RESET_PARAM, 0.0, 1.0, 0.0));
  84. item = dynamic_cast<TS_LightString*>(TS_createColorValueLight<TS_LightString>(/*pos */ Vec(15, 292),
  85. /*thisModule*/ thisModule,
  86. /*lightId*/ TSSequencerModuleBase::LightIds::RESET_LIGHT,
  87. /* size */ btnSize, /* color */ COLOR_WHITE));
  88. item->lightString = "RESET";
  89. addChild(item);
  90. // Paste button:
  91. addParam(ParamWidget::create<TS_PadBtn>(Vec(15, 115), thisModule, TSSequencerModuleBase::ParamIds::PASTE_PARAM, 0.0, 1.0, 0.0));
  92. thisModule->pasteLight = dynamic_cast<TS_LightString*>(TS_createColorValueLight<TS_LightString>(/*pos */ Vec(15, 115),
  93. /*thisModule*/ thisModule,
  94. /*lightId*/ TSSequencerModuleBase::LightIds::PASTE_LIGHT,
  95. /* size */ btnSize, /* color */ COLOR_WHITE));
  96. thisModule->pasteLight->lightString = "PASTE";
  97. addChild(thisModule->pasteLight);
  98. // Top Knobs : Keep references for later
  99. int knobRow = 79;
  100. int knobStart = 27;
  101. int knobSpacing = 61;
  102. RoundSmallBlackKnob* outKnobPtr = NULL;
  103. // Pattern Playback Select (Knob)
  104. outKnobPtr = dynamic_cast<RoundSmallBlackKnob*>(ParamWidget::create<RoundSmallBlackKnob>(Vec(knobStart, knobRow), thisModule, TSSequencerModuleBase::ParamIds::SELECTED_PATTERN_PLAY_PARAM, /*min*/ 0.0, /*max*/ TROWA_SEQ_NUM_PATTERNS - 1, /*default value*/ 0.0));
  105. if (!isPreview)
  106. thisModule->controlKnobs[TSSequencerModuleBase::KnobIx::PlayPatternKnob] = outKnobPtr;
  107. addParam(outKnobPtr);
  108. // Clock BPM (Knob)
  109. outKnobPtr = dynamic_cast<RoundSmallBlackKnob*>(ParamWidget::create<RoundSmallBlackKnob>(Vec(knobStart + (knobSpacing * 1), knobRow), thisModule, TSSequencerModuleBase::ParamIds::BPM_PARAM, TROWA_SEQ_BPM_KNOB_MIN, TROWA_SEQ_BPM_KNOB_MAX, (TROWA_SEQ_BPM_KNOB_MAX + TROWA_SEQ_BPM_KNOB_MIN) / 2));
  110. if (!isPreview)
  111. thisModule->controlKnobs[TSSequencerModuleBase::KnobIx::BPMKnob] = outKnobPtr;
  112. addParam(outKnobPtr);
  113. // Steps (Knob)
  114. outKnobPtr = dynamic_cast<RoundSmallBlackKnob*>(ParamWidget::create<RoundSmallBlackKnob>(Vec(knobStart + (knobSpacing * 2), knobRow), thisModule, TSSequencerModuleBase::ParamIds::STEPS_PARAM, 1.0, this->maxSteps, this->maxSteps));
  115. if (!isPreview)
  116. thisModule->controlKnobs[TSSequencerModuleBase::KnobIx::StepLengthKnob] = outKnobPtr;
  117. addParam(outKnobPtr);
  118. // Output Mode (Knob)
  119. outKnobPtr = dynamic_cast<RoundSmallBlackKnob*>(ParamWidget::create<RoundSmallBlackKnob>(Vec(knobStart + (knobSpacing * 3), knobRow), thisModule,
  120. TSSequencerModuleBase::ParamIds::SELECTED_OUTPUT_VALUE_MODE_PARAM, 0, TROWA_SEQ_NUM_MODES - 1, TSSequencerModuleBase::ValueMode::VALUE_TRIGGER));
  121. outKnobPtr->minAngle = -0.6*M_PI;
  122. outKnobPtr->maxAngle = 0.6*M_PI;
  123. if (!isPreview)
  124. thisModule->controlKnobs[TSSequencerModuleBase::KnobIx::OutputModeKnob] = outKnobPtr;
  125. addParam(outKnobPtr);
  126. // Pattern Edit Select (Knob)
  127. outKnobPtr = dynamic_cast<RoundSmallBlackKnob*>(ParamWidget::create<RoundSmallBlackKnob>(Vec(knobStart + (knobSpacing * 4), knobRow), thisModule, TSSequencerModuleBase::ParamIds::SELECTED_PATTERN_EDIT_PARAM, /*min*/ 0.0, /*max*/ TROWA_SEQ_NUM_PATTERNS - 1, /*default value*/ 0));
  128. if (!isPreview)
  129. thisModule->controlKnobs[TSSequencerModuleBase::KnobIx::EditPatternKnob] = outKnobPtr;
  130. addParam(outKnobPtr);
  131. // Selected Gate/Voice/Channel (Knob)
  132. outKnobPtr = dynamic_cast<RoundSmallBlackKnob*>(ParamWidget::create<RoundSmallBlackKnob>(Vec(knobStart + (knobSpacing * 5), knobRow), thisModule, TSSequencerModuleBase::ParamIds::SELECTED_CHANNEL_PARAM, /*min*/ 0.0, /*max*/ TROWA_SEQ_NUM_CHNLS - 1, /*default value*/ 0));
  133. if (!isPreview)
  134. thisModule->controlKnobs[TSSequencerModuleBase::KnobIx::EditChannelKnob] = outKnobPtr;
  135. addParam(outKnobPtr);
  136. Vec ledSize = Vec(15,15);
  137. int dx = 28;
  138. // OSC: Enable OSC button:
  139. LEDButton* btn;
  140. int y = knobRow;
  141. int x = knobStart + (knobSpacing * 3) + dx; // 30
  142. if (isPreview || thisModule->allowOSC)
  143. {
  144. Vec btnSize = Vec(ledSize.x - 2, ledSize.y - 2);
  145. btn = dynamic_cast<LEDButton*>(ParamWidget::create<LEDButton>(Vec(x, y), module, TSSequencerModuleBase::ParamIds::OSC_SHOW_CONF_PARAM, 0, 1, 0));
  146. btn->box.size = btnSize;
  147. addParam(btn);
  148. addChild(TS_createColorValueLight<ColorValueLight>(Vec(x, y), module, TSSequencerModuleBase::LightIds::OSC_CONFIGURE_LIGHT, ledSize, COLOR_WHITE));
  149. addChild(TS_createColorValueLight<ColorValueLight>(Vec(x + 2, y + 2), module, TSSequencerModuleBase::LightIds::OSC_ENABLED_LIGHT, Vec(ledSize.x - 4, ledSize.y - 4), TSOSC_STATUS_COLOR));
  150. }
  151. ColorValueLight* lightPtr = NULL;
  152. // COPY: Pattern Copy button:
  153. btn = dynamic_cast<LEDButton*>(ParamWidget::create<LEDButton>(Vec(knobStart + (knobSpacing * 4) + dx, knobRow), module, TSSequencerModuleBase::ParamIds::COPY_PATTERN_PARAM, 0, 1, 0));
  154. btn->box.size = ledSize;
  155. addParam(btn);
  156. lightPtr = dynamic_cast<ColorValueLight*>(TS_createColorValueLight<ColorValueLight>(Vec(knobStart + (knobSpacing * 4) + dx, knobRow), module, TSSequencerModuleBase::LightIds::COPY_PATTERN_LIGHT, ledSize, COLOR_WHITE));
  157. if (!isPreview)
  158. thisModule->copyPatternLight = lightPtr;
  159. addChild(lightPtr);
  160. // COPY: Gate Copy button:
  161. btn = dynamic_cast<LEDButton*>(ParamWidget::create<LEDButton>(Vec(knobStart + (knobSpacing * 5) + dx, knobRow), module, TSSequencerModuleBase::ParamIds::COPY_CHANNEL_PARAM, 0, 1, 0));
  162. btn->box.size = ledSize;
  163. addParam(btn);
  164. lightPtr = dynamic_cast<ColorValueLight*>(TS_createColorValueLight<ColorValueLight>(Vec(knobStart + (knobSpacing * 5) + dx, knobRow), module, TSSequencerModuleBase::LightIds::COPY_CHANNEL_LIGHT, ledSize, COLOR_WHITE));
  165. if (!isPreview)
  166. thisModule->copyGateLight = lightPtr;
  167. addChild(lightPtr);
  168. // CHANGE BPM CALC NOTE (1/4, 1/8, 1/8T, 1/16)
  169. //SELECTED_BPM_MULT_IX_PARAM
  170. btn = dynamic_cast<LEDButton*>(ParamWidget::create<LEDButton>(Vec(knobStart + (knobSpacing * 1) + dx, knobRow), module, TSSequencerModuleBase::ParamIds::SELECTED_BPM_MULT_IX_PARAM, 0, 1, 0));
  171. btn->box.size = ledSize;
  172. addParam(btn);
  173. addChild(TS_createColorValueLight<ColorValueLight>(Vec(knobStart + (knobSpacing * 1) + dx, knobRow), module, TSSequencerModuleBase::LightIds::SELECTED_BPM_MULT_IX_LIGHT, ledSize, COLOR_WHITE));
  174. // Input Jacks:
  175. int xStart = 10;
  176. int ySpacing = 28;
  177. int portStart = 143;
  178. // Selected Pattern Playback:
  179. addInput(TS_createInput<TS_Port>(Vec(xStart, portStart + (ySpacing * 0)), thisModule, TSSequencerModuleBase::InputIds::SELECTED_PATTERN_PLAY_INPUT));
  180. // Clock
  181. addInput(TS_createInput<TS_Port>(Vec(xStart, portStart + (ySpacing * 1)), thisModule, TSSequencerModuleBase::InputIds::BPM_INPUT));
  182. // Steps
  183. addInput(TS_createInput<TS_Port>(Vec(xStart, portStart + (ySpacing * 2)), thisModule, TSSequencerModuleBase::InputIds::STEPS_INPUT));
  184. // External Clock
  185. addInput(TS_createInput<TS_Port>(Vec(xStart, portStart + (ySpacing * 3)), thisModule, TSSequencerModuleBase::InputIds::EXT_CLOCK_INPUT));
  186. // Reset
  187. addInput(TS_createInput<TS_Port>(Vec(xStart, portStart + (ySpacing * 4)), thisModule, TSSequencerModuleBase::InputIds::RESET_INPUT));
  188. // Outputs ==================================================
  189. // Loop through each channel/voice/gate
  190. y = 115;
  191. x = 314;
  192. int v = 0;
  193. float jackDiameter = 20.5; // 28.351
  194. float add = 0;
  195. Vec outputLightSize = Vec(jackDiameter + add, jackDiameter + add);
  196. NVGcolor* channelColors = NULL;
  197. NVGcolor colors[TROWA_SEQ_NUM_CHNLS] {
  198. COLOR_TS_RED, COLOR_DARK_ORANGE, COLOR_YELLOW, COLOR_TS_GREEN,
  199. COLOR_CYAN, COLOR_TS_BLUE, COLOR_PURPLE, COLOR_PINK,
  200. COLOR_TS_RED, COLOR_DARK_ORANGE, COLOR_YELLOW, COLOR_TS_GREEN,
  201. COLOR_CYAN, COLOR_TS_BLUE, COLOR_PURPLE, COLOR_PINK
  202. };
  203. if (!isPreview)
  204. {
  205. channelColors = thisModule->voiceColors;
  206. }
  207. else
  208. {
  209. channelColors = colors; // Point to our default array
  210. }
  211. for (int r = 0; r < 8; r++)
  212. {
  213. for (int c = 0; c < 2; c++)
  214. {
  215. // Triggers / Gates / Output:
  216. addOutput(TS_createOutput<TS_Port>(Vec(x, y), thisModule, TSSequencerModuleBase::OutputIds::CHANNELS_OUTPUT+v, /*color*/ channelColors[v]));
  217. // Match the color to the trigger/gate/output:
  218. addChild(TS_createColorValueLight<TS_LightRing>(/*position*/ Vec(x + 5, y + 5),
  219. /*thisModule*/ thisModule,
  220. /*lightId*/ TSSequencerModuleBase::LightIds::CHANNEL_LIGHTS+v,
  221. /*size*/ outputLightSize, /*lightColor*/ channelColors[v], /*backColor*/ channelColors[v]));
  222. if (!isPreview)
  223. thisModule->lights[TSSequencerModuleBase::LightIds::CHANNEL_LIGHTS + v].value = 0;
  224. x += 36;
  225. v++;
  226. } // end for
  227. y += 28; // Next row
  228. x = 314;
  229. } // end loop through NxM grid
  230. //debug("Base Controls added.");
  231. return;
  232. } // end addBaseControls()
  233. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  234. // step(void)
  235. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  236. void TSSequencerWidgetBase::step()
  237. {
  238. if (this->module == NULL)
  239. return;
  240. TSSequencerModuleBase* thisModule = dynamic_cast<TSSequencerModuleBase*>(module);
  241. if (thisModule->oscConfigTrigger.process(thisModule->params[TSSequencerModuleBase::ParamIds::OSC_SHOW_CONF_PARAM].value))
  242. {
  243. thisModule->oscShowConfigurationScreen = !thisModule->oscShowConfigurationScreen;
  244. thisModule->lights[TSSequencerModuleBase::LightIds::OSC_CONFIGURE_LIGHT].value = (thisModule->oscShowConfigurationScreen) ? 1.0 : 0.0;
  245. this->oscConfigurationScreen->setVisible(thisModule->oscShowConfigurationScreen);
  246. this->display->showDisplay = !thisModule->oscShowConfigurationScreen;
  247. if (thisModule->oscShowConfigurationScreen)
  248. {
  249. if (!thisModule->oscInitialized)
  250. {
  251. // Make sure the ports are available
  252. int p = TSOSCConnector::PortInUse(thisModule->currentOSCSettings.oscTxPort);
  253. if (p > 0 && p != thisModule->oscId)
  254. thisModule->currentOSCSettings.oscTxPort = TSOSCConnector::GetAvailablePort(thisModule->oscId, thisModule->currentOSCSettings.oscTxPort);
  255. p = TSOSCConnector::PortInUse(thisModule->currentOSCSettings.oscRxPort);
  256. if (p > 0 && p != thisModule->oscId)
  257. thisModule->currentOSCSettings.oscRxPort = TSOSCConnector::GetAvailablePort(thisModule->oscId, thisModule->currentOSCSettings.oscRxPort);
  258. }
  259. this->oscConfigurationScreen->setValues(thisModule->currentOSCSettings.oscTxIpAddress, thisModule->currentOSCSettings.oscTxPort, thisModule->currentOSCSettings.oscRxPort);
  260. this->oscConfigurationScreen->ckAutoReconnect->checked = thisModule->oscReconnectAtLoad;
  261. this->oscConfigurationScreen->setSelectedClient(thisModule->oscCurrentClient); // OSC Client
  262. this->oscConfigurationScreen->btnActionEnable = !thisModule->oscInitialized;
  263. this->oscConfigurationScreen->errorMsg = "";
  264. if (thisModule->oscError)
  265. {
  266. this->oscConfigurationScreen->errorMsg = "Error connecting to " + thisModule->currentOSCSettings.oscTxIpAddress;
  267. }
  268. this->oscConfigurationScreen->setVisible(true);
  269. }
  270. else
  271. {
  272. this->oscConfigurationScreen->setVisible(false);
  273. }
  274. }
  275. if (thisModule->oscShowConfigurationScreen)
  276. {
  277. // Check for enable/disable
  278. if (thisModule->oscConnectTrigger.process(thisModule->params[TSSequencerModuleBase::ParamIds::OSC_SAVE_CONF_PARAM].value))
  279. {
  280. if (oscConfigurationScreen->btnActionEnable)
  281. {
  282. // Enable OSC ------------------------------------------------------------------------
  283. // User checked to connect
  284. if (!this->oscConfigurationScreen->isValidIpAddress())
  285. {
  286. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  287. debug("IP Address is not valid.");
  288. #endif
  289. this->oscConfigurationScreen->errorMsg = "Invalid IP Address.";
  290. this->oscConfigurationScreen->tbIpAddress->requestFocus();
  291. }
  292. else if (!this->oscConfigurationScreen->isValidTxPort())
  293. {
  294. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  295. debug("Tx Port is not valid.");
  296. #endif
  297. this->oscConfigurationScreen->errorMsg = "Invalid Output Port (0-" + std::to_string(0xFFFF) + ").";
  298. this->oscConfigurationScreen->tbTxPort->requestFocus();
  299. }
  300. else if (!this->oscConfigurationScreen->isValidRxPort())
  301. {
  302. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  303. debug("Rx Port is not valid.");
  304. #endif
  305. this->oscConfigurationScreen->errorMsg = "Invalid Input Port (0-" + std::to_string(0xFFFF) + ").";
  306. this->oscConfigurationScreen->tbRxPort->requestFocus();
  307. }
  308. else
  309. {
  310. // Try to connect
  311. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  312. debug("Save OSC Configuration clicked, save information for module.");
  313. #endif
  314. this->oscConfigurationScreen->errorMsg = "";
  315. thisModule->oscNewSettings.oscTxIpAddress = this->oscConfigurationScreen->tbIpAddress->text.c_str();
  316. thisModule->oscNewSettings.oscTxPort = this->oscConfigurationScreen->getTxPort();
  317. thisModule->oscNewSettings.oscRxPort = this->oscConfigurationScreen->getRxPort();
  318. thisModule->oscCurrentClient = this->oscConfigurationScreen->getSelectedClient();
  319. thisModule->oscCurrentAction = TSSequencerModuleBase::OSCAction::Enable;
  320. thisModule->oscReconnectAtLoad = this->oscConfigurationScreen->ckAutoReconnect->checked;
  321. }
  322. } // end if enable osc
  323. else
  324. {
  325. // Disable OSC ------------------------------------------------------------------
  326. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  327. debug("Disable OSC clicked.");
  328. #endif
  329. this->oscConfigurationScreen->errorMsg = "";
  330. thisModule->oscCurrentAction = TSSequencerModuleBase::OSCAction::Disable;
  331. } // end else disable OSC
  332. } // end if OSC Save btn pressed
  333. else
  334. {
  335. if (thisModule->oscError)
  336. {
  337. if (this->oscConfigurationScreen->errorMsg.empty())
  338. this->oscConfigurationScreen->errorMsg = "Error connecting to " + thisModule->currentOSCSettings.oscTxIpAddress + ".";
  339. }
  340. }
  341. // Current status of OSC
  342. if (thisModule->useOSC && thisModule->oscInitialized)
  343. { // Now we have a checkbox up top where statusMsg used to be, so let's not use it for now.
  344. //this->oscConfigurationScreen->statusMsg = OSCClientAbbr[thisModule->oscCurrentClient] + " " + thisModule->currentOSCSettings.oscTxIpAddress;
  345. //this->oscConfigurationScreen->statusMsg2 = ":" + std::to_string(thisModule->currentOSCSettings.oscTxPort)
  346. // + " :" + std::to_string(thisModule->currentOSCSettings.oscRxPort);
  347. this->oscConfigurationScreen->statusMsg2 = OSCClientAbbr[thisModule->oscCurrentClient] + " " + thisModule->currentOSCSettings.oscTxIpAddress;
  348. this->oscConfigurationScreen->btnActionEnable = false;
  349. }
  350. else
  351. {
  352. this->oscConfigurationScreen->successMsg = "";
  353. this->oscConfigurationScreen->statusMsg = "";// "OSC Not Connected";
  354. this->oscConfigurationScreen->statusMsg2 = "OSC Not Connected"; //"";
  355. this->oscConfigurationScreen->btnActionEnable = true;
  356. }
  357. } // end if show OSC config screen
  358. ModuleWidget::step();
  359. return;
  360. } // end step()
  361. struct seqRandomSubMenuItem : MenuItem {
  362. TSSequencerModuleBase* sequencerModule;
  363. bool useStucturedRandom;
  364. enum ShiftType {
  365. // Current Edit Pattern & Channel
  366. CurrentChannelOnly,
  367. // Current Edit Pattern, All Channels
  368. ThisPattern,
  369. // All patterns, all channels
  370. AllPatterns
  371. };
  372. ShiftType Target = ShiftType::CurrentChannelOnly;
  373. seqRandomSubMenuItem(std::string text, ShiftType target, bool useStructured, TSSequencerModuleBase* seqModule)
  374. {
  375. this->box.size.x = 200;
  376. this->text = text;
  377. this->Target = target;
  378. this->useStucturedRandom = useStructured;
  379. this->sequencerModule = seqModule;
  380. }
  381. ~seqRandomSubMenuItem()
  382. {
  383. sequencerModule = NULL;
  384. }
  385. void onAction(EventAction &e) override {
  386. if (this->Target == ShiftType::AllPatterns)
  387. {
  388. sequencerModule->randomize(TROWA_INDEX_UNDEFINED, TROWA_SEQ_COPY_CHANNELIX_ALL, useStucturedRandom);
  389. }
  390. else if (this->Target == ShiftType::ThisPattern)
  391. {
  392. sequencerModule->randomize(sequencerModule->currentPatternEditingIx, TROWA_SEQ_COPY_CHANNELIX_ALL, useStucturedRandom);
  393. }
  394. else //if (this->Target == ShiftType::CurrentChannelOnly)
  395. {
  396. sequencerModule->randomize(sequencerModule->currentPatternEditingIx, sequencerModule->currentChannelEditingIx, useStucturedRandom);
  397. }
  398. }
  399. };
  400. struct seqRandomSubMenu : Menu {
  401. TSSequencerModuleBase* sequencerModule;
  402. bool useStucturedRandom;
  403. seqRandomSubMenu(bool useStructured, TSSequencerModuleBase* seqModule)
  404. {
  405. this->box.size = Vec(200, 60);
  406. this->useStucturedRandom = useStructured;
  407. this->sequencerModule = seqModule;
  408. return;
  409. }
  410. ~seqRandomSubMenu()
  411. {
  412. sequencerModule = NULL;
  413. }
  414. void createChildren()
  415. {
  416. addChild(new seqRandomSubMenuItem("Current Edit Channel", seqRandomSubMenuItem::ShiftType::CurrentChannelOnly, this->useStucturedRandom, this->sequencerModule));
  417. addChild(new seqRandomSubMenuItem("Current Edit Pattern", seqRandomSubMenuItem::ShiftType::ThisPattern, this->useStucturedRandom, this->sequencerModule));
  418. addChild(new seqRandomSubMenuItem("ALL Patterns", seqRandomSubMenuItem::ShiftType::AllPatterns, this->useStucturedRandom, this->sequencerModule));
  419. return;
  420. }
  421. };
  422. // First tier menu item. Create Submenu
  423. struct seqRandomMenuItem : MenuItem {
  424. TSSequencerModuleBase* sequencerModule;
  425. bool useStucturedRandom;
  426. seqRandomMenuItem(std::string text, bool useStructured, TSSequencerModuleBase* seqModule)
  427. {
  428. this->box.size.x = 200;
  429. this->text = text;
  430. this->useStucturedRandom = useStructured;
  431. this->sequencerModule = seqModule;
  432. return;
  433. }
  434. ~seqRandomMenuItem() {
  435. sequencerModule = NULL;
  436. return;
  437. }
  438. Menu *createChildMenu() override {
  439. seqRandomSubMenu* menu = new seqRandomSubMenu(useStucturedRandom, sequencerModule);
  440. menu->sequencerModule = this->sequencerModule;
  441. menu->createChildren();
  442. menu->box.size = Vec(200, 60);
  443. return menu;
  444. }
  445. };
  446. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  447. // createContextMenu()
  448. // Create context menu with more random options for sequencers.
  449. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  450. Menu *TSSequencerWidgetBase::createContextMenu()
  451. {
  452. Menu *menu = ModuleWidget::createContextMenu();
  453. MenuLabel *spacerLabel = new MenuLabel();
  454. menu->addChild(spacerLabel);
  455. TSSequencerModuleBase* sequencerModule = dynamic_cast<TSSequencerModuleBase*>(module);
  456. //-------- Random ------- //
  457. MenuLabel *modeLabel = new MenuLabel();
  458. modeLabel->text = "Random Options";
  459. menu->addChild(modeLabel); //menu->pushChild(modeLabel);
  460. menu->addChild(new seqRandomMenuItem("> All Steps Random", false, sequencerModule));
  461. menu->addChild(new seqRandomMenuItem("> Structured Random", true, sequencerModule));
  462. return menu;
  463. }