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.

1619 lines
56KB

  1. #include <chrono>
  2. #include <string.h>
  3. #include <exception>
  4. #include "trowaSoft.hpp"
  5. #include "dsp/digital.hpp"
  6. #include "trowaSoftComponents.hpp"
  7. #include "trowaSoftUtilities.hpp"
  8. #include "TSSequencerModuleBase.hpp"
  9. #include "TSOSCSequencerListener.hpp"
  10. #include "TSOSCSequencerOutputMessages.hpp"
  11. #include "TSOSCCommunicator.hpp"
  12. #include "TSSequencerWidgetBase.hpp"
  13. // Static Variables:
  14. RandStructure TSSequencerModuleBase::RandomPatterns[TROWA_SEQ_NUM_RANDOM_PATTERNS] = {
  15. { 1,{ 0 } },
  16. { 2,{ 0, 1 } },
  17. { 2,{ 0,0,0,1 } },
  18. { 2,{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } },
  19. { 2,{ 0,0,1,1 } },
  20. { 2,{ 0,1,1,1 } },
  21. { 2,{ 0,1,1,0 } },
  22. { 3,{ 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,2 } },
  23. { 3,{ 0,0,1,2 } },
  24. { 3,{ 0,0,0,0,0,0,1,2 } },
  25. { 3,{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2 } },
  26. { 3,{ 0,1,0,2 } },
  27. { 3,{ 0,1,2,0 } },
  28. { 3,{ 0,1,1,2 } },
  29. { 3,{ 0,2,1,2 } },
  30. { 4,{ 0,1,2,3 } },
  31. { 4,{ 0,0,1,1,2,2,3,3 } },
  32. { 4,{ 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3 } },
  33. { 5,{ 0,1,0,1,0,1,0,2,0,3,0,3,0,3,0,4 } },
  34. { 6,{ 0,1,0,2,0,1,0,3,0,1,0,4,0,1,0,5 } },
  35. { 8,{ 0,0,0,1,2,3,4,5,0,0,0,1,2,3,6,7 } },
  36. { 9,{ 0,1,0,2,0,1,0,3,0,1,0,4,5,6,7,8 } },
  37. { 10,{ 0,1,1,2,3,4,5,6,0,1,1,2,3,7,8,9 } },
  38. { 10,{ 0,1,1,2,3,4,5,6,1,1,1,2,3,7,8,9 } },
  39. { 10,{ 0,1,2,3,4,5,6,7,0,1,2,3,4,5,8,9 } },
  40. { 10,{ 0,1,2,3,4,5,6,7,0,1,8,3,4,5,6,9 } },
  41. { 11,{ 0,1,2,3,4,5,6,7,8,1,2,3,4,5,9,10 } }
  42. };
  43. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  44. // TSSequencerModuleBase()
  45. // Instantiate the abstract base class.
  46. // @numSteps: (IN) Maximum number of steps
  47. // @numRows: (IN) The number of rows (for layout).
  48. // @numCols: (IN) The number of columns (for layout).
  49. // @numRows * @numCols = @numSteps
  50. // @defStateVal : (IN) The default state value (i.e. 0/false for a boolean step sequencer or whatever float value you want).
  51. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  52. TSSequencerModuleBase::TSSequencerModuleBase(/*in*/ int numSteps, /*in*/ int numRows, /*in*/ int numCols, /*in*/ float defStateVal) : Module(NUM_PARAMS + numSteps, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS + numSteps)
  53. {
  54. useOSC = false;
  55. oscInitialized = false;
  56. oscBuffer = NULL;
  57. oscTxSocket = NULL;
  58. oscListener = NULL;
  59. oscRxSocket = NULL;
  60. oscNamespace = OSC_DEFAULT_NS;
  61. oscId = TSOSCConnector::GetId();
  62. for (int i = 0; i < SeqOSCOutputMsg::NUM_OSC_OUTPUT_MSGS; i++)
  63. {
  64. for (int j = 0; j < OSC_ADDRESS_BUFFER_SIZE; j++)
  65. oscAddrBuffer[i][j] = '\0';
  66. }
  67. prevIndex = TROWA_INDEX_UNDEFINED;
  68. gateTriggers = NULL;
  69. lastStepWasExternalClock = false;
  70. defaultStateValue = defStateVal;
  71. currentChannelEditingIx = 0;
  72. currentPatternEditingIx = 0;
  73. currentPatternPlayingIx = 0;
  74. // Number of steps in not static at compile time anymore...
  75. maxSteps = numSteps; // Num Steps may vary now up to 64
  76. currentNumberSteps = maxSteps;
  77. storedNumberSteps = maxSteps;
  78. this->numRows = numRows;
  79. this->numCols = numCols;
  80. stepLights = new float*[numRows];
  81. gateLights = new float*[numRows];
  82. padLightPtrs = new ColorValueLight**[numRows];
  83. for (int r = 0; r < numRows; r++)
  84. {
  85. stepLights[r] = new float[numCols];
  86. gateLights[r] = new float[numCols];
  87. padLightPtrs[r] = new ColorValueLight*[numCols];
  88. for (int c = 0; c < numCols; c++)
  89. {
  90. stepLights[r][c] = 0;
  91. gateLights[r][c] = 0;
  92. }
  93. }
  94. for (int g = 0; g < TROWA_SEQ_NUM_CHNLS; g++)
  95. {
  96. copyBuffer[g] = new float[maxSteps];
  97. }
  98. for (int p = 0; p < TROWA_SEQ_NUM_PATTERNS; p++)
  99. {
  100. for (int g = 0; g < TROWA_SEQ_NUM_CHNLS; g++)
  101. {
  102. triggerState[p][g] = new float[maxSteps];
  103. for (int s = 0; s < maxSteps; s++)
  104. {
  105. triggerState[p][g][s] = defaultStateValue;
  106. }
  107. }
  108. }
  109. modeStrings[0] = "TRIG";
  110. modeStrings[1] = "RTRG";
  111. modeStrings[2] = "GATE"; // CONT/GATE
  112. copySourcePatternIx = -1;
  113. copySourceChannelIx = TROWA_SEQ_COPY_CHANNELIX_ALL; // Which trigger we are copying, -1 for all
  114. initialized = false;
  115. firstLoad = true;
  116. return;
  117. } // end TSSequencerModuleBase()
  118. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  119. // Delete our goodies.
  120. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  121. TSSequencerModuleBase::~TSSequencerModuleBase()
  122. {
  123. initialized = false; // Stop doing stuff
  124. cleanupOSC();
  125. for (int r = 0; r < numRows; r++)
  126. {
  127. if (stepLights[r])
  128. delete[] stepLights[r];
  129. if (gateLights[r])
  130. delete[] gateLights[r];
  131. if (padLightPtrs[r])
  132. delete[] padLightPtrs[r];
  133. }
  134. if (stepLights != NULL)
  135. {
  136. delete[] stepLights; stepLights = NULL;
  137. }
  138. if (gateLights != NULL)
  139. {
  140. delete[] gateLights; gateLights = NULL;
  141. }
  142. if (padLightPtrs != NULL)
  143. {
  144. delete[] padLightPtrs; padLightPtrs = NULL;
  145. }
  146. for (int g = 0; g < TROWA_SEQ_NUM_CHNLS; g++)
  147. {
  148. delete[] copyBuffer[g];
  149. copyBuffer[g] = NULL; // We should be totally dead & unreferenced anyway, so I'm not sure we have NULL our ptrs???
  150. }
  151. for (int p = 0; p < TROWA_SEQ_NUM_PATTERNS; p++)
  152. {
  153. for (int g = 0; g < TROWA_SEQ_NUM_CHNLS; g++)
  154. {
  155. delete[] triggerState[p][g];
  156. triggerState[p][g] = NULL;
  157. }
  158. }
  159. this->copyGateLight = NULL;
  160. this->copyPatternLight = NULL;
  161. this->pasteLight = NULL;
  162. // Free our buffer if we had initialized it
  163. oscMutex.lock();
  164. if (oscBuffer != NULL)
  165. {
  166. free(oscBuffer);
  167. oscBuffer = NULL;
  168. }
  169. oscMutex.unlock();
  170. return;
  171. } // end ~TSSequencerModuleBase()
  172. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  173. // reset(void)
  174. // Reset ALL step values to default.
  175. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  176. void TSSequencerModuleBase::reset()
  177. {
  178. valuesChanging = true;
  179. for (int p = 0; p < TROWA_SEQ_NUM_PATTERNS; p++)
  180. {
  181. for (int c = 0; c < TROWA_SEQ_NUM_CHNLS; c++)
  182. {
  183. for (int s = 0; s < maxSteps; s++)
  184. {
  185. triggerState[p][c][s] = defaultStateValue;
  186. }
  187. }
  188. }
  189. /// TODO: Also clear our clipboard and turn off OSC?
  190. reloadEditMatrix = true;
  191. valuesChanging = false;
  192. return;
  193. }
  194. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  195. // randomize()
  196. // @patternIx : (IN) The index into our pattern matrix (0-63). Or TROWA_INDEX_UNDEFINED for all patterns.
  197. // @channelIx : (IN) The index of the channel (gate/trigger/voice) if any (0-15, or TROWA_SEQ_COPY_CHANNELIX_ALL/TROWA_INDEX_UNDEFINED for all).
  198. // @useStructured: (IN) Create a random sequence/pattern of random values.
  199. // Random all from : https://github.com/j4s0n-c/trowaSoft-VCV/issues/8
  200. // Structured from : https://github.com/j4s0n-c/trowaSoft-VCV/issues/10
  201. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  202. void TSSequencerModuleBase::randomize(int patternIx, int channelIx, bool useStructured)
  203. {
  204. if (patternIx == TROWA_INDEX_UNDEFINED)
  205. {
  206. // All patterns:
  207. for (int p = 0; p < TROWA_SEQ_NUM_PATTERNS; p++)
  208. {
  209. randomize(p, TROWA_INDEX_UNDEFINED, useStructured); // All channels
  210. }
  211. }
  212. else if (channelIx == TROWA_INDEX_UNDEFINED)
  213. {
  214. // This pattern:
  215. for (int c = 0; c < TROWA_SEQ_NUM_CHNLS; c++)
  216. {
  217. randomize(patternIx, c, useStructured);
  218. }
  219. }
  220. else
  221. {
  222. valuesChanging = true;
  223. // -- Randomize Channel Specified --
  224. float val;
  225. if (useStructured)
  226. {
  227. // Use a pattern
  228. // A, AB, ABBA, ABAC
  229. int rIx = rand() % numStructuredRandomPatterns;// TROWA_SEQ_NUM_RANDOM_PATTERNS;
  230. int n = RandomPatterns[rIx].numDiffVals;
  231. float* randVals = new float[n];
  232. int patternLen = RandomPatterns[rIx].pattern.size();
  233. // Every Channel should get its own random pattern
  234. for (int i = 0; i < n; i++)
  235. randVals[i] = getRandomValue();
  236. for (int s = 0; s < maxSteps; s++)
  237. {
  238. val = randVals[RandomPatterns[rIx].pattern[s % patternLen]];
  239. triggerState[patternIx][channelIx][s] = val;
  240. if (patternIx == currentPatternEditingIx && channelIx == currentChannelEditingIx)
  241. onShownStepChange(s, val);
  242. }
  243. delete[] randVals;
  244. } // end if random pattern/structure
  245. else
  246. {
  247. // Every value is random
  248. for (int s = 0; s < maxSteps; s++)
  249. {
  250. val = getRandomValue();
  251. triggerState[patternIx][channelIx][s] = val;
  252. if (patternIx == currentPatternEditingIx && channelIx == currentChannelEditingIx)
  253. onShownStepChange(s, val);
  254. }
  255. } // end else (normal Rand -- all values random)
  256. reloadEditMatrix = (patternIx == currentPatternEditingIx && channelIx == currentChannelEditingIx);
  257. valuesChanging = false;
  258. } // end else (channel and pattern specified)
  259. return;
  260. }
  261. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  262. // Set the OSC namespace.
  263. // @oscNs: (IN) The namespace for OSC.
  264. // Sets the command address strings too.
  265. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  266. void TSSequencerModuleBase::setOSCNamespace(const char* oscNs)
  267. {
  268. this->oscNamespace = oscNs;
  269. for (int i = 0; i < SeqOSCOutputMsg::NUM_OSC_OUTPUT_MSGS; i++)
  270. {
  271. // Create our array of output addresses based on the base format and the osc name space.
  272. sprintf(this->oscAddrBuffer[i], TSSeqOSCOutputFormats[i], oscNamespace.c_str());
  273. }
  274. // Add %d (all this was changed for touchOSC's limitations)
  275. std::strcat(oscAddrBuffer[SeqOSCOutputMsg::EditStepString], "%d");
  276. std::strcat(oscAddrBuffer[SeqOSCOutputMsg::EditStep], "%d");
  277. std::strcat(oscAddrBuffer[SeqOSCOutputMsg::PlayStepLed], "%d");
  278. // [touchOSC] Add some <row>/<col>
  279. std::strcat(oscAddrBuffer[SeqOSCOutputMsg::EditTOSC_GridStep], "%d/%d");
  280. return;
  281. } // end setOSCNameSpace()
  282. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  283. // Initialize OSC on the given ip and ports.
  284. // @ipAddress: (IN) The ip address.
  285. // @outputPort: (IN) The output port.
  286. // @inputPort: (IN) The input port.
  287. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  288. void TSSequencerModuleBase::initOSC(const char* ipAddress, int outputPort, int inputPort)
  289. {
  290. oscMutex.lock();
  291. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  292. debug("TSSequencerModuleBase::initOSC() - Initializing OSC");
  293. #endif
  294. try
  295. {
  296. // Try to register these ports:
  297. if (TSOSCConnector::RegisterPorts(oscId, outputPort, inputPort))
  298. {
  299. oscError = false;
  300. this->currentOSCSettings.oscTxIpAddress = ipAddress;
  301. this->setOSCNamespace(this->oscNamespace.c_str());
  302. if (oscBuffer == NULL)
  303. {
  304. oscBuffer = (char*)malloc(OSC_OUTPUT_BUFFER_SIZE * sizeof(char));
  305. }
  306. if (oscTxSocket == NULL)
  307. {
  308. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  309. debug("TSSequencerModuleBase::initOSC() - Create TRANS socket at %s, port %d.", ipAddress, outputPort);
  310. #endif
  311. oscTxSocket = new UdpTransmitSocket(IpEndpointName(ipAddress, outputPort));
  312. this->currentOSCSettings.oscTxPort = outputPort;
  313. }
  314. if (oscRxSocket == NULL)
  315. {
  316. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  317. debug("TSSequencerModuleBase::initOSC() - Create RECV socket at any address, port %d.", inputPort);
  318. #endif
  319. oscListener = new TSOSCSequencerListener();
  320. oscListener->sequencerModule = this;
  321. oscListener->oscNamespace = this->oscNamespace;
  322. oscRxSocket = new UdpListeningReceiveSocket(IpEndpointName(IpEndpointName::ANY_ADDRESS, inputPort), oscListener);
  323. this->currentOSCSettings.oscRxPort = inputPort;
  324. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  325. debug("TSSequencerModuleBase::initOSC() - Starting listener thread...");
  326. #endif
  327. oscListenerThread = std::thread(&UdpListeningReceiveSocket::Run, oscRxSocket);
  328. }
  329. //#if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  330. // debug("TSSequencerModuleBase::initOSC() - OSC Initialized");
  331. //#endif
  332. info("TSSequencerModuleBase::initOSC() - OSC Initialized : %s :%d :%d", ipAddress, outputPort, inputPort);
  333. oscInitialized = true;
  334. }
  335. else
  336. {
  337. oscError = true;
  338. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  339. debug("TSSequencerModuleBase::initOSC() - Ports in use already.");
  340. #endif
  341. }
  342. }
  343. catch (const std::exception& ex)
  344. {
  345. oscError = true;
  346. warn("TSSequencerModuleBase::initOSC() - Error initializing: %s.", ex.what());
  347. }
  348. oscMutex.unlock();
  349. return;
  350. } // end initOSC()
  351. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  352. // Clean up OSC.
  353. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  354. void TSSequencerModuleBase::cleanupOSC()
  355. {
  356. oscMutex.lock();
  357. try
  358. {
  359. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  360. debug("TSSequencerModuleBase::cleanupOSC() - Cleaning up OSC");
  361. #endif
  362. oscInitialized = false;
  363. oscError = false;
  364. TSOSCConnector::ClearPorts(oscId, currentOSCSettings.oscTxPort, currentOSCSettings.oscRxPort);
  365. if (oscRxSocket != NULL)
  366. {
  367. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  368. debug("TSSequencerModuleBase::cleanupOSC() - Cleaning up RECV socket.");
  369. #endif
  370. oscRxSocket->AsynchronousBreak();
  371. oscListenerThread.join(); // Wait for him to finish
  372. delete oscRxSocket;
  373. oscRxSocket = NULL;
  374. }
  375. if (oscTxSocket != NULL)
  376. {
  377. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  378. debug("TSSequencerModuleBase::cleanupOSC() - Cleanup TRANS socket.");
  379. #endif
  380. delete oscTxSocket;
  381. oscTxSocket = NULL;
  382. }
  383. //if (oscBuffer != NULL)
  384. //{
  385. // free(oscBuffer);
  386. // oscBuffer = NULL;
  387. //}
  388. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  389. debug("TSSequencerModuleBase::cleanupOSC() - OSC cleaned");
  390. #endif
  391. }
  392. catch (const std::exception& ex)
  393. {
  394. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  395. debug("TSSequencerModuleBase::cleanupOSC() - Exception caught:\n%s", ex.what());
  396. #endif
  397. }
  398. oscMutex.unlock();
  399. return;
  400. } // end cleanupOSC()
  401. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  402. // copy()
  403. // @patternIx : (IN) The index into our pattern matrix (0-15).
  404. // @channelIx : (IN) The index of the channel (gate/trigger/voice) to copy if any (0-15, or TROWA_SEQ_COPY_CHANNELIX_ALL for all).
  405. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  406. void TSSequencerModuleBase::copy(/*in*/ int patternIx, /*in*/ int channelIx)
  407. {
  408. copySourceChannelIx = channelIx;
  409. copySourcePatternIx = patternIx;
  410. if (copySourceChannelIx == TROWA_SEQ_COPY_CHANNELIX_ALL)
  411. {
  412. // Copy entire pattern (all gates/triggers/voices)
  413. for (int g = 0; g < TROWA_SEQ_NUM_CHNLS; g++)
  414. {
  415. for (int s = 0; s < maxSteps; s++)
  416. {
  417. copyBuffer[g][s] = triggerState[copySourcePatternIx][g][s];
  418. }
  419. }
  420. }
  421. else
  422. {
  423. // Copy just the gate:
  424. for (int s = 0; s < maxSteps; s++)
  425. {
  426. copyBuffer[copySourceChannelIx][s] = triggerState[copySourcePatternIx][copySourceChannelIx][s];
  427. }
  428. }
  429. return;
  430. } // end copy()
  431. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  432. // paste(void)
  433. // Paste our current clipboard Pattern/Gate to the currently selected Pattern/Gate.
  434. // @returns: True if the values were copied, false if not.
  435. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  436. bool TSSequencerModuleBase::paste()
  437. {
  438. if (copySourcePatternIx < 0) // Nothing to copy
  439. return false;
  440. valuesChanging = true;
  441. if (copySourceChannelIx == TROWA_SEQ_COPY_CHANNELIX_ALL)
  442. {
  443. // Copy entire pattern (all gates/triggers/voices)
  444. for (int g = 0; g < TROWA_SEQ_NUM_CHNLS; g++)
  445. {
  446. for (int s = 0; s < maxSteps; s++)
  447. {
  448. triggerState[currentPatternEditingIx][g][s] = copyBuffer[g][s];
  449. }
  450. }
  451. }
  452. else
  453. {
  454. // Copy just the channel:
  455. for (int s = 0; s < maxSteps; s++)
  456. {
  457. triggerState[currentPatternEditingIx][currentChannelEditingIx][s] = copyBuffer[copySourceChannelIx][s];
  458. }
  459. }
  460. valuesChanging = false;
  461. return true;
  462. } // end paste()
  463. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  464. // Set a single the step value
  465. // (i.e. this command probably comes from an external source)
  466. // @step : (IN) The step number to edit (0 to maxSteps).
  467. // @val : (IN) The step value.
  468. // @channel : (IN) The channel to edit (0 to TROWA_SEQ_NUM_CHNLS - 1).
  469. // @pattern: (IN) The pattern to edit (0 to TROWA_SEQ_NUM_PATTERNS - 1).
  470. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  471. void TSSequencerModuleBase::setStepValue(int step, float val, int channel, int pattern)
  472. {
  473. int r, c;
  474. if (channel == CURRENT_EDIT_CHANNEL_IX)
  475. {
  476. channel = currentChannelEditingIx;
  477. }
  478. if (pattern == CURRENT_EDIT_PATTERN_IX)
  479. {
  480. pattern = currentPatternEditingIx;
  481. }
  482. triggerState[pattern][channel][step] = val;
  483. r = step / this->numCols;
  484. c = step % this->numCols;
  485. if (pattern == currentPatternEditingIx && channel == currentChannelEditingIx)
  486. {
  487. if (triggerState[pattern][channel][step])
  488. {
  489. gateLights[r][c] = 1.0f - stepLights[r][c];
  490. if (gateTriggers != NULL)
  491. gateTriggers[step].state = SchmittTrigger::HIGH;
  492. }
  493. else
  494. {
  495. gateLights[r][c] = 0.0f; // Turn light off
  496. if (gateTriggers != NULL)
  497. gateTriggers[step].state = SchmittTrigger::LOW;
  498. }
  499. }
  500. oscMutex.lock();
  501. if (useOSC && oscInitialized)
  502. {
  503. try
  504. {
  505. char addrBuff[50] = { 0 };
  506. // Send the result back
  507. if (this->oscCurrentClient == OSCClient::touchOSCClient)
  508. {
  509. int gridRow, gridCol;
  510. touchOSC::stepIndex_to_mcRowCol(step, numRows, numCols, &gridRow, &gridCol);
  511. sprintf(addrBuff, oscAddrBuffer[SeqOSCOutputMsg::EditTOSC_GridStep], gridRow, gridCol); // Grid's /<row>/<col> to accomodate touchOSC's lack of multi-parameter support.
  512. }
  513. else
  514. {
  515. sprintf(addrBuff, oscAddrBuffer[SeqOSCOutputMsg::EditStep], step + 1); // Changed to /<step> to accomodate touchOSC's lack of multi-parameter support.
  516. }
  517. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  518. debug("setStepValue() - Received a msg (s=%d, v=%0.2f, c=%d, p=%d), sending back (%s).",
  519. step, val, channel, pattern,
  520. addrBuff);
  521. #endif
  522. osc::OutboundPacketStream oscStream(oscBuffer, OSC_OUTPUT_BUFFER_SIZE);
  523. oscStream << osc::BeginBundleImmediate
  524. << osc::BeginMessage(addrBuff)
  525. << triggerState[pattern][channel][step]
  526. << osc::EndMessage
  527. << osc::EndBundle;
  528. oscTxSocket->Send(oscStream.Data(), oscStream.Size());
  529. }
  530. catch (const std::exception &e)
  531. {
  532. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  533. debug("seStepValue - Error sending back msg: %s.", e.what());
  534. #endif
  535. }
  536. }
  537. oscMutex.unlock();
  538. return;
  539. } // end setStepValue()
  540. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  541. // getStepInputs()
  542. // Get the inputs shared between our Sequencers.
  543. // Now also processes our external message queue.
  544. // @pulse : (OUT) If gate pulse
  545. // @reloadMatrix: (OUT) If the edit matrix should be refreshed.
  546. // @valueModeChanged: (OUT) If the output value mode has changed.
  547. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  548. void TSSequencerModuleBase::getStepInputs(/*out*/ bool* pulse, /*out*/ bool* reloadMatrix, /*out*/ bool* valueModeChanged)
  549. {
  550. // Track if we have changed these
  551. bool editPatternChanged = false;
  552. bool editChannelChanged = false;
  553. float lastBPM = currentBPM;
  554. bool playBPMChanged = false;
  555. bool lastRunning = running;
  556. int lastBPMNoteIx = this->selectedBPMNoteIx;
  557. int lastStepIndex = index;
  558. // Run
  559. if (runningTrigger.process(params[RUN_PARAM].value)) {
  560. running = !running;
  561. }
  562. lights[RUNNING_LIGHT].value = running ? 1.0 : 0.0;
  563. bool oscStarted = false; // If OSC just started to a new address this step.
  564. switch (this->oscCurrentAction)
  565. {
  566. case OSCAction::Disable:
  567. this->cleanupOSC(); // Try to clean up OSC
  568. break;
  569. case OSCAction::Enable:
  570. this->cleanupOSC(); // Try to clean up OSC if we already have something
  571. this->initOSC(this->oscNewSettings.oscTxIpAddress.c_str(), this->oscNewSettings.oscTxPort, this->oscNewSettings.oscRxPort);
  572. this->useOSC = true;
  573. oscStarted = this->useOSC && this->oscInitialized;
  574. break;
  575. case OSCAction::None:
  576. default:
  577. break;
  578. }
  579. this->oscCurrentAction = OSCAction::None;
  580. // OSC is Enabled and Active light
  581. lights[LightIds::OSC_ENABLED_LIGHT].value = (useOSC && oscInitialized) ? 1.0 : 0.0;
  582. if (!firstLoad)
  583. lastPatternPlayingIx = currentPatternPlayingIx;
  584. bool nextStep = false;
  585. // Now calculate BPM even if we are paused:
  586. // BPM calculation selection
  587. if (selectedBPMNoteTrigger.process(params[SELECTED_BPM_MULT_IX_PARAM].value)) {
  588. if (selectedBPMNoteIx < TROWA_TEMP_BPM_NUM_OPTIONS - 1)
  589. selectedBPMNoteIx++;
  590. else
  591. selectedBPMNoteIx = 0; // Wrap around
  592. lights[SELECTED_BPM_MULT_IX_LIGHT].value = 1.0;
  593. }
  594. float clockTime = 1.0;
  595. float input = 1.0;
  596. if (inputs[BPM_INPUT].active)
  597. {
  598. // Use whatever voltage we are getting (-10 TO 10 input)
  599. input = rescale(inputs[BPM_INPUT].value, TROWA_SEQ_PATTERN_MIN_V, TROWA_SEQ_PATTERN_MAX_V,
  600. TROWA_SEQ_BPM_KNOB_MIN, TROWA_SEQ_BPM_KNOB_MAX);
  601. }
  602. else
  603. {
  604. // Otherwise read our knob
  605. input = params[BPM_PARAM].value; // -2 to 6
  606. }
  607. clockTime = powf(2.0, input); // -2 to 6
  608. // Calculate his all the time now instead of just on next step:
  609. currentBPM = roundf(clockTime * BPMOptions[selectedBPMNoteIx]->multiplier);
  610. playBPMChanged = lastBPM != currentBPM;
  611. if (running)
  612. {
  613. if (inputs[EXT_CLOCK_INPUT].active)
  614. {
  615. // External clock input
  616. if (clockTrigger.process(inputs[EXT_CLOCK_INPUT].value))
  617. {
  618. realPhase = 0.0;
  619. nextStep = true;
  620. lastStepWasExternalClock = true;
  621. }
  622. }
  623. else
  624. {
  625. // Internal clock
  626. lastStepWasExternalClock = false;
  627. float dt = clockTime / engineGetSampleRate(); // Real dt
  628. realPhase += dt; // Real Time no matter what
  629. if (realPhase >= 1.0)
  630. {
  631. realPhase -= 1.0;
  632. nextStep = true;
  633. }
  634. //if (nextStep)
  635. //{
  636. //currentBPM = roundf(clockTime * BPMOptions[selectedBPMNoteIx]->multiplier);
  637. //playBPMChanged = lastBPM != currentBPM;
  638. //}
  639. }
  640. } // end if running
  641. // Current Playing Pattern
  642. // If we get an input, then use that:
  643. if (inputs[SELECTED_PATTERN_PLAY_INPUT].active)
  644. {
  645. currentPatternPlayingIx = VoltsToPattern(inputs[SELECTED_PATTERN_PLAY_INPUT].value) - 1;
  646. }
  647. else
  648. {
  649. // Otherwise read our knob parameter and use that
  650. currentPatternPlayingIx = (int)clamp(static_cast<int>(roundf(params[SELECTED_PATTERN_PLAY_PARAM].value)), 0, TROWA_SEQ_NUM_PATTERNS - 1);
  651. }
  652. if (currentPatternPlayingIx < 0)
  653. currentPatternPlayingIx = 0;
  654. else if (currentPatternPlayingIx > TROWA_SEQ_NUM_PATTERNS - 1)
  655. currentPatternPlayingIx = TROWA_SEQ_NUM_PATTERNS - 1;
  656. // Current Edit Pattern
  657. int lastEditPatternIx = currentPatternEditingIx;
  658. // From User Knob:
  659. currentPatternEditingIx = (int)clamp(static_cast<int>(roundf(params[SELECTED_PATTERN_EDIT_PARAM].value)), 0, TROWA_SEQ_NUM_PATTERNS - 1);
  660. if (currentPatternEditingIx < 0)
  661. currentPatternEditingIx = 0;
  662. else if (currentPatternEditingIx > TROWA_SEQ_NUM_PATTERNS - 1)
  663. currentPatternEditingIx = TROWA_SEQ_NUM_PATTERNS - 1;
  664. // Gate inputs (which gate we are displaying & editing)
  665. int lastChannelIx = currentChannelEditingIx;
  666. currentChannelEditingIx = (int)clamp(static_cast<int>(roundf(params[SELECTED_CHANNEL_PARAM].value)), 0, TROWA_SEQ_NUM_CHNLS - 1);
  667. if (currentChannelEditingIx < 0)
  668. currentChannelEditingIx = 0;
  669. else if (currentChannelEditingIx > TROWA_SEQ_NUM_CHNLS - 1)
  670. currentChannelEditingIx = TROWA_SEQ_NUM_CHNLS - 1;
  671. editChannelChanged = lastChannelIx != currentChannelEditingIx;
  672. int r = 0;
  673. int c = 0;
  674. // Current output value mode
  675. selectedOutputValueMode = static_cast<ValueMode>((int)clamp(static_cast<int>(roundf(params[SELECTED_OUTPUT_VALUE_MODE_PARAM].value)), 0, TROWA_SEQ_NUM_MODES - 1));
  676. int lastNumberSteps = currentNumberSteps;
  677. if (inputs[STEPS_INPUT].active)
  678. {
  679. // Use the input if something is connected.
  680. // Some seqeuencers go to 64 steps, we want the same voltage to mean the same step number no matter how many max steps this one takes.
  681. // so voltage input is normalized to indicate step 1 to step 64, but we'll limit it to maxSteps.
  682. currentNumberSteps = (int)clamp(static_cast<int>(roundf(rescale(inputs[STEPS_INPUT].value, TROWA_SEQ_STEPS_MIN_V, TROWA_SEQ_STEPS_MAX_V, 1.0, (float)TROWA_SEQ_MAX_NUM_STEPS))), 1, maxSteps);
  683. }
  684. else
  685. {
  686. // Otherwise read our knob
  687. currentNumberSteps = (int)clamp(static_cast<int>(roundf(params[STEPS_PARAM].value)), 1, maxSteps);
  688. }
  689. //------------------------------------------------------------
  690. // Check if we have any eternal messages.
  691. // (i.e. from OSC)
  692. //------------------------------------------------------------
  693. /// TODO: Check performance hit from sending OSC in general
  694. /// TODO: Some thread safety and make sure that this queue never gets unruly? such that we start getting out of time.
  695. bool resetMsg = false;
  696. bool doPaste = false;
  697. int prevCopyPatternIx = copySourcePatternIx;
  698. int prevCopyChannelIx = copySourceChannelIx;
  699. bool storedPatternChanged = false;
  700. bool storedLengthChanged = false;
  701. bool storedBPMChanged = false;
  702. while (ctlMsgQueue.size() > 0)
  703. {
  704. TSExternalControlMessage recvMsg = (TSExternalControlMessage)(ctlMsgQueue.front());
  705. ctlMsgQueue.pop();
  706. float tmp;
  707. /// TODO: redorder switch for most common cases first.
  708. switch (recvMsg.messageType)
  709. {
  710. case TSExternalControlMessage::MessageType::ToggleEditStepValue:
  711. case TSExternalControlMessage::MessageType::SetEditStepValue:
  712. if (currentCtlMode == ExternalControllerMode::EditMode)
  713. {
  714. int p = (recvMsg.pattern == CURRENT_EDIT_PATTERN_IX) ? currentPatternEditingIx : recvMsg.pattern;
  715. int c = (recvMsg.channel == CURRENT_EDIT_CHANNEL_IX) ? currentChannelEditingIx : recvMsg.channel;
  716. float oldVal = this->triggerState[p][c][recvMsg.step];
  717. float val = (recvMsg.messageType == TSExternalControlMessage::MessageType::ToggleEditStepValue) ? getToggleStepValue(recvMsg.step, recvMsg.val, /*channel*/ c, /*pattern*/ p) : recvMsg.val;
  718. if (oldVal != val)
  719. {
  720. // Value has changed:
  721. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  722. debug("[%d] Set Step Value (value changed): %d (P %d, C %d) = %.4f.", recvMsg.messageType, recvMsg.step, p, c, val);
  723. #endif
  724. this->setStepValue(recvMsg.step, val, /*channel*/ c, /*pattern*/ p);
  725. }
  726. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  727. else
  728. {
  729. debug("[%d] Step value did not change -- Ignore : %d (P %d, C %d) = %.4f.", recvMsg.messageType, recvMsg.step, p, c, val);
  730. }
  731. #endif
  732. }
  733. else
  734. {
  735. // In performance mode, this will be interupted as jump to (playing):
  736. if (recvMsg.pattern != CURRENT_EDIT_PATTERN_IX)
  737. {
  738. currentPatternPlayingIx = recvMsg.pattern; // Jump to this pattern if sent
  739. // Update our knob
  740. controlKnobs[KnobIx::PlayPatternKnob]->value = currentPatternPlayingIx;
  741. controlKnobs[KnobIx::PlayPatternKnob]->dirty = true;
  742. params[ParamIds::SELECTED_PATTERN_PLAY_PARAM].value = currentPatternPlayingIx;
  743. }
  744. // Jump to this step:
  745. if (nextStep)
  746. {
  747. // We are already at beginning of a step, so we can sneak this in now.
  748. index = recvMsg.step - 1; // We will set nextStep to true to go to this step fresh
  749. nextIndex = TROWA_INDEX_UNDEFINED;
  750. }
  751. else
  752. {
  753. // Next time we are ready to go to the next step, this should be it.
  754. nextIndex = recvMsg.step;
  755. }
  756. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  757. debug("Performance Mode: Jump to Step (index): %d (Pattern %d).", index, currentPatternPlayingIx);
  758. #endif
  759. }
  760. break;
  761. case TSExternalControlMessage::MessageType::SetPlayCurrentStep:
  762. // We want to wait until the 'next step' (finish the one we are currently doing so things are still in time).
  763. if (nextStep)
  764. {
  765. // We are already at beginning of a step, so we can sneak this in now.
  766. index = recvMsg.step - 1; // We will set nextStep to true to go to this step fresh
  767. nextIndex = TROWA_INDEX_UNDEFINED;
  768. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  769. debug("Set Play Step (index): %d [Immediate].", recvMsg.step);
  770. #endif
  771. }
  772. else
  773. {
  774. // Next time we are ready to go to the next step, this should be it.
  775. nextIndex = recvMsg.step;
  776. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  777. debug("Set Play Step (index): %d [Next, curr is %d].", nextIndex, index);
  778. #endif
  779. }
  780. break;
  781. case TSExternalControlMessage::MessageType::SetPlayReset:
  782. resetMsg = true;
  783. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  784. debug("Set Reset.");
  785. #endif
  786. break;
  787. case TSExternalControlMessage::MessageType::SetPlayPattern:
  788. if (recvMsg.pattern == TROWA_INDEX_UNDEFINED)
  789. recvMsg.pattern = storedPatternPlayingIx; // Check our stored pattern
  790. if (recvMsg.pattern > -1 && recvMsg.pattern < TROWA_SEQ_NUM_PATTERNS)
  791. {
  792. currentPatternPlayingIx = recvMsg.pattern;
  793. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  794. debug("Set Play Pattern: %d.", currentPatternPlayingIx);
  795. #endif
  796. // Update our knob
  797. controlKnobs[KnobIx::PlayPatternKnob]->value = currentPatternPlayingIx;
  798. controlKnobs[KnobIx::PlayPatternKnob]->dirty = true;
  799. params[ParamIds::SELECTED_PATTERN_PLAY_PARAM].value = currentPatternPlayingIx;
  800. }
  801. break;
  802. case TSExternalControlMessage::MessageType::StorePlayPattern:
  803. if (storedPatternPlayingIx != recvMsg.pattern)
  804. {
  805. storedPatternPlayingIx = recvMsg.pattern;
  806. storedPatternChanged = true;
  807. }
  808. break;
  809. case TSExternalControlMessage::MessageType::SetPlayOutputMode:
  810. // -- Set Ouput Mode: (TRIG, RTRIG, GATE) or (VOLT, NOTE, PATT) --
  811. selectedOutputValueMode = (ValueMode)(recvMsg.mode);
  812. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  813. debug("Set Output Mode: %d (TRIG, RTRIG, GATE) or (VOLT, NOTE, PATT).", selectedOutputValueMode);
  814. #endif
  815. controlKnobs[KnobIx::OutputModeKnob]->value = selectedOutputValueMode;
  816. controlKnobs[KnobIx::OutputModeKnob]->dirty = true;
  817. params[ParamIds::SELECTED_OUTPUT_VALUE_MODE_PARAM].value = selectedOutputValueMode;
  818. break;
  819. case TSExternalControlMessage::MessageType::SetEditPattern:
  820. currentPatternEditingIx = recvMsg.pattern;
  821. *reloadMatrix = true; // Refresh our display matrix
  822. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  823. debug("Set Edit Pattern: %d.", currentPatternEditingIx);
  824. #endif
  825. // Update our knob
  826. controlKnobs[KnobIx::EditPatternKnob]->value = currentPatternEditingIx;
  827. controlKnobs[KnobIx::EditPatternKnob]->dirty = true;
  828. params[ParamIds::SELECTED_PATTERN_EDIT_PARAM].value = currentPatternEditingIx;
  829. break;
  830. case TSExternalControlMessage::MessageType::SetEditChannel:
  831. currentChannelEditingIx = recvMsg.channel;
  832. *reloadMatrix = true; // Refresh our display matrix
  833. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  834. debug("Set Edit Channel: %d.", currentChannelEditingIx);
  835. #endif
  836. // Update our knob
  837. controlKnobs[KnobIx::EditChannelKnob]->value = currentChannelEditingIx;
  838. controlKnobs[KnobIx::EditChannelKnob]->dirty = true;
  839. params[ParamIds::SELECTED_CHANNEL_PARAM].value = currentChannelEditingIx;
  840. break;
  841. case TSExternalControlMessage::MessageType::TogglePlayMode:
  842. // -- Control Mode: Edit / Performance Mode --
  843. currentCtlMode = (currentCtlMode == ExternalControllerMode::EditMode) ? ExternalControllerMode::PerformanceMode : ExternalControllerMode::EditMode;
  844. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  845. debug("Toggle Control Mode: %d.", currentCtlMode);
  846. #endif
  847. break;
  848. case TSExternalControlMessage::MessageType::SetPlayMode:
  849. // -- Control Mode: Edit / Performance Mode --
  850. currentCtlMode = static_cast<ExternalControllerMode>(recvMsg.mode);
  851. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  852. debug("Set Control Mode: %d.", currentCtlMode);
  853. #endif
  854. break;
  855. case TSExternalControlMessage::MessageType::StorePlayBPM:
  856. if (storedBPM != recvMsg.mode)
  857. {
  858. storedBPMChanged = true;
  859. storedBPM = recvMsg.mode;
  860. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  861. debug("Store BPM (%d): %.2f.", recvMsg.mode, storedBPM);
  862. #endif
  863. }
  864. break;
  865. // Now BPM and Tempo are separate in OSC.
  866. /// TODO: Maybe move the calcs to the listener thread? But if we have other external messages from non-OSC, then it would have to repeated somewhere...
  867. case TSExternalControlMessage::MessageType::SetPlayBPM: // "BPM" is relative to the note
  868. //float bpm = recvMsg.mode;
  869. // currentBPM = 2^knob * mult
  870. // currentBPM / mult = 2 ^ knob
  871. // log2(currentBPM / mult) = knob
  872. if (recvMsg.mode == TROWA_INDEX_UNDEFINED)
  873. recvMsg.mode = storedBPM;
  874. tmp = clamp(std::log2f(recvMsg.mode / BPMOptions[selectedBPMNoteIx]->multiplier), static_cast<float>(TROWA_SEQ_BPM_KNOB_MIN), static_cast<float>(TROWA_SEQ_BPM_KNOB_MAX));
  875. controlKnobs[KnobIx::BPMKnob]->value = tmp;
  876. controlKnobs[KnobIx::BPMKnob]->dirty = true;
  877. params[ParamIds::BPM_PARAM].value = tmp;
  878. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  879. debug("Set BPM (%d): %.2f.", recvMsg.mode, tmp);
  880. #endif
  881. break;
  882. case TSExternalControlMessage::MessageType::AddPlayBPM: // "BPM" is relative to the note
  883. tmp = pow(2, controlKnobs[KnobIx::BPMKnob]->value) // Current BPM
  884. + recvMsg.mode / BPMOptions[selectedBPMNoteIx]->multiplier;
  885. tmp = std::log2f(tmp);
  886. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  887. debug("Add BPM (%d): Knob %.2f, End is %.2f", recvMsg.mode, controlKnobs[KnobIx::BPMKnob]->value, tmp);
  888. #endif
  889. controlKnobs[KnobIx::BPMKnob]->value = clamp(tmp, static_cast<float>(TROWA_SEQ_BPM_KNOB_MIN), static_cast<float>(TROWA_SEQ_BPM_KNOB_MAX));
  890. controlKnobs[KnobIx::BPMKnob]->dirty = true;
  891. params[ParamIds::BPM_PARAM].value = tmp;
  892. break;
  893. case TSExternalControlMessage::MessageType::SetPlayTempo: // Tempo goes from 0 to 1
  894. tmp = rescale(recvMsg.val, 0.0, 1.0, TROWA_SEQ_BPM_KNOB_MIN, TROWA_SEQ_BPM_KNOB_MAX);
  895. controlKnobs[KnobIx::BPMKnob]->value = tmp;
  896. controlKnobs[KnobIx::BPMKnob]->dirty = true;
  897. params[ParamIds::BPM_PARAM].value = tmp;
  898. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  899. debug("Set Tempo (%.2f): Knob %.2f.", recvMsg.val, tmp);
  900. #endif
  901. break;
  902. case TSExternalControlMessage::MessageType::AddPlayTempo: // Tempo goes from 0 to 1
  903. tmp = rescale(recvMsg.val, 0.0, 1.0, TROWA_SEQ_BPM_KNOB_MIN, TROWA_SEQ_BPM_KNOB_MAX);
  904. controlKnobs[KnobIx::BPMKnob]->value = clamp(tmp + controlKnobs[KnobIx::BPMKnob]->value, static_cast<float>(TROWA_SEQ_BPM_KNOB_MIN), static_cast<float>(TROWA_SEQ_BPM_KNOB_MAX));
  905. controlKnobs[KnobIx::BPMKnob]->dirty = true;
  906. params[ParamIds::BPM_PARAM].value = tmp;
  907. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  908. debug("Add Tempo (%.2f): Knob %.2f.", recvMsg.val, controlKnobs[KnobIx::BPMKnob]->value);
  909. #endif
  910. break;
  911. case TSExternalControlMessage::MessageType::AddPlayBPMNote:
  912. selectedBPMNoteIx = (selectedBPMNoteIx + recvMsg.step) % TROWA_TEMP_BPM_NUM_OPTIONS;
  913. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  914. debug("Add %d to BPM Note Ix: %d.", recvMsg.step, selectedBPMNoteIx);
  915. #endif
  916. break;
  917. case TSExternalControlMessage::MessageType::SetPlayBPMNote:
  918. selectedBPMNoteIx = recvMsg.step % TROWA_TEMP_BPM_NUM_OPTIONS;
  919. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  920. debug("Set BPM Note Ix: %d.", selectedBPMNoteIx);
  921. #endif
  922. break;
  923. case TSExternalControlMessage::MessageType::StorePlayLength:
  924. if (recvMsg.step != storedNumberSteps)
  925. {
  926. storedNumberSteps = recvMsg.step;
  927. storedLengthChanged = true;
  928. }
  929. break;
  930. case TSExternalControlMessage::MessageType::SetPlayLength:
  931. // Use our stored value if sent is -1
  932. recvMsg.step = (recvMsg.step == TROWA_INDEX_UNDEFINED) ? storedNumberSteps : recvMsg.step;
  933. if (recvMsg.step > 0 && recvMsg.step <= maxSteps)
  934. {
  935. currentNumberSteps = recvMsg.step;
  936. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  937. debug("Set Play Step Length: %d.", currentNumberSteps);
  938. #endif
  939. // Update our knob
  940. controlKnobs[KnobIx::StepLengthKnob]->value = currentNumberSteps;
  941. controlKnobs[KnobIx::StepLengthKnob]->dirty = true;
  942. params[ParamIds::STEPS_PARAM].value = currentNumberSteps;
  943. }
  944. break;
  945. case TSExternalControlMessage::MessageType::PasteEditClipboard:
  946. doPaste = true;
  947. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  948. debug("Paste message.");
  949. #endif
  950. break;
  951. case TSExternalControlMessage::MessageType::CopyEditPattern:
  952. {
  953. int pat = (recvMsg.pattern == CURRENT_EDIT_PATTERN_IX) ? currentPatternEditingIx : recvMsg.pattern;
  954. if (copySourcePatternIx > -1 && copySourceChannelIx == TROWA_SEQ_COPY_CHANNELIX_ALL)
  955. {
  956. // Clear clipboard
  957. clearClipboard();
  958. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  959. debug("(clear clipboard) Copy Edit Pattern: %d.", pat);
  960. #endif
  961. }
  962. else
  963. {
  964. //int c = (recvMsg.channel == CURRENT_EDIT_CHANNEL_IX) ? currentChannelEditingIx : recvMsg.channel;
  965. copy(pat, TROWA_SEQ_COPY_CHANNELIX_ALL);
  966. lights[PASTE_LIGHT].value = 1; // Activate paste light to show there is something on the clipboard
  967. pasteLight->setColor(COLOR_WHITE);
  968. lights[COPY_PATTERN_LIGHT].value = 1; // Light up Pattern Copy as Active clipboard
  969. lights[COPY_CHANNEL_LIGHT].value = 0; // Inactivate Gate Copy light
  970. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  971. debug("Copy Edit Pattern: %d.", pat);
  972. #endif
  973. }
  974. }
  975. break;
  976. case TSExternalControlMessage::MessageType::CopyEditChannel:
  977. {
  978. int pat = (recvMsg.pattern == CURRENT_EDIT_PATTERN_IX) ? currentPatternEditingIx : recvMsg.pattern;
  979. int ch = (recvMsg.channel == CURRENT_EDIT_CHANNEL_IX) ? currentChannelEditingIx : recvMsg.channel;
  980. if (copySourcePatternIx > -1 && copySourceChannelIx > -1)
  981. {
  982. // Clear clipboard
  983. clearClipboard();
  984. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  985. debug("(clear clipboard) Copy Edit Channel: (P:%d, C:%d).", pat, ch);
  986. #endif
  987. }
  988. else
  989. {
  990. copy(pat, ch);
  991. lights[PASTE_LIGHT].value = 1; // Activate paste light to show there is something on the clipboard
  992. pasteLight->setColor(voiceColors[currentChannelEditingIx]);
  993. lights[COPY_CHANNEL_LIGHT].value = 1; // Light up Channel Copy Light as Active clipboard
  994. copyGateLight->setColor(voiceColors[currentChannelEditingIx]); // Match the color with our Channel color
  995. lights[COPY_PATTERN_LIGHT].value = 0; // Inactivate Pattern Copy Light
  996. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  997. debug("Copy Edit Channel: (P:%d, C:%d).", pat, ch);
  998. #endif
  999. }
  1000. }
  1001. break;
  1002. case TSExternalControlMessage::MessageType::SetPlayRunningState:
  1003. case TSExternalControlMessage::MessageType::TogglePlayRunningState:
  1004. if (recvMsg.messageType == TSExternalControlMessage::MessageType::TogglePlayRunningState)
  1005. {
  1006. running = !running;
  1007. }
  1008. else
  1009. {
  1010. running = recvMsg.val > 0;
  1011. }
  1012. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  1013. debug("Set Running to: %d.", running);
  1014. #endif
  1015. runningTrigger.state = (running) ? SchmittTrigger::HIGH : SchmittTrigger::LOW;
  1016. params[RUN_PARAM].value = running;
  1017. lights[RUNNING_LIGHT].value = running ? 1.0 : 0.0;
  1018. break;
  1019. case TSExternalControlMessage::MessageType::RandomizeEditStepValue:
  1020. randomize();
  1021. break;
  1022. case TSExternalControlMessage::MessageType::InitializeEditModule:
  1023. reset();
  1024. for (int i = 0; i < KnobIx::NumKnobs; i++)
  1025. {
  1026. controlKnobs[i]->value = controlKnobs[i]->defaultValue;
  1027. controlKnobs[i]->dirty = true;
  1028. }
  1029. // We also need to make sure our controls reset....
  1030. //Module::reset(); // Base method reset should do the knobs
  1031. //_ParentWidget->reset();
  1032. /// TODO: We should also send our new values to OSC if OSC is enabled. We would have to re-read the vals though,
  1033. /// I think the values should trigger that they changed next step()... TODO: double check that this happens
  1034. break;
  1035. default:
  1036. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_LOW
  1037. debug("Ooops - didn't handle this control message type yet %d.", recvMsg.messageType);
  1038. #endif
  1039. break;
  1040. } // end switch
  1041. } // end loop through message queue
  1042. //-- COPY / PASTE --
  1043. bool pasteCompleted = false;
  1044. if (pasteTrigger.process(params[PASTE_PARAM].value) || doPaste)
  1045. {
  1046. pasteCompleted = paste(); // Paste whatever we have if we have anything
  1047. }
  1048. else
  1049. {
  1050. // Check Copy
  1051. if (copyPatternTrigger.process(params[COPY_PATTERN_PARAM].value))
  1052. {
  1053. if (copySourcePatternIx > -1 && copySourceChannelIx == TROWA_SEQ_COPY_CHANNELIX_ALL)
  1054. {
  1055. // Clear clipboard
  1056. clearClipboard();
  1057. }
  1058. else
  1059. {
  1060. copy(currentPatternEditingIx, TROWA_SEQ_COPY_CHANNELIX_ALL);
  1061. lights[PASTE_LIGHT].value = 1; // Activate paste light to show there is something on the clipboard
  1062. pasteLight->setColor(COLOR_WHITE);
  1063. lights[COPY_PATTERN_LIGHT].value = 1; // Light up Pattern Copy as Active clipboard
  1064. lights[COPY_CHANNEL_LIGHT].value = 0; // Inactivate Gate Copy light
  1065. }
  1066. }
  1067. if (copyGateTrigger.process(params[COPY_CHANNEL_PARAM].value))
  1068. {
  1069. if (copySourcePatternIx > -1 && copySourceChannelIx > -1)
  1070. {
  1071. // Clear clipboard
  1072. clearClipboard();
  1073. }
  1074. else
  1075. {
  1076. copy(currentPatternEditingIx, currentChannelEditingIx);
  1077. lights[PASTE_LIGHT].value = 1; // Activate paste light to show there is something on the clipboard
  1078. pasteLight->setColor(voiceColors[currentChannelEditingIx]);
  1079. lights[COPY_CHANNEL_LIGHT].value = 1; // Light up Channel Copy Light as Active clipboard
  1080. copyGateLight->setColor(voiceColors[currentChannelEditingIx]); // Match the color with our Channel color
  1081. lights[COPY_PATTERN_LIGHT].value = 0; // Inactivate Pattern Copy Light
  1082. }
  1083. } // end if copyGateTrigger()
  1084. }
  1085. // Check value mode change after we have processed incoming messages.
  1086. *valueModeChanged = (lastOutputValueMode != selectedOutputValueMode);
  1087. lastOutputValueMode = selectedOutputValueMode;
  1088. // Reset
  1089. // [03/30/2018] So, now j4s0n wants RESET to wait until the next step is played...
  1090. // So it's delayed reset. https://github.com/j4s0n-c/trowaSoft-VCV/issues/11
  1091. if (resetTrigger.process(params[RESET_PARAM].value + inputs[RESET_INPUT].value) || resetMsg)
  1092. {
  1093. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  1094. debug("Reset");
  1095. #endif
  1096. resetPaused = !running;
  1097. // [03/30/2018] Delay reset until the next step. (https://github.com/j4s0n-c/trowaSoft-VCV/issues/11)
  1098. // So it's more like JUMP TO step 0 (waits until the next step).
  1099. resetQueued = true; // Flag that the reset has been queued.
  1100. } // end check for reset
  1101. if (resetQueued && nextStep) {
  1102. resetQueued = false;
  1103. realPhase = 0.0;
  1104. swingAdjustedPhase = 0; // Reset swing
  1105. index = 999;
  1106. nextStep = true;
  1107. lights[RESET_LIGHT].value = 1.0;
  1108. nextIndex = TROWA_INDEX_UNDEFINED; // Reset our jump to index
  1109. oscMutex.lock();
  1110. if (useOSC && oscInitialized)
  1111. {
  1112. osc::OutboundPacketStream oscStream(oscBuffer, OSC_OUTPUT_BUFFER_SIZE);
  1113. oscStream << osc::BeginBundleImmediate
  1114. << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayReset])
  1115. << "bang" << osc::EndMessage
  1116. << osc::EndBundle;
  1117. oscTxSocket->Send(oscStream.Data(), oscStream.Size());
  1118. }
  1119. oscMutex.unlock();
  1120. } // end if resetQueued and it's time to reset
  1121. // Next Step
  1122. if (nextStep)
  1123. {
  1124. if (nextIndex == TROWA_INDEX_UNDEFINED)
  1125. index++; // Advance step
  1126. else
  1127. {
  1128. index = nextIndex; // Set to our 'jump to' value
  1129. nextIndex = TROWA_INDEX_UNDEFINED; // Reset our jump to index
  1130. }
  1131. if (index >= currentNumberSteps || index < 0) {
  1132. index = 0; // Reset (artifical limit)
  1133. }
  1134. // Show which step we are on:
  1135. r = index / this->numCols;// TROWA_SEQ_STEP_NUM_COLS;
  1136. c = index % this->numCols; //TROWA_SEQ_STEP_NUM_COLS;
  1137. stepLights[r][c] = 1.0f;
  1138. gatePulse.trigger(TROWA_PULSE_WIDTH);
  1139. oscMutex.lock();
  1140. if (useOSC && oscInitialized)
  1141. {
  1142. // [01/06/2018] Changed to one-based for OSC (send index+1 instead of index)
  1143. osc::OutboundPacketStream oscStream(oscBuffer, OSC_OUTPUT_BUFFER_SIZE);
  1144. oscStream << osc::BeginBundleImmediate
  1145. << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayClock])
  1146. << index + 1 << osc::EndMessage
  1147. << osc::EndBundle;
  1148. oscTxSocket->Send(oscStream.Data(), oscStream.Size());
  1149. }
  1150. oscMutex.unlock();
  1151. } // end if next step
  1152. // If we were just unpaused and we were reset during the pause, make sure we fire the first step.
  1153. if (running && !lastRunning)
  1154. {
  1155. if (resetPaused)
  1156. {
  1157. gatePulse.trigger(TROWA_PULSE_WIDTH);
  1158. }
  1159. resetPaused = false;
  1160. } // end if
  1161. // Reset light
  1162. lights[RESET_LIGHT].value -= lights[RESET_LIGHT].value / lightLambda / engineGetSampleRate();
  1163. // BPM Note Calc light:
  1164. lights[SELECTED_BPM_MULT_IX_LIGHT].value -= lights[SELECTED_BPM_MULT_IX_LIGHT].value / lightLambda / engineGetSampleRate();
  1165. *pulse = gatePulse.process(engineGetSampleTime());// 1.0 / engineGetSampleRate());
  1166. editChannelChanged = currentChannelEditingIx != lastChannelIx;
  1167. editPatternChanged = currentPatternEditingIx != lastEditPatternIx;
  1168. // See if we should reload our matrix
  1169. //*reloadMatrix = currentChannelEditingIx != lastChannelIx || currentPatternEditingIx != lastEditPatternIx || pasteCompleted || this->reloadEditMatrix || firstLoad;
  1170. *reloadMatrix = editChannelChanged || editPatternChanged || pasteCompleted || this->reloadEditMatrix || firstLoad || oscStarted;
  1171. // Send messages if needed
  1172. /// TODO: Make a message sender to do this crap
  1173. oscMutex.lock();
  1174. if (useOSC && oscInitialized)
  1175. {
  1176. bool bundleOpened = false;
  1177. // If something has changed or we just started up osc, then send the status of our sequencer.
  1178. osc::OutboundPacketStream oscStream(oscBuffer, OSC_OUTPUT_BUFFER_SIZE);
  1179. if (lastRunning != running || oscStarted)
  1180. {
  1181. if (!bundleOpened)
  1182. {
  1183. oscStream << osc::BeginBundleImmediate;
  1184. bundleOpened = true;
  1185. }
  1186. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayRunningState])
  1187. << (int)(running)
  1188. << osc::EndMessage;
  1189. // Send another toggle message for touchOSC
  1190. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayToggleRun])
  1191. << (int)(running)
  1192. << osc::EndMessage;
  1193. }
  1194. if (lastPatternPlayingIx != currentPatternPlayingIx || oscStarted)
  1195. {
  1196. if (!bundleOpened)
  1197. {
  1198. oscStream << osc::BeginBundleImmediate;
  1199. bundleOpened = true;
  1200. }
  1201. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayPattern])
  1202. << (currentPatternPlayingIx + 1)
  1203. << osc::EndMessage;
  1204. }
  1205. if (playBPMChanged || oscStarted)
  1206. {
  1207. if (!bundleOpened)
  1208. {
  1209. oscStream << osc::BeginBundleImmediate;
  1210. bundleOpened = true;
  1211. }
  1212. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayBPM])
  1213. << currentBPM << this->selectedBPMNoteIx
  1214. << osc::EndMessage;
  1215. }
  1216. if (lastNumberSteps != currentNumberSteps || oscStarted)
  1217. {
  1218. if (!bundleOpened)
  1219. {
  1220. oscStream << osc::BeginBundleImmediate;
  1221. bundleOpened = true;
  1222. }
  1223. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayLength])
  1224. << currentNumberSteps
  1225. << osc::EndMessage;
  1226. } // end playLengthChanged
  1227. if (*valueModeChanged || oscStarted)
  1228. {
  1229. if (!bundleOpened)
  1230. {
  1231. oscStream << osc::BeginBundleImmediate;
  1232. bundleOpened = true;
  1233. }
  1234. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayOutputMode])
  1235. << (int)(this->selectedOutputValueMode)
  1236. << osc::EndMessage;
  1237. } // end playOutputModeChanged
  1238. if (editPatternChanged || oscStarted)
  1239. {
  1240. if (!bundleOpened)
  1241. {
  1242. oscStream << osc::BeginBundleImmediate;
  1243. bundleOpened = true;
  1244. }
  1245. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditPattern])
  1246. << (currentPatternEditingIx + 1)
  1247. << osc::EndMessage;
  1248. } // end editPatternChanged
  1249. if (editChannelChanged || oscStarted)
  1250. {
  1251. if (!bundleOpened)
  1252. {
  1253. oscStream << osc::BeginBundleImmediate;
  1254. bundleOpened = true;
  1255. }
  1256. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditChannel])
  1257. << (currentChannelEditingIx + 1)
  1258. << osc::EndMessage;
  1259. } // end editChannelChanged
  1260. if (lastBPMNoteIx != this->selectedBPMNoteIx || oscStarted)
  1261. {
  1262. if (!bundleOpened)
  1263. {
  1264. oscStream << osc::BeginBundleImmediate;
  1265. bundleOpened = true;
  1266. }
  1267. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayBPMNote])
  1268. << selectedBPMNoteIx
  1269. << osc::EndMessage;
  1270. } // end bpmNoteChanged
  1271. if (storedPatternChanged || oscStarted)
  1272. {
  1273. if (!bundleOpened)
  1274. {
  1275. oscStream << osc::BeginBundleImmediate;
  1276. bundleOpened = true;
  1277. }
  1278. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayPatternSav])
  1279. << ((storedPatternPlayingIx > -1) ? storedPatternPlayingIx + 1 : currentPatternPlayingIx + 1)
  1280. << osc::EndMessage;
  1281. } // end storedPatternChanged
  1282. if (storedLengthChanged || oscStarted)
  1283. {
  1284. if (!bundleOpened)
  1285. {
  1286. oscStream << osc::BeginBundleImmediate;
  1287. bundleOpened = true;
  1288. }
  1289. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayLengthSav])
  1290. << ((storedNumberSteps > 0) ? storedNumberSteps : currentNumberSteps)
  1291. << osc::EndMessage;
  1292. } // end storedPatternChanged
  1293. if (storedBPMChanged || oscStarted)
  1294. {
  1295. if (!bundleOpened)
  1296. {
  1297. oscStream << osc::BeginBundleImmediate;
  1298. bundleOpened = true;
  1299. }
  1300. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::PlayBPMSav])
  1301. << ((storedBPM > 0) ? storedBPM : (int)(currentBPM))
  1302. << osc::EndMessage;
  1303. }
  1304. if (copySourcePatternIx != prevCopyPatternIx || copySourceChannelIx != prevCopyChannelIx || oscStarted)
  1305. {
  1306. // Clipboard has changed
  1307. if (!bundleOpened)
  1308. {
  1309. oscStream << osc::BeginBundleImmediate;
  1310. bundleOpened = true;
  1311. }
  1312. if (copySourcePatternIx == TROWA_INDEX_UNDEFINED)
  1313. {
  1314. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  1315. debug("Sending Clear Clipboard: %s %d.", oscAddrBuffer[SeqOSCOutputMsg::EditChannelCpyCurr], 0);
  1316. #endif
  1317. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditClipboard])
  1318. << 0
  1319. << 0
  1320. << osc::EndMessage;
  1321. // Clipboard was cleared
  1322. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditChannelCpyCurr])
  1323. << 0
  1324. << osc::EndMessage;
  1325. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditPatternCpyCurr])
  1326. << 0
  1327. << osc::EndMessage;
  1328. }
  1329. else
  1330. {
  1331. // Send clipboard message (pattern, channel)
  1332. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditClipboard])
  1333. << (copySourcePatternIx + 1)
  1334. << (copySourceChannelIx + 1)
  1335. << osc::EndMessage;
  1336. if (copySourceChannelIx == TROWA_SEQ_COPY_CHANNELIX_ALL)
  1337. {
  1338. // Pattern copied (pattern)
  1339. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  1340. debug("Sending Copied Pattern: %s %d.", oscAddrBuffer[SeqOSCOutputMsg::EditPatternCpyCurr], (copySourcePatternIx + 1));
  1341. #endif
  1342. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditPatternCpyCurr])
  1343. << (copySourcePatternIx + 1)
  1344. << osc::EndMessage;
  1345. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditChannelCpyCurr])
  1346. << 0
  1347. << osc::EndMessage;
  1348. }
  1349. else
  1350. {
  1351. // Channel copied (channel)
  1352. #if TROWA_DEBUG_MSGS >= TROWA_DEBUG_LVL_MED
  1353. debug("Sending Copied Channel: %s %d.", oscAddrBuffer[SeqOSCOutputMsg::EditChannelCpyCurr], (copySourceChannelIx + 1));
  1354. #endif
  1355. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditPatternCpyCurr])
  1356. << 0
  1357. << osc::EndMessage;
  1358. oscStream << osc::BeginMessage(oscAddrBuffer[SeqOSCOutputMsg::EditChannelCpyCurr])
  1359. << (copySourceChannelIx + 1)
  1360. << osc::EndMessage;
  1361. }
  1362. }// end else
  1363. } // end if clipboard change
  1364. #if OSC_UPDATE_CURRENT_STEP_LED
  1365. if (lastStepIndex != index)
  1366. {
  1367. // Turn off last led, turn on this led
  1368. if (!bundleOpened)
  1369. {
  1370. oscStream << osc::BeginBundleImmediate;
  1371. bundleOpened = true;
  1372. }
  1373. char addrBuff[50] = { 0 };
  1374. // Prev step should turn off:
  1375. sprintf(addrBuff, oscAddrBuffer[SeqOSCOutputMsg::PlayStepLed], lastStepIndex + 1);
  1376. oscStream << osc::BeginMessage(addrBuff)
  1377. << 0
  1378. << osc::EndMessage;
  1379. // Current step should turn on:
  1380. sprintf(addrBuff, oscAddrBuffer[SeqOSCOutputMsg::PlayStepLed], index + 1);
  1381. oscStream << osc::BeginMessage(addrBuff)
  1382. << 1
  1383. << osc::EndMessage;
  1384. }
  1385. #endif
  1386. //--- FINISH BUNDLE ---
  1387. if (bundleOpened)
  1388. {
  1389. // Finish and send
  1390. oscStream << osc::EndBundle;
  1391. oscTxSocket->Send(oscStream.Data(), oscStream.Size());
  1392. }
  1393. } // end send osc
  1394. oscMutex.unlock();
  1395. firstLoad = false;
  1396. return;
  1397. } // end getStepInputs()
  1398. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1399. // toJson(void)
  1400. // Save our junk to json.
  1401. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1402. json_t *TSSequencerModuleBase::toJson() {
  1403. json_t *rootJ = json_object();
  1404. // version
  1405. json_object_set_new(rootJ, "version", json_integer(TROWA_INTERNAL_VERSION_INT));
  1406. // running
  1407. json_object_set_new(rootJ, "running", json_boolean(running));
  1408. // Current Items:
  1409. json_object_set_new(rootJ, "currentPatternEditIx", json_integer((int)currentPatternEditingIx));
  1410. json_object_set_new(rootJ, "currentTriggerEditIx", json_integer((int)currentChannelEditingIx));
  1411. // The current output / knob mode.
  1412. json_object_set_new(rootJ, "selectedOutputValueMode", json_integer((int)selectedOutputValueMode));
  1413. // Current BPM calculation note (i.e. 1/4, 1/8, 1/8T, 1/16)
  1414. json_object_set_new(rootJ, "selectedBPMNoteIx", json_integer((int)selectedBPMNoteIx));
  1415. // triggers
  1416. json_t *triggersJ = json_array();
  1417. for (int p = 0; p < TROWA_SEQ_NUM_PATTERNS; p++)
  1418. {
  1419. for (int t = 0; t < TROWA_SEQ_NUM_CHNLS; t++)
  1420. {
  1421. for (int s = 0; s < maxSteps; s++)
  1422. {
  1423. json_t *gateJ = json_real((float)triggerState[p][t][s]);
  1424. json_array_append_new(triggersJ, gateJ);
  1425. } // end for (steps)
  1426. } // end for (triggers)
  1427. } // end for (patterns)
  1428. json_object_set_new(rootJ, "triggers", triggersJ);
  1429. // gateMode
  1430. json_t *gateModeJ = json_integer((int)gateMode);
  1431. json_object_set_new(rootJ, "gateMode", gateModeJ);
  1432. // OSC Parameters
  1433. json_t* oscJ = json_object();
  1434. json_object_set_new(oscJ, "IpAddress", json_string(this->currentOSCSettings.oscTxIpAddress.c_str()));
  1435. json_object_set_new(oscJ, "TxPort", json_integer(this->currentOSCSettings.oscTxPort));
  1436. json_object_set_new(oscJ, "RxPort", json_integer(this->currentOSCSettings.oscRxPort));
  1437. json_object_set_new(oscJ, "Client", json_integer(this->oscCurrentClient));
  1438. json_object_set_new(oscJ, "AutoReconnectAtLoad", json_boolean(oscReconnectAtLoad)); // [v11, v0.6.3]
  1439. json_object_set_new(oscJ, "Initialized", json_boolean(oscInitialized)); // [v11, v0.6.3] We know the settings are good at least at the time of save
  1440. json_object_set_new(rootJ, "osc", oscJ);
  1441. return rootJ;
  1442. } // end toJson()
  1443. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1444. // fromJson(void)
  1445. // Read in our junk from json.
  1446. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  1447. void TSSequencerModuleBase::fromJson(json_t *rootJ) {
  1448. // running
  1449. json_t *runningJ = json_object_get(rootJ, "running");
  1450. if (runningJ)
  1451. running = json_is_true(runningJ);
  1452. // Current Items:
  1453. json_t *currJ = NULL;
  1454. currJ = json_object_get(rootJ, "currentPatternEditIx");
  1455. if (currJ)
  1456. currentPatternEditingIx = json_integer_value(currJ);
  1457. currJ = json_object_get(rootJ, "currentTriggerEditIx");
  1458. if (currJ)
  1459. currentChannelEditingIx = json_integer_value(currJ);
  1460. currJ = json_object_get(rootJ, "selectedOutputValueMode");
  1461. if (currJ)
  1462. {
  1463. selectedOutputValueMode = static_cast<ValueMode>(json_integer_value(currJ));
  1464. modeString = modeStrings[selectedOutputValueMode];
  1465. }
  1466. // Current BPM calculation note (i.e. 1/4, 1/8, 1/8T, 1/16)
  1467. currJ = json_object_get(rootJ, "selectedBPMNoteIx");
  1468. if (currJ)
  1469. selectedBPMNoteIx = json_integer_value(currJ);
  1470. // triggers
  1471. json_t *triggersJ = json_object_get(rootJ, "triggers");
  1472. if (triggersJ)
  1473. {
  1474. int i = 0;
  1475. for (int p = 0; p < TROWA_SEQ_NUM_PATTERNS; p++)
  1476. {
  1477. for (int t = 0; t < TROWA_SEQ_NUM_CHNLS; t++)
  1478. {
  1479. for (int s = 0; s < maxSteps; s++)
  1480. {
  1481. json_t *gateJ = json_array_get(triggersJ, i++);
  1482. if (gateJ)
  1483. triggerState[p][t][s] = (float)json_real_value(gateJ);
  1484. } // end for (steps)
  1485. } // end for (triggers)
  1486. } // end for (patterns)
  1487. }
  1488. // gateMode
  1489. json_t *gateModeJ = json_object_get(rootJ, "gateMode");
  1490. if (gateModeJ)
  1491. gateMode = (GateMode)json_integer_value(gateModeJ);
  1492. json_t* oscJ = json_object_get(rootJ, "osc");
  1493. if (oscJ)
  1494. {
  1495. currJ = json_object_get(oscJ, "IpAddress");
  1496. if (currJ)
  1497. this->currentOSCSettings.oscTxIpAddress = json_string_value(currJ);
  1498. currJ = json_object_get(oscJ, "TxPort");
  1499. if (currJ)
  1500. this->currentOSCSettings.oscTxPort = (uint16_t)(json_integer_value(currJ));
  1501. currJ = json_object_get(oscJ, "RxPort");
  1502. if (currJ)
  1503. this->currentOSCSettings.oscRxPort = (uint16_t)(json_integer_value(currJ));
  1504. currJ = json_object_get(oscJ, "Client");
  1505. if (currJ)
  1506. this->oscCurrentClient = static_cast<OSCClient>((uint8_t)(json_integer_value(currJ)));
  1507. currJ = json_object_get(oscJ, "AutoReconnectAtLoad");
  1508. if (currJ)
  1509. oscReconnectAtLoad = json_boolean_value(currJ);
  1510. if (oscReconnectAtLoad)
  1511. {
  1512. currJ = json_object_get(oscJ, "Initialized");
  1513. if (currJ && json_boolean_value(currJ))
  1514. {
  1515. oscCurrentAction = OSCAction::Enable; // Will enable at next step
  1516. //// Try to reconnect
  1517. //cleanupOSC();
  1518. //this->initOSC(this->currentOSCSettings.oscTxIpAddress.c_str(), this->currentOSCSettings.oscTxPort, this->currentOSCSettings.oscRxPort);
  1519. //if (oscError || !oscInitialized)
  1520. //{
  1521. // warn("TSSequencerModuleBase::fromJson(): Error on auto-reconnect OSC %s :%d :%d.", this->currentOSCSettings.oscTxIpAddress.c_str(), this->currentOSCSettings.oscTxPort, this->currentOSCSettings.oscRxPort);
  1522. //}
  1523. //else
  1524. //{
  1525. // info("TSSequencerModuleBase::fromJson(): Successful auto-reconnection of OSC %s :%d :%d.", this->currentOSCSettings.oscTxIpAddress.c_str(), this->currentOSCSettings.oscTxPort, this->currentOSCSettings.oscRxPort);
  1526. //}
  1527. }
  1528. }
  1529. }
  1530. saveVersion = 0;
  1531. currJ = NULL;
  1532. currJ = json_object_get(rootJ, "version");
  1533. if (currJ)
  1534. {
  1535. saveVersion = (int)(json_integer_value(currJ));
  1536. }
  1537. firstLoad = true;
  1538. return;
  1539. } // end fromJson()