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.

356 lines
9.2KB

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