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.

566 lines
14KB

  1. #pragma once
  2. #ifdef LAUNCHPAD
  3. #include "communicator.hpp"
  4. // The interface for driving the Novation Launchpad Pro
  5. class ILaunchpadPro
  6. {
  7. public:
  8. static LaunchpadKey RC2Key(int r, int c) { return (LaunchpadKey)(R8C1 + c + 10 * (7 - r)); }
  9. static bool IsPlayKey(LaunchpadKey key) // true if key is a squared key (not a function key!)
  10. {
  11. if(key >= R8C1 && key <= R1C8)
  12. {
  13. int v = ((int)key - 1) % 10;
  14. return v < 8;
  15. }
  16. return false;
  17. }
  18. static bool Key2RC(LaunchpadKey key, int *r, int *c)
  19. {
  20. if(IsPlayKey(key))
  21. {
  22. int v = (int)key - 1;
  23. int n = v / 10;
  24. *c = v % 10;
  25. *r = 8 - n;
  26. return true;
  27. }
  28. return false;
  29. }
  30. static bool IsValidkey(LaunchpadKey key)
  31. {
  32. return key >= RECORD_ARM
  33. && key != reserved_unused0
  34. && key != reserved_unused1;
  35. }
  36. static LaunchpadMessage *Led(LaunchpadMessage *dest, LaunchpadKey key, LaunchpadLed led)
  37. {
  38. switch(led.status)
  39. {
  40. case ButtonColorType::Normal: LedColor(dest, key, led.r_color); break;
  41. case ButtonColorType::RGB: LedRGB(dest, key, led.r_color, led.g, led.b); break;
  42. case ButtonColorType::Flash: LedFlash(dest, key, led.r_color); break;
  43. case ButtonColorType::Pulse: LedPulse(dest, key, led.r_color); break;
  44. }
  45. return dest;
  46. }
  47. static LaunchpadMessage *Led(LaunchpadMessage *dest, int r, int c, LaunchpadLed led) { return Led(dest, RC2Key(r, c), led); }
  48. static LaunchpadMessage *LedOff(LaunchpadMessage *dest, int r, int c) { return LedOff(dest, RC2Key(r, c)); }
  49. static LaunchpadMessage *LedOff(LaunchpadMessage *dest, LaunchpadKey key) { return LedColor(dest, key, 0); }
  50. static LaunchpadMessage *LedColor(LaunchpadMessage *dest, LaunchpadKey key, int color)
  51. {
  52. dest->key = key;
  53. dest->cmd = KEYON;
  54. dest->param0 = color & 0x3f;
  55. return dest;
  56. }
  57. static LaunchpadMessage *LedColor(LaunchpadMessage *dest, int r, int c, int color) { return LedColor(dest, RC2Key(r, c), color); }
  58. static LaunchpadMessage *RegisterScene(LaunchpadMessage *dest, LaunchpadScene scene, bool registr)
  59. {
  60. dest->cmd = REGISTERSCENE;
  61. dest->currentScene = SceneAll;
  62. dest->param0 = registr ? 1 : 0;
  63. dest->param1 = scene;
  64. return dest;
  65. }
  66. static LaunchpadMessage *SetScene(LaunchpadMessage *dest, LaunchpadScene scene)
  67. {
  68. dest->cmd = SETSCENE;
  69. dest->currentScene = scene;
  70. return dest;
  71. }
  72. static LaunchpadMessage *GetNumLaunchpads(LaunchpadMessage *dest)
  73. {
  74. dest->currentScene = SceneAll;
  75. dest->cmd = GETNUMLAUNCHPADS;
  76. return dest;
  77. }
  78. static LaunchpadMessage *SetStandaloneMode(LaunchpadMessage *dest, LaunchpadMode mode)
  79. {
  80. dest->cmd = SET_STANDALONE_MODE;
  81. dest->param0 = mode;
  82. return dest;
  83. }
  84. static LaunchpadMessage *SetLiveMode(LaunchpadMessage *dest, LaunchpadLiveMode mode)
  85. {
  86. dest->cmd = SET_LIVE_MODE;
  87. dest->param0 = mode;
  88. return dest;
  89. }
  90. static LaunchpadMessage *SetStatus(LaunchpadMessage *dest, LaunchpadStatus status)
  91. {
  92. dest->cmd = SETSTATUS;
  93. dest->param0 = status;
  94. return dest;
  95. }
  96. static LaunchpadMessage *SideLed(LaunchpadMessage *dest, int color)
  97. {
  98. dest->cmd = SIDE_LED;
  99. dest->param0 = color & 0x3f;
  100. return dest;
  101. }
  102. static LaunchpadMessage *LightAll(LaunchpadMessage *dest, int color)
  103. {
  104. dest->cmd = LED_ALL;
  105. dest->param0 = color & 0x3f;
  106. return dest;
  107. }
  108. static LaunchpadMessage *LedFlash(LaunchpadMessage *dest, LaunchpadKey key, int color)
  109. {
  110. dest->key = key;
  111. dest->cmd = FLASH_KEY;
  112. dest->param0 = color & 0x3f;
  113. return dest;
  114. }
  115. static LaunchpadMessage *LedFlash(LaunchpadMessage *dest, int r, int c, int color) { return LedFlash(dest, RC2Key(r, c), color); }
  116. static LaunchpadMessage *LedPulse(LaunchpadMessage *dest, LaunchpadKey key, int color)
  117. {
  118. dest->key = key;
  119. dest->cmd = PULSE_KEY;
  120. dest->param0 = color & 0x3f;
  121. return dest;
  122. }
  123. static LaunchpadMessage *LedPulse(LaunchpadMessage *dest, int r, int c, int color) { return LedPulse(dest, RC2Key(r, c), color); }
  124. static LaunchpadMessage *LedRGB(LaunchpadMessage *dest, LaunchpadKey key, int c_r, int c_g, int c_b)
  125. {
  126. dest->key = key;
  127. dest->cmd = LED_RGB;
  128. dest->param0 = ((c_r & 0x3f) << 8) | (c_g & 0x3f); // R,G
  129. dest->param1 = (c_b & 0x3f); // B
  130. return dest;
  131. }
  132. static LaunchpadMessage *LedRGB(LaunchpadMessage *dest, int r, int c, int c_r, int c_g, int c_b) { return LedRGB(dest, RC2Key(r, c), c_r, c_g, c_b); }
  133. };
  134. class launchpadDriver
  135. {
  136. // uses keys SESSION, NOTE, DEVICE, USER
  137. // as page keys
  138. public:
  139. static const int ALL_PAGES = -1;
  140. launchpadDriver(LaunchpadScene scene, int maxPage)
  141. {
  142. comm = new communicator();
  143. numPages = maxPage;
  144. myScene = scene;
  145. Reset(ALL_LAUNCHPADS);
  146. lastCheck = 0;
  147. currentPage = 0;
  148. registerMyScene(true);
  149. }
  150. ~launchpadDriver()
  151. {
  152. registerMyScene(false);
  153. delete comm;
  154. }
  155. bool Connected() { return comm->Connected(); }
  156. void LedRGB(int lp, int page, int r, int c, int c_r, int c_g, int c_b) { return LedRGB(lp, page, ILaunchpadPro::RC2Key(r, c), c_r, c_g, c_b); }
  157. void LedPulse(int lp, int page, int r, int c, int color) { return LedPulse(lp, page, ILaunchpadPro::RC2Key(r, c), color); }
  158. void LedColor(int lp, int page, int r, int c, int color) { return LedColor(lp, page, ILaunchpadPro::RC2Key(r, c), color); }
  159. void LedFlash(int lp, int page, int r, int c, int color) { return LedFlash(lp, page, ILaunchpadPro::RC2Key(r, c), color); }
  160. void Led(int lp, int page, int r, int c, LaunchpadLed led) { return Led(lp, page, ILaunchpadPro::RC2Key(r, c), led); }
  161. void Led(int lp, int page, LaunchpadKey key, LaunchpadLed led) { setValue(lp, page, key, led); }
  162. void LedColor(int lp, int page, LaunchpadKey key, int colr)
  163. {
  164. LaunchpadLed led;
  165. led.status = ButtonColorType::Normal;
  166. led.r_color = colr;
  167. Led(lp, page, key, led);
  168. }
  169. void LedFlash(int lp, int page, LaunchpadKey key, int colr)
  170. {
  171. LaunchpadLed led;
  172. led.status = ButtonColorType::Flash;
  173. led.r_color = colr;
  174. Led(lp, page, key, led);
  175. }
  176. void LedPulse(int lp, int page, LaunchpadKey key, int colr)
  177. {
  178. LaunchpadLed led;
  179. led.status = ButtonColorType::Pulse;
  180. led.r_color = colr;
  181. Led(lp, page, key, led);
  182. }
  183. void LedRGB(int lp, int page, LaunchpadKey key, int c_r, int c_g, int c_b)
  184. {
  185. LaunchpadLed led;
  186. led.status = ButtonColorType::RGB;
  187. led.r_color = c_r;
  188. led.g = c_g;
  189. led.b = c_b;
  190. Led(lp, page, key, led);
  191. }
  192. int GetPage() { return currentPage; }
  193. void SetPage(int page)
  194. {
  195. if(page >= 0 && page < numPages && currentPage != page)
  196. {
  197. currentPage = page;
  198. Clear(ALL_LAUNCHPADS);
  199. redrawCache();
  200. }
  201. }
  202. void Clear(int lp)
  203. {
  204. LaunchpadMessage dest;
  205. ILaunchpadPro::LightAll(&dest, 0);
  206. dest.currentScene = myScene;
  207. dest.lpNumber = lp;
  208. comm->Write(dest);
  209. }
  210. void Reset(int lp)
  211. {
  212. SetPage(0);
  213. Clear(lp);
  214. comm->clear();
  215. }
  216. int GetNumLaunchpads() // SYNC read
  217. {
  218. LaunchpadMessage dest;
  219. ILaunchpadPro::GetNumLaunchpads(&dest);
  220. comm->Write(dest);
  221. LaunchpadMessage rcv;
  222. if(syncRead(&rcv, LaunchpadCommand::GETNUMLAUNCHPADS))
  223. return rcv.lpNumber;
  224. return 0;
  225. }
  226. void SetAutoPageKey(LaunchpadKey key, int page)
  227. {
  228. if(page >= 0 && page < numPages)
  229. {
  230. autoPages[key] = page;
  231. } else if(page == -1) // remove key?
  232. {
  233. auto it = autoPages.find(key);
  234. if(it != autoPages.end())
  235. autoPages.erase(it);
  236. }
  237. }
  238. void drive_led(int lp, LaunchpadKey key, LaunchpadLed led)
  239. {
  240. LaunchpadMessage dest;
  241. ILaunchpadPro::Led(&dest, key, led);
  242. dest.currentScene = myScene;
  243. dest.lpNumber = lp;
  244. comm->Write(dest);
  245. }
  246. protected:
  247. int numPages;
  248. int currentPage;
  249. LaunchpadScene myScene;
  250. communicator *comm;
  251. virtual void redrawCache() { drive_autopage(); };
  252. void setValue(int lp, int page, LaunchpadKey key, LaunchpadLed led)
  253. {
  254. if(page == currentPage || page == launchpadDriver::ALL_PAGES)
  255. drive_led(lp, key, led);
  256. }
  257. int isAutoPageKey(LaunchpadMessage *msg)
  258. {
  259. if(msg->cmd == LaunchpadCommand::KEYON)
  260. {
  261. auto it = autoPages.find(msg->key);
  262. if(it != autoPages.end())
  263. return it->second;
  264. }
  265. return -1;
  266. }
  267. bool syncRead(LaunchpadMessage *rv, LaunchpadCommand waitCmd, int timeout = 1000)
  268. {
  269. DWORD now = GetTickCount();
  270. LaunchpadMessage msg;
  271. do
  272. {
  273. msg = comm->Read();
  274. if(msg.cmd == waitCmd)
  275. {
  276. memcpy(rv, &msg, sizeof(msg));
  277. return true;
  278. }
  279. } while((GetTickCount() - now) <= (DWORD)timeout);
  280. return false;
  281. }
  282. void registerMyScene(bool registr)
  283. {
  284. lastCheck = GetTickCount();
  285. LaunchpadMessage dest;
  286. ILaunchpadPro::RegisterScene(&dest, myScene, registr);
  287. dest.lpNumber = ALL_LAUNCHPADS;
  288. if(comm->Open())
  289. {
  290. comm->Write(dest);
  291. if(registr)
  292. SetPage(0);
  293. comm->Write(dest);
  294. }
  295. }
  296. uint32_t lastCheck;
  297. private:
  298. void drive_autopage()
  299. {
  300. for(std::map<LaunchpadKey, int>::iterator it = autoPages.begin(); it != autoPages.end(); ++it)
  301. {
  302. for(int k = 0; k < numPages; k++)
  303. {
  304. LaunchpadMessage dest;
  305. ILaunchpadPro::Led(&dest, it->first, LaunchpadLed::Color(it->second == currentPage ? 57 : 11));
  306. comm->Write(dest);
  307. }
  308. }
  309. }
  310. private:
  311. std::map<LaunchpadKey, int> autoPages;
  312. };
  313. struct launchpadControl
  314. {
  315. public:
  316. virtual ~launchpadControl() {};
  317. void Draw(launchpadDriver *drv, bool force = false)
  318. {
  319. if((force || m_dirty) && (drv->GetPage() == m_page || m_page == launchpadDriver::ALL_PAGES))
  320. {
  321. draw(drv);
  322. }
  323. m_dirty = false;
  324. m_lastDrawnValue = getValue();
  325. }
  326. bool Intersect(int lp, int page, LaunchpadKey key, bool shift)
  327. {
  328. if(m_shifted == shift)
  329. {
  330. if(page == m_page || page == launchpadDriver::ALL_PAGES || m_page == launchpadDriver::ALL_PAGES)
  331. {
  332. if(lp == m_lpNumber || lp == ALL_LAUNCHPADS || m_lpNumber == ALL_LAUNCHPADS)
  333. return intersect(key);
  334. }
  335. }
  336. return false;
  337. }
  338. void ChangeFromGUI(launchpadDriver *drv) // gui updated: the new value is already in the binded parameter
  339. {
  340. m_dirty = true;
  341. Draw(drv);
  342. }
  343. virtual void onLaunchpadKey(Module *pModule, LaunchpadMessage msg) = 0;
  344. bool DetectGUIChanges() { return getValue() != m_lastDrawnValue; }
  345. int ID() { return is_light ? pBindedLight->firstLightId : pBindedParam->paramId; }
  346. void bindWidget(ModuleLightWidget *p) { pBindedLight = p; is_light = true; }
  347. void bindWidget(ParamWidget *p) { pBindedParam = p; }
  348. protected:
  349. virtual void draw(launchpadDriver *drv) = 0;
  350. virtual bool intersect(LaunchpadKey key) { return false; }
  351. launchpadControl(int lp, int page, LaunchpadKey key, bool shifted)
  352. {
  353. m_lpNumber = lp;
  354. is_light = false;
  355. m_page = page;
  356. m_key = key;
  357. m_shifted = shifted;
  358. pBindedLight = NULL;
  359. pBindedParam = NULL;
  360. m_dirty = true;
  361. m_lastDrawnValue = -10202020;
  362. }
  363. float getValue() { return is_light ? pBindedLight->module->lights[pBindedLight->firstLightId].getBrightness() : pBindedParam->value; }
  364. void setValue(Module *pModule, float v)
  365. {
  366. if(v != getValue())
  367. {
  368. if(is_light)
  369. pBindedLight->module->lights[pBindedLight->firstLightId].value = v;
  370. else
  371. {
  372. SVGKnob *pk = (SVGKnob *)dynamic_cast<SVGKnob *>(pBindedParam);
  373. if(pk != NULL)
  374. {
  375. pModule->params[pBindedParam->paramId].value = pBindedParam->value = v;
  376. pk->dirty = true;
  377. } else
  378. {
  379. SVGFader *pk1 = (SVGFader *)dynamic_cast<SVGFader *>(pBindedParam);
  380. if(pk1 != NULL)
  381. {
  382. pModule->params[pBindedParam->paramId].value = pBindedParam->value = v;
  383. pk1->dirty = true;
  384. } else
  385. pBindedParam->setValue(v);
  386. }
  387. }
  388. m_dirty = true;
  389. }
  390. }
  391. int m_lpNumber;
  392. int m_page;
  393. bool is_light;
  394. LaunchpadKey m_key;
  395. bool m_shifted;
  396. ModuleLightWidget *pBindedLight;
  397. ParamWidget *pBindedParam;
  398. bool m_dirty;
  399. float m_lastDrawnValue;
  400. };
  401. struct LaunchpadBindingDriver : public launchpadDriver
  402. {
  403. public:
  404. LaunchpadBindingDriver(Module *pMod, LaunchpadScene scene, int maxPage) : launchpadDriver(scene, maxPage)
  405. {
  406. pModule = pMod;
  407. }
  408. virtual ~LaunchpadBindingDriver()
  409. {
  410. for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
  411. {
  412. if(it->second != NULL)
  413. delete it->second;
  414. }
  415. m_bindings.clear();
  416. }
  417. void Add(launchpadControl *ctrl, ParamWidget *p)
  418. {
  419. ctrl->bindWidget(p);
  420. int id = ctrl->ID();
  421. m_bindings[id] = ctrl;
  422. #ifdef DEBUG
  423. info("binded param %i ", id);
  424. #endif
  425. }
  426. void Add(launchpadControl *ctrl, ModuleLightWidget *p)
  427. {
  428. ctrl->bindWidget(p);
  429. int id = ctrl->ID();
  430. m_bindings[0x8000 | id] = ctrl;
  431. #ifdef DEBUG
  432. info("binded light %i ", 0x8000 | id);
  433. #endif
  434. }
  435. void ProcessLaunchpad()
  436. {
  437. processGUI();
  438. processLaunchpadKeys();
  439. if(!Connected() && (GetTickCount() - lastCheck) >= 2000)
  440. {
  441. registerMyScene(true);
  442. }
  443. }
  444. protected:
  445. virtual void redrawCache() override
  446. {
  447. for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
  448. {
  449. it->second->Draw(this, true);
  450. }
  451. launchpadDriver::redrawCache();
  452. }
  453. private:
  454. Module *pModule;
  455. std::map<int, launchpadControl *>m_bindings;
  456. void processGUI()
  457. {
  458. for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
  459. {
  460. if(it->second->DetectGUIChanges())
  461. {
  462. it->second->ChangeFromGUI(this);
  463. }
  464. }
  465. }
  466. void processLaunchpadKeys()
  467. {
  468. LaunchpadMessage msg;
  469. do
  470. {
  471. msg = comm->Read();
  472. if(msg.status != LaunchpadKeyStatus::keyNone && (msg.currentScene == SceneAll || msg.currentScene == myScene))
  473. {
  474. int page = isAutoPageKey(&msg);
  475. #ifdef DEBUG
  476. info("MSG: from LP=%i %i scene=%i ispage=%i key=%i", msg.lpNumber, msg.cmd, msg.currentScene, page, msg.key);
  477. #endif
  478. if(page >= 0 && msg.status == LaunchpadKeyStatus::keyDown && !msg.shiftDown)
  479. {
  480. SetPage(page);
  481. } else if(msg.cmd == LaunchpadCommand::RESET)
  482. {
  483. SetPage(currentPage);
  484. } else if(msg.cmd == LaunchpadCommand::SETSCENE)
  485. {
  486. #ifdef DEBUG
  487. info("MSG: set scene=%i myscene=%i", msg.param1, myScene);
  488. #endif
  489. if(myScene == msg.param1)
  490. {
  491. redrawCache();
  492. }
  493. } else
  494. {
  495. for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
  496. {
  497. if(it->second->Intersect(msg.lpNumber, GetPage(), msg.key, msg.shiftDown))
  498. {
  499. #ifdef DEBUG
  500. info("MSG: lp#=%i page=%i, key=%i shift=%i detected: %i", msg.lpNumber, GetPage(), msg.key, msg.shiftDown, it->first);
  501. #endif
  502. it->second->onLaunchpadKey(pModule, msg);
  503. }
  504. }
  505. }
  506. }
  507. } while(msg.status != LaunchpadKeyStatus::keyNone);
  508. }
  509. };
  510. #endif