|
- #pragma once
- #ifdef LAUNCHPAD
- #include "communicator.hpp"
-
- // The interface for driving the Novation Launchpad Pro
- class ILaunchpadPro
- {
- public:
- static LaunchpadKey RC2Key(int r, int c) { return (LaunchpadKey)(R8C1 + c + 10 * (7 - r)); }
- static bool IsPlayKey(LaunchpadKey key) // true if key is a squared key (not a function key!)
- {
- if(key >= R8C1 && key <= R1C8)
- {
- int v = ((int)key - 1) % 10;
- return v < 8;
- }
-
- return false;
- }
-
- static bool Key2RC(LaunchpadKey key, int *r, int *c)
- {
- if(IsPlayKey(key))
- {
- int v = (int)key - 1;
- int n = v / 10;
- *c = v % 10;
- *r = 8 - n;
-
- return true;
- }
-
- return false;
- }
- static bool IsValidkey(LaunchpadKey key)
- {
- return key >= RECORD_ARM
- && key != reserved_unused0
- && key != reserved_unused1;
- }
-
- static LaunchpadMessage *Led(LaunchpadMessage *dest, LaunchpadKey key, LaunchpadLed led)
- {
- switch(led.status)
- {
- case ButtonColorType::Normal: LedColor(dest, key, led.r_color); break;
- case ButtonColorType::RGB: LedRGB(dest, key, led.r_color, led.g, led.b); break;
- case ButtonColorType::Flash: LedFlash(dest, key, led.r_color); break;
- case ButtonColorType::Pulse: LedPulse(dest, key, led.r_color); break;
- }
- return dest;
- }
- static LaunchpadMessage *Led(LaunchpadMessage *dest, int r, int c, LaunchpadLed led) { return Led(dest, RC2Key(r, c), led); }
- static LaunchpadMessage *LedOff(LaunchpadMessage *dest, int r, int c) { return LedOff(dest, RC2Key(r, c)); }
- static LaunchpadMessage *LedOff(LaunchpadMessage *dest, LaunchpadKey key) { return LedColor(dest, key, 0); }
- static LaunchpadMessage *LedColor(LaunchpadMessage *dest, LaunchpadKey key, int color)
- {
- dest->key = key;
- dest->cmd = KEYON;
- dest->param0 = color & 0x3f;
- return dest;
- }
- static LaunchpadMessage *LedColor(LaunchpadMessage *dest, int r, int c, int color) { return LedColor(dest, RC2Key(r, c), color); }
-
- static LaunchpadMessage *RegisterScene(LaunchpadMessage *dest, LaunchpadScene scene, bool registr)
- {
- dest->cmd = REGISTERSCENE;
- dest->currentScene = SceneAll;
- dest->param0 = registr ? 1 : 0;
- dest->param1 = scene;
- return dest;
- }
- static LaunchpadMessage *SetScene(LaunchpadMessage *dest, LaunchpadScene scene)
- {
- dest->cmd = SETSCENE;
- dest->currentScene = scene;
- return dest;
- }
- static LaunchpadMessage *GetNumLaunchpads(LaunchpadMessage *dest)
- {
- dest->currentScene = SceneAll;
- dest->cmd = GETNUMLAUNCHPADS;
- return dest;
- }
- static LaunchpadMessage *SetStandaloneMode(LaunchpadMessage *dest, LaunchpadMode mode)
- {
- dest->cmd = SET_STANDALONE_MODE;
- dest->param0 = mode;
- return dest;
- }
-
- static LaunchpadMessage *SetLiveMode(LaunchpadMessage *dest, LaunchpadLiveMode mode)
- {
- dest->cmd = SET_LIVE_MODE;
- dest->param0 = mode;
- return dest;
- }
-
- static LaunchpadMessage *SetStatus(LaunchpadMessage *dest, LaunchpadStatus status)
- {
- dest->cmd = SETSTATUS;
- dest->param0 = status;
- return dest;
- }
-
- static LaunchpadMessage *SideLed(LaunchpadMessage *dest, int color)
- {
- dest->cmd = SIDE_LED;
- dest->param0 = color & 0x3f;
- return dest;
- }
-
- static LaunchpadMessage *LightAll(LaunchpadMessage *dest, int color)
- {
- dest->cmd = LED_ALL;
- dest->param0 = color & 0x3f;
- return dest;
- }
-
- static LaunchpadMessage *LedFlash(LaunchpadMessage *dest, LaunchpadKey key, int color)
- {
- dest->key = key;
- dest->cmd = FLASH_KEY;
- dest->param0 = color & 0x3f;
- return dest;
- }
- static LaunchpadMessage *LedFlash(LaunchpadMessage *dest, int r, int c, int color) { return LedFlash(dest, RC2Key(r, c), color); }
-
- static LaunchpadMessage *LedPulse(LaunchpadMessage *dest, LaunchpadKey key, int color)
- {
- dest->key = key;
- dest->cmd = PULSE_KEY;
- dest->param0 = color & 0x3f;
- return dest;
- }
- static LaunchpadMessage *LedPulse(LaunchpadMessage *dest, int r, int c, int color) { return LedPulse(dest, RC2Key(r, c), color); }
-
- static LaunchpadMessage *LedRGB(LaunchpadMessage *dest, LaunchpadKey key, int c_r, int c_g, int c_b)
- {
- dest->key = key;
- dest->cmd = LED_RGB;
- dest->param0 = ((c_r & 0x3f) << 8) | (c_g & 0x3f); // R,G
- dest->param1 = (c_b & 0x3f); // B
- return dest;
- }
- 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); }
- };
-
- class launchpadDriver
- {
- // uses keys SESSION, NOTE, DEVICE, USER
- // as page keys
-
- public:
- static const int ALL_PAGES = -1;
- launchpadDriver(LaunchpadScene scene, int maxPage)
- {
- comm = new communicator();
- numPages = maxPage;
- myScene = scene;
- Reset(ALL_LAUNCHPADS);
- lastCheck = 0;
- currentPage = 0;
- registerMyScene(true);
- }
-
- ~launchpadDriver()
- {
- registerMyScene(false);
- delete comm;
- }
-
- bool Connected() { return comm->Connected(); }
-
- 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); }
- void LedPulse(int lp, int page, int r, int c, int color) { return LedPulse(lp, page, ILaunchpadPro::RC2Key(r, c), color); }
- void LedColor(int lp, int page, int r, int c, int color) { return LedColor(lp, page, ILaunchpadPro::RC2Key(r, c), color); }
- void LedFlash(int lp, int page, int r, int c, int color) { return LedFlash(lp, page, ILaunchpadPro::RC2Key(r, c), color); }
- void Led(int lp, int page, int r, int c, LaunchpadLed led) { return Led(lp, page, ILaunchpadPro::RC2Key(r, c), led); }
- void Led(int lp, int page, LaunchpadKey key, LaunchpadLed led) { setValue(lp, page, key, led); }
- void LedColor(int lp, int page, LaunchpadKey key, int colr)
- {
- LaunchpadLed led;
- led.status = ButtonColorType::Normal;
- led.r_color = colr;
- Led(lp, page, key, led);
- }
- void LedFlash(int lp, int page, LaunchpadKey key, int colr)
- {
- LaunchpadLed led;
- led.status = ButtonColorType::Flash;
- led.r_color = colr;
- Led(lp, page, key, led);
- }
- void LedPulse(int lp, int page, LaunchpadKey key, int colr)
- {
- LaunchpadLed led;
- led.status = ButtonColorType::Pulse;
- led.r_color = colr;
- Led(lp, page, key, led);
- }
- void LedRGB(int lp, int page, LaunchpadKey key, int c_r, int c_g, int c_b)
- {
- LaunchpadLed led;
- led.status = ButtonColorType::RGB;
- led.r_color = c_r;
- led.g = c_g;
- led.b = c_b;
- Led(lp, page, key, led);
- }
-
- int GetPage() { return currentPage; }
-
- void SetPage(int page)
- {
- if(page >= 0 && page < numPages && currentPage != page)
- {
- currentPage = page;
- Clear(ALL_LAUNCHPADS);
- redrawCache();
- }
- }
-
-
- void Clear(int lp)
- {
- LaunchpadMessage dest;
- ILaunchpadPro::LightAll(&dest, 0);
- dest.currentScene = myScene;
- dest.lpNumber = lp;
- comm->Write(dest);
- }
-
- void Reset(int lp)
- {
- SetPage(0);
- Clear(lp);
- comm->clear();
- }
-
- int GetNumLaunchpads() // SYNC read
- {
- LaunchpadMessage dest;
- ILaunchpadPro::GetNumLaunchpads(&dest);
- comm->Write(dest);
- LaunchpadMessage rcv;
- if(syncRead(&rcv, LaunchpadCommand::GETNUMLAUNCHPADS))
- return rcv.lpNumber;
- return 0;
- }
-
- void SetAutoPageKey(LaunchpadKey key, int page)
- {
- if(page >= 0 && page < numPages)
- {
- autoPages[key] = page;
- } else if(page == -1) // remove key?
- {
- auto it = autoPages.find(key);
- if(it != autoPages.end())
- autoPages.erase(it);
- }
- }
-
- void drive_led(int lp, LaunchpadKey key, LaunchpadLed led)
- {
- LaunchpadMessage dest;
- ILaunchpadPro::Led(&dest, key, led);
- dest.currentScene = myScene;
- dest.lpNumber = lp;
- comm->Write(dest);
- }
-
- protected:
- int numPages;
- int currentPage;
- LaunchpadScene myScene;
- communicator *comm;
- virtual void redrawCache() { drive_autopage(); };
- void setValue(int lp, int page, LaunchpadKey key, LaunchpadLed led)
- {
- if(page == currentPage || page == launchpadDriver::ALL_PAGES)
- drive_led(lp, key, led);
- }
- int isAutoPageKey(LaunchpadMessage *msg)
- {
- if(msg->cmd == LaunchpadCommand::KEYON)
- {
- auto it = autoPages.find(msg->key);
- if(it != autoPages.end())
- return it->second;
- }
- return -1;
- }
- bool syncRead(LaunchpadMessage *rv, LaunchpadCommand waitCmd, int timeout = 1000)
- {
- DWORD now = GetTickCount();
- LaunchpadMessage msg;
- do
- {
- msg = comm->Read();
- if(msg.cmd == waitCmd)
- {
- memcpy(rv, &msg, sizeof(msg));
- return true;
- }
-
- } while((GetTickCount() - now) <= (DWORD)timeout);
- return false;
- }
-
- void registerMyScene(bool registr)
- {
- lastCheck = GetTickCount();
- LaunchpadMessage dest;
- ILaunchpadPro::RegisterScene(&dest, myScene, registr);
- dest.lpNumber = ALL_LAUNCHPADS;
- if(comm->Open())
- {
- comm->Write(dest);
- if(registr)
- SetPage(0);
-
- comm->Write(dest);
- }
-
- }
- uint32_t lastCheck;
-
- private:
- void drive_autopage()
- {
- for(std::map<LaunchpadKey, int>::iterator it = autoPages.begin(); it != autoPages.end(); ++it)
- {
- for(int k = 0; k < numPages; k++)
- {
- LaunchpadMessage dest;
- ILaunchpadPro::Led(&dest, it->first, LaunchpadLed::Color(it->second == currentPage ? 57 : 11));
- comm->Write(dest);
- }
- }
- }
-
- private:
- std::map<LaunchpadKey, int> autoPages;
- };
-
- struct launchpadControl
- {
- public:
- virtual ~launchpadControl() {};
- void Draw(launchpadDriver *drv, bool force = false)
- {
- if((force || m_dirty) && (drv->GetPage() == m_page || m_page == launchpadDriver::ALL_PAGES))
- {
- draw(drv);
- }
- m_dirty = false;
- m_lastDrawnValue = getValue();
-
- }
- bool Intersect(int lp, int page, LaunchpadKey key, bool shift)
- {
- if(m_shifted == shift)
- {
- if(page == m_page || page == launchpadDriver::ALL_PAGES || m_page == launchpadDriver::ALL_PAGES)
- {
- if(lp == m_lpNumber || lp == ALL_LAUNCHPADS || m_lpNumber == ALL_LAUNCHPADS)
- return intersect(key);
- }
- }
- return false;
- }
-
- void ChangeFromGUI(launchpadDriver *drv) // gui updated: the new value is already in the binded parameter
- {
- m_dirty = true;
- Draw(drv);
- }
-
- virtual void onLaunchpadKey(Module *pModule, LaunchpadMessage msg) = 0;
- bool DetectGUIChanges() { return getValue() != m_lastDrawnValue; }
-
- int ID() { return is_light ? pBindedLight->firstLightId : pBindedParam->paramId; }
- void bindWidget(ModuleLightWidget *p) { pBindedLight = p; is_light = true; }
- void bindWidget(ParamWidget *p) { pBindedParam = p; }
-
- protected:
- virtual void draw(launchpadDriver *drv) = 0;
- virtual bool intersect(LaunchpadKey key) { return false; }
-
- launchpadControl(int lp, int page, LaunchpadKey key, bool shifted)
- {
- m_lpNumber = lp;
- is_light = false;
- m_page = page;
- m_key = key;
- m_shifted = shifted;
- pBindedLight = NULL;
- pBindedParam = NULL;
- m_dirty = true;
- m_lastDrawnValue = -10202020;
- }
-
- float getValue() { return is_light ? pBindedLight->module->lights[pBindedLight->firstLightId].getBrightness() : pBindedParam->value; }
-
- void setValue(Module *pModule, float v)
- {
- if(v != getValue())
- {
- if(is_light)
- pBindedLight->module->lights[pBindedLight->firstLightId].value = v;
- else
- {
- SVGKnob *pk = (SVGKnob *)dynamic_cast<SVGKnob *>(pBindedParam);
- if(pk != NULL)
- {
- pModule->params[pBindedParam->paramId].value = pBindedParam->value = v;
- pk->dirty = true;
- } else
- {
- SVGFader *pk1 = (SVGFader *)dynamic_cast<SVGFader *>(pBindedParam);
- if(pk1 != NULL)
- {
- pModule->params[pBindedParam->paramId].value = pBindedParam->value = v;
- pk1->dirty = true;
- } else
- pBindedParam->setValue(v);
- }
- }
- m_dirty = true;
- }
- }
-
- int m_lpNumber;
- int m_page;
- bool is_light;
- LaunchpadKey m_key;
- bool m_shifted;
- ModuleLightWidget *pBindedLight;
- ParamWidget *pBindedParam;
- bool m_dirty;
- float m_lastDrawnValue;
- };
-
- struct LaunchpadBindingDriver : public launchpadDriver
- {
- public:
- LaunchpadBindingDriver(Module *pMod, LaunchpadScene scene, int maxPage) : launchpadDriver(scene, maxPage)
- {
- pModule = pMod;
- }
-
- virtual ~LaunchpadBindingDriver()
- {
- for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
- {
- if(it->second != NULL)
- delete it->second;
- }
-
- m_bindings.clear();
- }
-
- void Add(launchpadControl *ctrl, ParamWidget *p)
- {
- ctrl->bindWidget(p);
- int id = ctrl->ID();
- m_bindings[id] = ctrl;
- #ifdef DEBUG
- info("binded param %i ", id);
- #endif
-
- }
-
- void Add(launchpadControl *ctrl, ModuleLightWidget *p)
- {
- ctrl->bindWidget(p);
- int id = ctrl->ID();
- m_bindings[0x8000 | id] = ctrl;
- #ifdef DEBUG
- info("binded light %i ", 0x8000 | id);
- #endif
- }
-
- void ProcessLaunchpad()
- {
- processGUI();
- processLaunchpadKeys();
- if(!Connected() && (GetTickCount() - lastCheck) >= 2000)
- {
- registerMyScene(true);
- }
- }
-
- protected:
- virtual void redrawCache() override
- {
- for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
- {
- it->second->Draw(this, true);
- }
- launchpadDriver::redrawCache();
- }
-
- private:
- Module *pModule;
- std::map<int, launchpadControl *>m_bindings;
- void processGUI()
- {
- for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
- {
- if(it->second->DetectGUIChanges())
- {
- it->second->ChangeFromGUI(this);
- }
- }
- }
-
- void processLaunchpadKeys()
- {
- LaunchpadMessage msg;
- do
- {
- msg = comm->Read();
- if(msg.status != LaunchpadKeyStatus::keyNone && (msg.currentScene == SceneAll || msg.currentScene == myScene))
- {
- int page = isAutoPageKey(&msg);
- #ifdef DEBUG
- info("MSG: from LP=%i %i scene=%i ispage=%i key=%i", msg.lpNumber, msg.cmd, msg.currentScene, page, msg.key);
- #endif
- if(page >= 0 && msg.status == LaunchpadKeyStatus::keyDown && !msg.shiftDown)
- {
- SetPage(page);
- } else if(msg.cmd == LaunchpadCommand::RESET)
- {
- SetPage(currentPage);
- } else if(msg.cmd == LaunchpadCommand::SETSCENE)
- {
- #ifdef DEBUG
- info("MSG: set scene=%i myscene=%i", msg.param1, myScene);
- #endif
- if(myScene == msg.param1)
- {
- redrawCache();
- }
- } else
- {
- for(std::map<int, launchpadControl *>::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
- {
- if(it->second->Intersect(msg.lpNumber, GetPage(), msg.key, msg.shiftDown))
- {
- #ifdef DEBUG
- info("MSG: lp#=%i page=%i, key=%i shift=%i detected: %i", msg.lpNumber, GetPage(), msg.key, msg.shiftDown, it->first);
- #endif
- it->second->onLaunchpadKey(pModule, msg);
- }
- }
- }
- }
- } while(msg.status != LaunchpadKeyStatus::keyNone);
- }
-
- };
- #endif
|