Collection of DPF-based plugins for packaging
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.

384 lines
10KB

  1. /*
  2. * DISTRHO ProM Plugin
  3. * Copyright (C) 2015-2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * For a full copy of the license see the LICENSE file.
  15. */
  16. #include "libprojectM/projectM-opengl.h"
  17. #include "libprojectM/projectM.hpp"
  18. #include "DistrhoPluginProM.hpp"
  19. #include "DistrhoUIProM.hpp"
  20. #ifndef DISTRHO_OS_WINDOWS
  21. # include <dlfcn.h>
  22. #endif
  23. #ifdef DISTRHO_OS_WINDOWS
  24. static HINSTANCE hInstance = nullptr;
  25. DISTRHO_PLUGIN_EXPORT
  26. BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID)
  27. {
  28. if (reason == DLL_PROCESS_ATTACH)
  29. hInstance = hInst;
  30. return 1;
  31. }
  32. #endif
  33. START_NAMESPACE_DISTRHO
  34. // -----------------------------------------------------------------------
  35. static String getCurrentExecutableDataDir()
  36. {
  37. static String datadir;
  38. if (datadir.isNotEmpty())
  39. return datadir;
  40. #ifdef DISTRHO_OS_WINDOWS
  41. CHAR filename[MAX_PATH + 256];
  42. filename[0] = '\0';
  43. GetModuleFileName(hInstance, filename, sizeof(filename));
  44. datadir = String(filename);
  45. datadir.truncate(datadir.rfind('\\'));
  46. #else
  47. Dl_info info;
  48. dladdr((void*)getCurrentExecutableDataDir, &info);
  49. datadir = String(info.dli_fname);
  50. datadir.truncate(datadir.rfind('/'));
  51. # ifdef DISTRHO_OS_MAC
  52. if (datadir.endsWith("/MacOS"))
  53. {
  54. datadir.truncate(datadir.rfind('/'));
  55. datadir += "/Resources";
  56. }
  57. else
  58. # endif
  59. #endif
  60. {
  61. datadir += "/resources";
  62. }
  63. return datadir;
  64. }
  65. // -----------------------------------------------------------------------
  66. DistrhoUIProM::DistrhoUIProM()
  67. : UI(512, 512),
  68. fPM(nullptr),
  69. fResizeHandle(this)
  70. {
  71. // const double scaleFactor = getScaleFactor();
  72. // if (d_isNotZero(scaleFactor))
  73. // setSize(512*scaleFactor, 512*scaleFactor)
  74. setGeometryConstraints(256, 256, true);
  75. // no need to show resize handle if window is user-resizable
  76. // if (isResizable())
  77. // fResizeHandle.hide();
  78. }
  79. DistrhoUIProM::~DistrhoUIProM()
  80. {
  81. if (fPM == nullptr)
  82. return;
  83. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  84. {
  85. const MutexLocker csm(dspPtr->fMutex);
  86. dspPtr->fPM = nullptr;
  87. }
  88. }
  89. // -----------------------------------------------------------------------
  90. // DSP Callbacks
  91. void DistrhoUIProM::parameterChanged(uint32_t, float)
  92. {
  93. }
  94. // -----------------------------------------------------------------------
  95. // UI Callbacks
  96. void DistrhoUIProM::uiIdle()
  97. {
  98. if (fPM == nullptr)
  99. return;
  100. repaint();
  101. if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer())
  102. {
  103. if (dspPtr->fPM != nullptr)
  104. return;
  105. const MutexLocker csm(dspPtr->fMutex);
  106. dspPtr->fPM = fPM;
  107. }
  108. }
  109. void DistrhoUIProM::uiReshape(uint width, uint height)
  110. {
  111. UI::uiReshape(width, height);
  112. if (fPM == nullptr)
  113. {
  114. #ifdef PROJECTM_DATA_DIR
  115. fPM = new projectM(PROJECTM_DATA_DIR "/config.inp");
  116. #else
  117. const String datadir(getCurrentExecutableDataDir());
  118. d_stdout("ProM datadir: '%s'", datadir.buffer());
  119. projectM::Settings settings;
  120. settings.presetURL = datadir + DISTRHO_OS_SEP_STR "presets";
  121. settings.titleFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "Vera.ttf";
  122. settings.menuFontURL = datadir + DISTRHO_OS_SEP_STR "fonts" DISTRHO_OS_SEP_STR "VeraMono.ttf";
  123. settings.datadir = datadir;
  124. fPM = new projectM(settings);
  125. #endif
  126. }
  127. fPM->projectM_resetGL(width, height);
  128. }
  129. // -----------------------------------------------------------------------
  130. // Widget Callbacks
  131. void DistrhoUIProM::onDisplay()
  132. {
  133. if (fPM == nullptr)
  134. return;
  135. fPM->renderFrame();
  136. // turn off shaders at the end of the drawing cycle, so other things can draw properly
  137. glUseProgram(0);
  138. }
  139. static projectMKeycode dgl2pmkey(const DGL_NAMESPACE::Key key) noexcept
  140. {
  141. switch (key)
  142. {
  143. case DGL_NAMESPACE::kKeyBackspace:
  144. return PROJECTM_K_BACKSPACE;
  145. case DGL_NAMESPACE::kKeyEscape:
  146. return PROJECTM_K_ESCAPE;
  147. case DGL_NAMESPACE::kKeyDelete:
  148. return PROJECTM_K_DELETE;
  149. case DGL_NAMESPACE::kKeyF1:
  150. return PROJECTM_K_F1;
  151. case DGL_NAMESPACE::kKeyF2:
  152. return PROJECTM_K_F2;
  153. case DGL_NAMESPACE::kKeyF3:
  154. return PROJECTM_K_F3;
  155. case DGL_NAMESPACE::kKeyF4:
  156. return PROJECTM_K_F4;
  157. case DGL_NAMESPACE::kKeyF5:
  158. return PROJECTM_K_F5;
  159. case DGL_NAMESPACE::kKeyF6:
  160. return PROJECTM_K_F6;
  161. case DGL_NAMESPACE::kKeyF7:
  162. return PROJECTM_K_F7;
  163. case DGL_NAMESPACE::kKeyF8:
  164. return PROJECTM_K_F8;
  165. case DGL_NAMESPACE::kKeyF9:
  166. return PROJECTM_K_F9;
  167. case DGL_NAMESPACE::kKeyF10:
  168. return PROJECTM_K_F10;
  169. case DGL_NAMESPACE::kKeyF11:
  170. return PROJECTM_K_F11;
  171. case DGL_NAMESPACE::kKeyF12:
  172. return PROJECTM_K_F12;
  173. case DGL_NAMESPACE::kKeyLeft:
  174. return PROJECTM_K_LEFT;
  175. case DGL_NAMESPACE::kKeyUp:
  176. return PROJECTM_K_UP;
  177. case DGL_NAMESPACE::kKeyRight:
  178. return PROJECTM_K_RIGHT;
  179. case DGL_NAMESPACE::kKeyDown:
  180. return PROJECTM_K_DOWN;
  181. case DGL_NAMESPACE::kKeyPageUp:
  182. return PROJECTM_K_PAGEUP;
  183. case DGL_NAMESPACE::kKeyPageDown:
  184. return PROJECTM_K_PAGEDOWN;
  185. case DGL_NAMESPACE::kKeyHome:
  186. return PROJECTM_K_HOME;
  187. case DGL_NAMESPACE::kKeyEnd:
  188. return PROJECTM_K_END;
  189. case DGL_NAMESPACE::kKeyInsert:
  190. return PROJECTM_K_INSERT;
  191. case DGL_NAMESPACE::kKeyShiftL:
  192. return PROJECTM_K_LSHIFT;
  193. case DGL_NAMESPACE::kKeyShiftR:
  194. return PROJECTM_K_RSHIFT;
  195. case DGL_NAMESPACE::kKeyControlL:
  196. return PROJECTM_K_LCTRL;
  197. case DGL_NAMESPACE::kKeyControlR:
  198. case DGL_NAMESPACE::kKeyAltL:
  199. case DGL_NAMESPACE::kKeyAltR:
  200. case DGL_NAMESPACE::kKeySuperL:
  201. case DGL_NAMESPACE::kKeySuperR:
  202. case DGL_NAMESPACE::kKeyMenu:
  203. case DGL_NAMESPACE::kKeyCapsLock:
  204. case DGL_NAMESPACE::kKeyScrollLock:
  205. case DGL_NAMESPACE::kKeyNumLock:
  206. case DGL_NAMESPACE::kKeyPrintScreen:
  207. case DGL_NAMESPACE::kKeyPause:
  208. break;
  209. }
  210. return PROJECTM_K_NONE;
  211. }
  212. bool DistrhoUIProM::onKeyboard(const KeyboardEvent& ev)
  213. {
  214. if (fPM == nullptr)
  215. return false;
  216. #if 0
  217. if (ev.press && (ev.key == '1' || ev.key == '+' || ev.key == '-'))
  218. {
  219. if (ev.key == '1')
  220. {
  221. if (getWidth() != 512 || getHeight() != 512)
  222. setSize(512, 512);
  223. }
  224. else if (ev.key == '+')
  225. {
  226. /**/ if (getWidth() < 1100 && getHeight() < 1100)
  227. setSize(getWidth()+100, getHeight()+100);
  228. else if (getWidth() != 1100 || getHeight() != 1100)
  229. setSize(1100, 1100);
  230. }
  231. else if (ev.key == '-')
  232. {
  233. /**/ if (getWidth() >= 200 && getHeight() >= 200)
  234. setSize(getWidth()-100, getHeight()-100);
  235. else if (getWidth() != 100 || getHeight() != 100)
  236. setSize(100, 100);
  237. }
  238. return true;
  239. }
  240. #endif
  241. // special handling for text
  242. if (fPM->isTextInputActive(true) && !ev.press)
  243. {
  244. if (ev.key >= ' ' && ev.key <= 'z')
  245. {
  246. std::string key;
  247. key += static_cast<char>(ev.key);
  248. fPM->setSearchText(key);
  249. return true;
  250. }
  251. else if (ev.key == DGL_NAMESPACE::kKeyBackspace)
  252. {
  253. fPM->deleteSearchText();
  254. return true;
  255. }
  256. }
  257. projectMKeycode pmKey = PROJECTM_K_NONE;
  258. if (ev.key >= kKeyF1)
  259. {
  260. pmKey = dgl2pmkey(static_cast<DGL_NAMESPACE::Key>(ev.key));
  261. }
  262. else if ((ev.key >= PROJECTM_K_0 && ev.key <= PROJECTM_K_9) ||
  263. (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z) ||
  264. (ev.key >= PROJECTM_K_a && ev.key <= PROJECTM_K_z))
  265. {
  266. pmKey = static_cast<projectMKeycode>(ev.key);
  267. if (ev.key >= PROJECTM_K_A && ev.key <= PROJECTM_K_Z && (ev.mod & DGL_NAMESPACE::kModifierShift))
  268. pmKey = static_cast<projectMKeycode>(pmKey + (PROJECTM_K_a - PROJECTM_K_A));
  269. }
  270. else
  271. {
  272. /* missing:
  273. * PROJECTM_K_CAPSLOCK
  274. */
  275. switch (ev.key)
  276. {
  277. case DGL_NAMESPACE::kKeyBackspace:
  278. pmKey = PROJECTM_K_BACKSPACE;
  279. break;
  280. case DGL_NAMESPACE::kKeyEscape:
  281. pmKey = PROJECTM_K_ESCAPE;
  282. break;
  283. case DGL_NAMESPACE::kKeyDelete:
  284. pmKey = PROJECTM_K_DELETE;
  285. break;
  286. case '\r':
  287. pmKey = PROJECTM_K_RETURN;
  288. break;
  289. case '/':
  290. pmKey = PROJECTM_K_SLASH;
  291. break;
  292. case '\\':
  293. pmKey = PROJECTM_K_BACKSLASH;
  294. break;
  295. case '+':
  296. pmKey = PROJECTM_K_PLUS;
  297. break;
  298. case '-':
  299. pmKey = PROJECTM_K_MINUS;
  300. break;
  301. case '=':
  302. pmKey = PROJECTM_K_EQUALS;
  303. break;
  304. default:
  305. // d_stdout("Unhandled key %u %u %c", ev.keycode, ev.key, ev.key);
  306. break;
  307. }
  308. }
  309. if (pmKey == PROJECTM_K_NONE)
  310. return false;
  311. fPM->default_key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey);
  312. return true;
  313. }
  314. bool DistrhoUIProM::onSpecial(const SpecialEvent& ev)
  315. {
  316. if (fPM == nullptr)
  317. return false;
  318. const projectMKeycode pmKey = dgl2pmkey(ev.key);
  319. if (pmKey == PROJECTM_K_NONE)
  320. return false;
  321. fPM->default_key_handler(ev.press ? PROJECTM_KEYUP : PROJECTM_KEYDOWN, pmKey);
  322. return true;
  323. }
  324. // -----------------------------------------------------------------------
  325. UI* createUI()
  326. {
  327. return new DistrhoUIProM();
  328. }
  329. // -----------------------------------------------------------------------
  330. END_NAMESPACE_DISTRHO