Audio plugin host https://kx.studio/carla
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.

1854 lines
67KB

  1. /*
  2. * Carla plugin host
  3. * Copyright (C) 2011-2023 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 General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "pluginlistdialog.hpp"
  18. #ifdef __clang__
  19. # pragma clang diagnostic push
  20. # pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
  21. # pragma clang diagnostic ignored "-Wdeprecated-register"
  22. #elif defined(__GNUC__) && __GNUC__ >= 8
  23. # pragma GCC diagnostic push
  24. # pragma GCC diagnostic ignored "-Wclass-memaccess"
  25. # pragma GCC diagnostic ignored "-Wdeprecated-copy"
  26. #endif
  27. #include "ui_pluginlistdialog.h"
  28. #include <QtCore/QDir>
  29. #include <QtCore/QFileInfo>
  30. #include <QtCore/QList>
  31. #ifdef __clang__
  32. # pragma clang diagnostic pop
  33. #elif defined(__GNUC__) && __GNUC__ >= 8
  34. # pragma GCC diagnostic pop
  35. #endif
  36. #include "qcarlastring.hpp"
  37. #include "qsafesettings.hpp"
  38. #include "CarlaBackendUtils.hpp"
  39. #include "CarlaFrontend.h"
  40. #include "CarlaUtils.h"
  41. #include "CarlaString.hpp"
  42. #include <cstdlib>
  43. #ifdef BUILDING_CARLA_OBS
  44. extern "C" {
  45. const char *get_carla_bin_path(void);
  46. }
  47. #endif
  48. CARLA_BACKEND_USE_NAMESPACE
  49. // --------------------------------------------------------------------------------------------------------------------
  50. // Carla Settings keys
  51. #define CARLA_KEY_PATHS_LADSPA "Paths/LADSPA"
  52. #define CARLA_KEY_PATHS_DSSI "Paths/DSSI"
  53. #define CARLA_KEY_PATHS_LV2 "Paths/LV2"
  54. #define CARLA_KEY_PATHS_VST2 "Paths/VST2"
  55. #define CARLA_KEY_PATHS_VST3 "Paths/VST3"
  56. #define CARLA_KEY_PATHS_CLAP "Paths/CLAP"
  57. #define CARLA_KEY_PATHS_SF2 "Paths/SF2"
  58. #define CARLA_KEY_PATHS_SFZ "Paths/SFZ"
  59. #define CARLA_KEY_PATHS_JSFX "Paths/JSFX"
  60. // --------------------------------------------------------------------------------------------------------------------
  61. // Carla Settings defaults
  62. // --------------------------------------------------------------------------------------------------------------------
  63. // utils
  64. const char* getEnv(const char* const env, const char* const fallback)
  65. {
  66. if (const char* const value = std::getenv(env))
  67. return value;
  68. return fallback;
  69. }
  70. QCarlaString getTMP()
  71. {
  72. QCarlaString tmp;
  73. if (const char* const envTMP = std::getenv("TMP"))
  74. {
  75. tmp = envTMP;
  76. }
  77. else
  78. {
  79. #ifdef CARLA_OS_WIN
  80. qWarning("TMP variable not set");
  81. #endif
  82. tmp = QDir::tempPath();
  83. }
  84. if (!QDir(tmp).exists())
  85. {
  86. qWarning("TMP does not exist");
  87. tmp = "/";
  88. }
  89. return tmp;
  90. }
  91. QCarlaString getHome()
  92. {
  93. QCarlaString home;
  94. if (const char* const envHOME = std::getenv("HOME"))
  95. {
  96. home = envHOME;
  97. }
  98. else
  99. {
  100. #ifndef CARLA_OS_WIN
  101. qWarning("HOME variable not set");
  102. #endif
  103. home = QDir::toNativeSeparators(QDir::homePath());
  104. }
  105. if (!QDir(home).exists())
  106. {
  107. qWarning("HOME does not exist");
  108. home = getTMP();
  109. }
  110. return home;
  111. }
  112. // --------------------------------------------------------------------------------------------------------------------
  113. // Default Plugin Folders (get)
  114. struct DefaultPaths {
  115. QCarlaString ladspa;
  116. QCarlaString dssi;
  117. QCarlaString lv2;
  118. QCarlaString vst2;
  119. QCarlaString vst3;
  120. QCarlaString clap;
  121. QCarlaString sf2;
  122. QCarlaString sfz;
  123. QCarlaString jsfx;
  124. void init()
  125. {
  126. const QCarlaString HOME = getHome();
  127. #if defined(CARLA_OS_WIN)
  128. const char* const envAPPDATA = std::getenv("APPDATA");
  129. const char* const envLOCALAPPDATA = getEnv("LOCALAPPDATA", envAPPDATA);
  130. const char* const envPROGRAMFILES = std::getenv("PROGRAMFILES");
  131. const char* const envPROGRAMFILESx86 = std::getenv("PROGRAMFILES(x86)");
  132. const char* const envCOMMONPROGRAMFILES = std::getenv("COMMONPROGRAMFILES");
  133. const char* const envCOMMONPROGRAMFILESx86 = std::getenv("COMMONPROGRAMFILES(x86)");
  134. // Small integrity tests
  135. if (envAPPDATA == nullptr)
  136. {
  137. qFatal("APPDATA variable not set, cannot continue");
  138. abort();
  139. }
  140. if (envPROGRAMFILES == nullptr)
  141. {
  142. qFatal("PROGRAMFILES variable not set, cannot continue");
  143. abort();
  144. }
  145. if (envCOMMONPROGRAMFILES == nullptr)
  146. {
  147. qFatal("COMMONPROGRAMFILES variable not set, cannot continue");
  148. abort();
  149. }
  150. const QCarlaString APPDATA(envAPPDATA);
  151. const QCarlaString LOCALAPPDATA(envLOCALAPPDATA);
  152. const QCarlaString PROGRAMFILES(envPROGRAMFILES);
  153. const QCarlaString COMMONPROGRAMFILES(envCOMMONPROGRAMFILES);
  154. ladspa = APPDATA + "\\LADSPA";
  155. ladspa += ";" + PROGRAMFILES + "\\LADSPA";
  156. dssi = APPDATA + "\\DSSI";
  157. dssi += ";" + PROGRAMFILES + "\\DSSI";
  158. lv2 = APPDATA + "\\LV2";
  159. lv2 += ";" + COMMONPROGRAMFILES + "\\LV2";
  160. vst2 = PROGRAMFILES + "\\VstPlugins";
  161. vst2 += ";" + PROGRAMFILES + "\\Steinberg\\VstPlugins";
  162. jsfx = APPDATA + "\\REAPER\\Effects";
  163. //jsfx += ";" + PROGRAMFILES + "\\REAPER\\InstallData\\Effects";
  164. #ifdef CARLA_OS_WIN64
  165. vst2 += ";" + COMMONPROGRAMFILES + "\\VST2";
  166. #endif
  167. vst3 = COMMONPROGRAMFILES + "\\VST3";
  168. vst3 += ";" + LOCALAPPDATA + "\\Programs\\Common\\VST3";
  169. clap = COMMONPROGRAMFILES + "\\CLAP";
  170. clap += ";" + LOCALAPPDATA + "\\Programs\\Common\\CLAP";
  171. sf2 = APPDATA + "\\SF2";
  172. sfz = APPDATA + "\\SFZ";
  173. if (envPROGRAMFILESx86 != nullptr)
  174. {
  175. const QCarlaString PROGRAMFILESx86(envPROGRAMFILESx86);
  176. ladspa += ";" + PROGRAMFILESx86 + "\\LADSPA";
  177. dssi += ";" + PROGRAMFILESx86 + "\\DSSI";
  178. vst2 += ";" + PROGRAMFILESx86 + "\\VstPlugins";
  179. vst2 += ";" + PROGRAMFILESx86 + "\\Steinberg\\VstPlugins";
  180. //jsfx += ";" + PROGRAMFILESx86 + "\\REAPER\\InstallData\\Effects";
  181. }
  182. if (envCOMMONPROGRAMFILESx86 != nullptr)
  183. {
  184. const QCarlaString COMMONPROGRAMFILESx86(envCOMMONPROGRAMFILESx86);
  185. vst3 += COMMONPROGRAMFILESx86 + "\\VST3";
  186. clap += COMMONPROGRAMFILESx86 + "\\CLAP";
  187. }
  188. #elif defined(CARLA_OS_HAIKU)
  189. ladspa = HOME + "/.ladspa";
  190. ladspa += ":/system/add-ons/media/ladspaplugins";
  191. ladspa += ":/system/lib/ladspa";
  192. dssi = HOME + "/.dssi";
  193. dssi += ":/system/add-ons/media/dssiplugins";
  194. dssi += ":/system/lib/dssi";
  195. lv2 = HOME + "/.lv2";
  196. lv2 += ":/system/add-ons/media/lv2plugins";
  197. vst2 = HOME + "/.vst";
  198. vst2 += ":/system/add-ons/media/vstplugins";
  199. vst3 = HOME + "/.vst3";
  200. vst3 += ":/system/add-ons/media/vst3plugins";
  201. clap = HOME + "/.clap";
  202. clap += ":/system/add-ons/media/clapplugins";
  203. #elif defined(CARLA_OS_MAC)
  204. ladspa = HOME + "/Library/Audio/Plug-Ins/LADSPA";
  205. ladspa += ":/Library/Audio/Plug-Ins/LADSPA";
  206. dssi = HOME + "/Library/Audio/Plug-Ins/DSSI";
  207. dssi += ":/Library/Audio/Plug-Ins/DSSI";
  208. lv2 = HOME + "/Library/Audio/Plug-Ins/LV2";
  209. lv2 += ":/Library/Audio/Plug-Ins/LV2";
  210. vst2 = HOME + "/Library/Audio/Plug-Ins/VST";
  211. vst2 += ":/Library/Audio/Plug-Ins/VST";
  212. vst3 = HOME + "/Library/Audio/Plug-Ins/VST3";
  213. vst3 += ":/Library/Audio/Plug-Ins/VST3";
  214. clap = HOME + "/Library/Audio/Plug-Ins/CLAP";
  215. clap += ":/Library/Audio/Plug-Ins/CLAP";
  216. jsfx = HOME + "/Library/Application Support/REAPER/Effects";
  217. //jsfx += ":/Applications/REAPER.app/Contents/InstallFiles/Effects";
  218. #else
  219. const QCarlaString CONFIG_HOME(getEnv("XDG_CONFIG_HOME", (HOME + "/.config").toUtf8()));
  220. ladspa = HOME + "/.ladspa";
  221. ladspa += ":/usr/lib/ladspa";
  222. ladspa += ":/usr/local/lib/ladspa";
  223. dssi = HOME + "/.dssi";
  224. dssi += ":/usr/lib/dssi";
  225. dssi += ":/usr/local/lib/dssi";
  226. lv2 = HOME + "/.lv2";
  227. lv2 += ":/usr/lib/lv2";
  228. lv2 += ":/usr/local/lib/lv2";
  229. vst2 = HOME + "/.vst";
  230. vst2 += ":/usr/lib/vst";
  231. vst2 += ":/usr/local/lib/vst";
  232. vst2 += HOME + "/.lxvst";
  233. vst2 += ":/usr/lib/lxvst";
  234. vst2 += ":/usr/local/lib/lxvst";
  235. vst3 = HOME + "/.vst3";
  236. vst3 += ":/usr/lib/vst3";
  237. vst3 += ":/usr/local/lib/vst3";
  238. clap = HOME + "/.clap";
  239. clap += ":/usr/lib/clap";
  240. clap += ":/usr/local/lib/clap";
  241. sf2 = HOME + "/.sounds/sf2";
  242. sf2 += ":" + HOME + "/.sounds/sf3";
  243. sf2 += ":/usr/share/sounds/sf2";
  244. sf2 += ":/usr/share/sounds/sf3";
  245. sf2 += ":/usr/share/soundfonts";
  246. sfz = HOME + "/.sounds/sfz";
  247. sfz += ":/usr/share/sounds/sfz";
  248. jsfx = CONFIG_HOME + "/REAPER/Effects";
  249. //jsfx += ":" + "/opt/REAPER/InstallData/Effects";
  250. #endif
  251. #ifndef CARLA_OS_WIN
  252. QCarlaString winePrefix;
  253. if (const char* const envWINEPREFIX = std::getenv("WINEPREFIX"))
  254. winePrefix = envWINEPREFIX;
  255. if (winePrefix.isEmpty())
  256. winePrefix = HOME + "/.wine";
  257. if (QDir(winePrefix).exists())
  258. {
  259. vst2 += ":" + winePrefix + "/drive_c/Program Files/VstPlugins";
  260. vst3 += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST3";
  261. clap += ":" + winePrefix + "/drive_c/Program Files/Common Files/CLAP";
  262. #ifdef CARLA_OS_64BIT
  263. if (QDir(winePrefix + "/drive_c/Program Files (x86)").exists())
  264. {
  265. vst2 += ":" + winePrefix + "/drive_c/Program Files (x86)/VstPlugins";
  266. vst3 += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/VST3";
  267. clap += ":" + winePrefix + "/drive_c/Program Files (x86)/Common Files/CLAP";
  268. }
  269. #endif
  270. }
  271. #endif
  272. }
  273. void loadFromEnv()
  274. {
  275. if (const char* const envLADSPA = std::getenv("LADSPA_PATH"))
  276. ladspa = envLADSPA;
  277. if (const char* const envDSSI = std::getenv("DSSI_PATH"))
  278. dssi = envDSSI;
  279. if (const char* const envLV2 = std::getenv("LV2_PATH"))
  280. lv2 = envLV2;
  281. if (const char* const envVST = std::getenv("VST_PATH"))
  282. vst2 = envVST;
  283. if (const char* const envVST3 = std::getenv("VST3_PATH"))
  284. vst3 = envVST3;
  285. if (const char* const envCLAP = std::getenv("CLAP_PATH"))
  286. clap = envCLAP;
  287. if (const char* const envSF2 = std::getenv("SF2_PATH"))
  288. sf2 = envSF2;
  289. if (const char* const envSFZ = std::getenv("SFZ_PATH"))
  290. sfz = envSFZ;
  291. if (const char* const envJSFX = std::getenv("JSFX_PATH"))
  292. jsfx = envJSFX;
  293. }
  294. };
  295. // --------------------------------------------------------------------------------------------------------------------
  296. PluginInfo checkPluginCached(const CarlaCachedPluginInfo* const desc, const PluginType ptype)
  297. {
  298. PluginInfo pinfo = {};
  299. pinfo.API = PLUGIN_QUERY_API_VERSION;
  300. pinfo.build = BINARY_NATIVE;
  301. pinfo.type = ptype;
  302. pinfo.hints = desc->hints;
  303. pinfo.name = desc->name;
  304. pinfo.label = desc->label;
  305. pinfo.maker = desc->maker;
  306. pinfo.category = getPluginCategoryAsString(desc->category);
  307. pinfo.audioIns = desc->audioIns;
  308. pinfo.audioOuts = desc->audioOuts;
  309. pinfo.cvIns = desc->cvIns;
  310. pinfo.cvOuts = desc->cvOuts;
  311. pinfo.midiIns = desc->midiIns;
  312. pinfo.midiOuts = desc->midiOuts;
  313. pinfo.parametersIns = desc->parameterIns;
  314. pinfo.parametersOuts = desc->parameterOuts;
  315. switch (ptype)
  316. {
  317. case PLUGIN_LV2:
  318. {
  319. const QString label(desc->label);
  320. pinfo.filename = label.split(CARLA_OS_SEP).first();
  321. pinfo.label = label.section(CARLA_OS_SEP, 1);
  322. }
  323. break;
  324. case PLUGIN_SFZ:
  325. pinfo.filename = pinfo.label;
  326. pinfo.label = pinfo.name;
  327. break;
  328. default:
  329. break;
  330. }
  331. return pinfo;
  332. }
  333. // --------------------------------------------------------------------------------------------------------------------
  334. // Backwards-compatible horizontalAdvance/width call, depending on Qt version
  335. static inline
  336. int fontMetricsHorizontalAdvance(const QFontMetrics& fontMetrics, const QString& string)
  337. {
  338. #if QT_VERSION >= 0x50b00
  339. return fontMetrics.horizontalAdvance(string);
  340. #else
  341. return fontMetrics.width(string);
  342. #endif
  343. }
  344. // --------------------------------------------------------------------------------------------------------------------
  345. typedef QList<PluginInfo> QPluginInfoList;
  346. class QSafePluginListSettings : public QSafeSettings
  347. {
  348. public:
  349. inline QSafePluginListSettings()
  350. : QSafeSettings() {}
  351. inline QSafePluginListSettings(const QString& organization, const QString& application)
  352. : QSafeSettings(organization, application) {}
  353. QPluginInfoList valuePluginInfoList(const QString& key) const
  354. {
  355. /*
  356. QVariant var(value(key, {}));
  357. if (!var.isNull() && var.convert(QVariant::List) && var.isValid())
  358. {
  359. QList<QVariant> varVariant(var.toList());
  360. QPluginInfoList varReal;
  361. varReal.reserve(varVariant.size());
  362. for (QVariant v : varVariant)
  363. {
  364. CARLA_SAFE_ASSERT_BREAK(!v.isNull());
  365. CARLA_SAFE_ASSERT_BREAK(v.convert(QVariant::UserType));
  366. CARLA_SAFE_ASSERT_BREAK(v.isValid());
  367. // varReal.append(v.toU);
  368. }
  369. }
  370. */
  371. return {};
  372. // TODO
  373. (void)key;
  374. }
  375. void setValue(const QString& key, const uint value)
  376. {
  377. QSafeSettings::setValue(key, value);
  378. }
  379. void setValue(const QString& key, const QPluginInfoList& value)
  380. {
  381. return;
  382. // TODO
  383. (void)key;
  384. (void)value;
  385. }
  386. };
  387. // --------------------------------------------------------------------------------------------------------------------
  388. template <class T> inline T static_cast_void(const void* ptr)
  389. {
  390. return static_cast<T>(ptr);
  391. }
  392. struct PluginInfoBytes {
  393. uint API;
  394. uint build;
  395. uint type;
  396. uint hints;
  397. uint64_t uniqueId;
  398. uint audioIns;
  399. uint audioOuts;
  400. uint cvIns;
  401. uint cvOuts;
  402. uint midiIns;
  403. uint midiOuts;
  404. uint parametersIns;
  405. uint parametersOuts;
  406. };
  407. QVariant asVariant(const PluginInfo& plugin)
  408. {
  409. const PluginInfoBytes data = {
  410. plugin.API,
  411. static_cast<uint>(plugin.build),
  412. static_cast<uint>(plugin.type),
  413. plugin.hints,
  414. plugin.uniqueId,
  415. plugin.audioIns,
  416. plugin.audioOuts,
  417. plugin.cvIns,
  418. plugin.cvOuts,
  419. plugin.midiIns,
  420. plugin.midiOuts,
  421. plugin.parametersIns,
  422. plugin.parametersOuts
  423. };
  424. QByteArray qdata(static_cast_void<const char*>(&data), sizeof(data));
  425. {
  426. const QByteArray qcategory(plugin.category.toUtf8());
  427. qdata += qcategory.constData();
  428. qdata += '\0';
  429. }
  430. {
  431. const QByteArray qfilename(plugin.filename.toUtf8());
  432. qdata += qfilename.constData();
  433. qdata += '\0';
  434. }
  435. {
  436. const QByteArray qname(plugin.name.toUtf8());
  437. qdata += qname.constData();
  438. qdata += '\0';
  439. }
  440. {
  441. const QByteArray qlabel(plugin.label.toUtf8());
  442. qdata += qlabel.constData();
  443. qdata += '\0';
  444. }
  445. {
  446. const QByteArray qmaker(plugin.maker.toUtf8());
  447. qdata += qmaker.constData();
  448. qdata += '\0';
  449. }
  450. QVariant var;
  451. var.setValue(qdata);
  452. return var;
  453. }
  454. PluginInfo asPluginInfo(const QVariant& var)
  455. {
  456. const QByteArray qdata(var.toByteArray());
  457. CARLA_SAFE_ASSERT_RETURN((size_t)qdata.size() >= sizeof(PluginInfoBytes) + sizeof(char)*5, {});
  458. const PluginInfoBytes* const data = static_cast_void<const PluginInfoBytes*>(qdata.constData());
  459. PluginInfo plugin = {
  460. data->API,
  461. static_cast<BinaryType>(data->build),
  462. static_cast<PluginType>(data->type),
  463. data->hints,
  464. {}, {}, {}, {}, {},
  465. data->uniqueId,
  466. data->audioIns,
  467. data->audioOuts,
  468. data->cvIns,
  469. data->cvOuts,
  470. data->midiIns,
  471. data->midiOuts,
  472. data->parametersIns,
  473. data->parametersOuts
  474. };
  475. const char* sdata = static_cast_void<const char*>(data) + sizeof(PluginInfoBytes);
  476. plugin.category = QString::fromUtf8(sdata);
  477. sdata += plugin.category.size() + 1;
  478. plugin.filename = QString::fromUtf8(sdata);
  479. sdata += plugin.filename.size() + 1;
  480. plugin.name = QString::fromUtf8(sdata);
  481. sdata += plugin.name.size() + 1;
  482. plugin.label = QString::fromUtf8(sdata);
  483. sdata += plugin.label.size() + 1;
  484. plugin.maker = QString::fromUtf8(sdata);
  485. sdata += plugin.maker.size() + 1;
  486. return plugin;
  487. }
  488. // --------------------------------------------------------------------------------------------------------------------
  489. // Plugin List Dialog
  490. struct PluginListDialog::Self {
  491. enum TableIndex {
  492. TABLEWIDGET_ITEM_FAVORITE,
  493. TABLEWIDGET_ITEM_NAME,
  494. TABLEWIDGET_ITEM_LABEL,
  495. TABLEWIDGET_ITEM_MAKER,
  496. TABLEWIDGET_ITEM_BINARY,
  497. };
  498. // To be changed by parent
  499. bool hasLoadedLv2Plugins = false;
  500. Ui_PluginListDialog ui;
  501. HostSettings hostSettings = {};
  502. struct Discovery {
  503. CarlaPluginDiscoveryHandle handle = nullptr;
  504. PluginType ptype = PLUGIN_NONE;
  505. DefaultPaths paths;
  506. QString tool;
  507. Discovery()
  508. {
  509. paths.init();
  510. paths.loadFromEnv();
  511. #ifdef BUILDING_CARLA_OBS
  512. tool = QString::fromUtf8(get_carla_bin_path());
  513. tool += CARLA_OS_SEP_STR "carla-discovery-native";
  514. #ifdef CARLA_OS_WIN
  515. tool += ".exe";
  516. #endif
  517. #else
  518. tool = "/usr/lib/carla/carla-discovery-native";
  519. #endif
  520. }
  521. ~Discovery()
  522. {
  523. if (handle != nullptr)
  524. carla_plugin_discovery_stop(handle);
  525. }
  526. } fDiscovery;
  527. int fLastTableWidgetIndex = 0;
  528. std::vector<PluginInfo> fPluginsInternal;
  529. std::vector<PluginInfo> fPluginsLADSPA;
  530. std::vector<PluginInfo> fPluginsDSSI;
  531. std::vector<PluginInfo> fPluginsLV2;
  532. std::vector<PluginInfo> fPluginsVST2;
  533. std::vector<PluginInfo> fPluginsVST3;
  534. std::vector<PluginInfo> fPluginsCLAP;
  535. #ifdef CARLA_OS_MAC
  536. std::vector<PluginInfo> fPluginsAU;
  537. #endif
  538. std::vector<PluginInfo> fPluginsJSFX;
  539. std::vector<PluginInfo> fPluginsSF2;
  540. std::vector<PluginInfo> fPluginsSFZ;
  541. int fTimerId = 0;
  542. PluginInfo fRetPlugin;
  543. QWidget* const fRealParent;
  544. QStringList fFavoritePlugins;
  545. bool fFavoritePluginsChanged = false;
  546. const QString fTrYes;
  547. const QString fTrNo;
  548. const QString fTrNative;
  549. Self(QWidget* const parent)
  550. : fRealParent(parent),
  551. fTrYes(tr("Yes")),
  552. fTrNo(tr("No")),
  553. fTrNative(tr("Native")) {}
  554. static Self& create(QWidget* const parent)
  555. {
  556. Self* const self = new Self(parent);
  557. return *self;
  558. }
  559. inline QString tr(const char* const txt)
  560. {
  561. return fRealParent != nullptr ? fRealParent->tr(txt) : QString::fromUtf8(txt);
  562. }
  563. void createFavoritePluginDict()
  564. {
  565. #if 0
  566. return {
  567. 'name' : plugin['name'],
  568. 'build' : plugin['build'],
  569. 'type' : plugin['type'],
  570. 'filename': plugin['filename'],
  571. 'label' : plugin['label'],
  572. 'uniqueId': plugin['uniqueId'],
  573. }
  574. #endif
  575. }
  576. void checkFilters()
  577. {
  578. const QCarlaString text = ui.lineEdit->text().toLower();
  579. const bool hideEffects = !ui.ch_effects->isChecked();
  580. const bool hideInstruments = !ui.ch_instruments->isChecked();
  581. const bool hideMidi = !ui.ch_midi->isChecked();
  582. const bool hideOther = !ui.ch_other->isChecked();
  583. const bool hideInternal = !ui.ch_internal->isChecked();
  584. const bool hideLadspa = !ui.ch_ladspa->isChecked();
  585. const bool hideDssi = !ui.ch_dssi->isChecked();
  586. const bool hideLV2 = !ui.ch_lv2->isChecked();
  587. const bool hideVST2 = !ui.ch_vst->isChecked();
  588. const bool hideVST3 = !ui.ch_vst3->isChecked();
  589. const bool hideCLAP = !ui.ch_clap->isChecked();
  590. const bool hideAU = !ui.ch_au->isChecked();
  591. const bool hideJSFX = !ui.ch_jsfx->isChecked();
  592. const bool hideKits = !ui.ch_kits->isChecked();
  593. const bool hideNative = !ui.ch_native->isChecked();
  594. const bool hideBridged = !ui.ch_bridged->isChecked();
  595. const bool hideBridgedWine = !ui.ch_bridged_wine->isChecked();
  596. #if 0
  597. const bool hideNonFavs = ui.ch_favorites->isChecked();
  598. #endif
  599. const bool hideNonRtSafe = ui.ch_rtsafe->isChecked();
  600. const bool hideNonCV = ui.ch_cv->isChecked();
  601. const bool hideNonGui = ui.ch_gui->isChecked();
  602. const bool hideNonIDisp = ui.ch_inline_display->isChecked();
  603. const bool hideNonStereo = ui.ch_stereo->isChecked();
  604. #if 0
  605. if HAIKU or LINUX or MACOS:
  606. nativeBins = [BINARY_POSIX32, BINARY_POSIX64]
  607. wineBins = [BINARY_WIN32, BINARY_WIN64]
  608. elif WINDOWS:
  609. nativeBins = [BINARY_WIN32, BINARY_WIN64]
  610. wineBins = []
  611. else:
  612. nativeBins = []
  613. wineBins = []
  614. #endif
  615. for (int i=0, c=ui.tableWidget->rowCount(); i<c; ++i)
  616. {
  617. const PluginInfo plugin = asPluginInfo(ui.tableWidget->item(i, TABLEWIDGET_ITEM_NAME)->data(Qt::UserRole+1));
  618. const QString ptext = ui.tableWidget->item(i, TABLEWIDGET_ITEM_NAME)->data(Qt::UserRole+2).toString();
  619. const uint aIns = plugin.audioIns;
  620. const uint aOuts = plugin.audioOuts;
  621. const uint cvIns = plugin.cvIns;
  622. const uint cvOuts = plugin.cvOuts;
  623. const uint mIns = plugin.midiIns;
  624. const uint mOuts = plugin.midiOuts;
  625. const uint phints = plugin.hints;
  626. const PluginType ptype = plugin.type;
  627. const QString categ = plugin.category;
  628. const bool isSynth = phints & PLUGIN_IS_SYNTH;
  629. const bool isEffect = aIns > 0 && aOuts > 0 && !isSynth;
  630. const bool isMidi = aIns == 0 && aOuts == 0 && mIns > 0 && mOuts > 0;
  631. const bool isKit = ptype == PLUGIN_SF2 || ptype == PLUGIN_SFZ;
  632. const bool isOther = !(isEffect || isSynth || isMidi || isKit);
  633. const bool isNative = plugin.build == BINARY_NATIVE;
  634. const bool isRtSafe = phints & PLUGIN_IS_RTSAFE;
  635. const bool isStereo = (aIns == 2 && aOuts == 2) || (isSynth && aOuts == 2);
  636. const bool hasCV = cvIns + cvOuts > 0;
  637. const bool hasGui = phints & PLUGIN_HAS_CUSTOM_UI;
  638. const bool hasIDisp = phints & PLUGIN_HAS_INLINE_DISPLAY;
  639. #if 0
  640. const bool isBridged = bool(not isNative and plugin.build in nativeBins);
  641. const bool isBridgedWine = bool(not isNative and plugin.build in wineBins);
  642. #else
  643. const bool isBridged = false;
  644. const bool isBridgedWine = false;
  645. #endif
  646. const auto hasText = [text, ptext]() {
  647. const QStringList textSplit = text.strip().split(' ');
  648. for (const QString& t : textSplit)
  649. if (ptext.contains(t))
  650. return true;
  651. return false;
  652. };
  653. /**/ if (hideEffects && isEffect)
  654. ui.tableWidget->hideRow(i);
  655. else if (hideInstruments && isSynth)
  656. ui.tableWidget->hideRow(i);
  657. else if (hideMidi && isMidi)
  658. ui.tableWidget->hideRow(i);
  659. else if (hideOther && isOther)
  660. ui.tableWidget->hideRow(i);
  661. else if (hideKits && isKit)
  662. ui.tableWidget->hideRow(i);
  663. else if (hideInternal && ptype == PLUGIN_INTERNAL)
  664. ui.tableWidget->hideRow(i);
  665. else if (hideLadspa && ptype == PLUGIN_LADSPA)
  666. ui.tableWidget->hideRow(i);
  667. else if (hideDssi && ptype == PLUGIN_DSSI)
  668. ui.tableWidget->hideRow(i);
  669. else if (hideLV2 && ptype == PLUGIN_LV2)
  670. ui.tableWidget->hideRow(i);
  671. else if (hideVST2 && ptype == PLUGIN_VST2)
  672. ui.tableWidget->hideRow(i);
  673. else if (hideVST3 && ptype == PLUGIN_VST3)
  674. ui.tableWidget->hideRow(i);
  675. else if (hideCLAP && ptype == PLUGIN_CLAP)
  676. ui.tableWidget->hideRow(i);
  677. else if (hideAU && ptype == PLUGIN_AU)
  678. ui.tableWidget->hideRow(i);
  679. else if (hideJSFX && ptype == PLUGIN_JSFX)
  680. ui.tableWidget->hideRow(i);
  681. else if (hideNative && isNative)
  682. ui.tableWidget->hideRow(i);
  683. else if (hideBridged && isBridged)
  684. ui.tableWidget->hideRow(i);
  685. else if (hideBridgedWine && isBridgedWine)
  686. ui.tableWidget->hideRow(i);
  687. else if (hideNonRtSafe && not isRtSafe)
  688. ui.tableWidget->hideRow(i);
  689. else if (hideNonCV && not hasCV)
  690. ui.tableWidget->hideRow(i);
  691. else if (hideNonGui && not hasGui)
  692. ui.tableWidget->hideRow(i);
  693. else if (hideNonIDisp && not hasIDisp)
  694. ui.tableWidget->hideRow(i);
  695. else if (hideNonStereo && not isStereo)
  696. ui.tableWidget->hideRow(i);
  697. else if (text.isNotEmpty() && ! hasText())
  698. ui.tableWidget->hideRow(i);
  699. #if 0
  700. else if (hideNonFavs && _createFavoritePluginDict(plugin) not in fFavoritePlugins)
  701. ui.tableWidget->hideRow(i);
  702. #endif
  703. else if (ui.ch_cat_all->isChecked() or
  704. (ui.ch_cat_delay->isChecked() && categ == "delay") or
  705. (ui.ch_cat_distortion->isChecked() && categ == "distortion") or
  706. (ui.ch_cat_dynamics->isChecked() && categ == "dynamics") or
  707. (ui.ch_cat_eq->isChecked() && categ == "eq") or
  708. (ui.ch_cat_filter->isChecked() && categ == "filter") or
  709. (ui.ch_cat_modulator->isChecked() && categ == "modulator") or
  710. (ui.ch_cat_synth->isChecked() && categ == "synth") or
  711. (ui.ch_cat_utility->isChecked() && categ == "utility") or
  712. (ui.ch_cat_other->isChecked() && categ == "other"))
  713. ui.tableWidget->showRow(i);
  714. else
  715. ui.tableWidget->hideRow(i);
  716. }
  717. }
  718. bool addPlugin(const PluginInfo& pinfo)
  719. {
  720. switch (pinfo.type)
  721. {
  722. case PLUGIN_INTERNAL: fPluginsInternal.push_back(pinfo); return true;
  723. case PLUGIN_LADSPA: fPluginsLADSPA.push_back(pinfo); return true;
  724. case PLUGIN_DSSI: fPluginsDSSI.push_back(pinfo); return true;
  725. case PLUGIN_LV2: fPluginsLV2.push_back(pinfo); return true;
  726. case PLUGIN_VST2: fPluginsVST2.push_back(pinfo); return true;
  727. case PLUGIN_VST3: fPluginsVST3.push_back(pinfo); return true;
  728. case PLUGIN_CLAP: fPluginsCLAP.push_back(pinfo); return true;
  729. #ifdef CARLA_OS_MAC
  730. case PLUGIN_AU: fPluginsAU.push_back(pinfo); return true;
  731. #endif
  732. case PLUGIN_JSFX: fPluginsJSFX.push_back(pinfo); return true;
  733. case PLUGIN_SF2: fPluginsSF2.push_back(pinfo); return true;
  734. case PLUGIN_SFZ: fPluginsSFZ.push_back(pinfo); return true;
  735. default: return false;
  736. }
  737. }
  738. void discoveryCallback(const CarlaPluginDiscoveryInfo* const info, const char* const sha1sum)
  739. {
  740. if (info == nullptr)
  741. {
  742. if (sha1sum != nullptr)
  743. {
  744. QSafeSettings settings("falkTX", "CarlaDatabase2");
  745. settings.setValue(QString("PluginCache/%1").arg(sha1sum), QByteArray());
  746. }
  747. return;
  748. }
  749. #ifdef BUILDING_CARLA_OBS
  750. if (info->io.cvIns != 0 || info->io.cvOuts != 0)
  751. {
  752. carla_stdout("discoveryCallback %p %s - ignored, has CV", info, info->filename);
  753. return;
  754. }
  755. if (info->io.audioIns > 8 || info->io.audioOuts > 8)
  756. {
  757. carla_stdout("discoveryCallback %p %s - ignored, has > 8 audio IO", info, info->filename);
  758. return;
  759. }
  760. #endif
  761. const PluginInfo pinfo = {
  762. PLUGIN_QUERY_API_VERSION,
  763. info->btype,
  764. info->ptype,
  765. info->metadata.hints,
  766. getPluginCategoryAsString(info->metadata.category),
  767. QString::fromUtf8(info->filename),
  768. QString::fromUtf8(info->metadata.name),
  769. QString::fromUtf8(info->label),
  770. QString::fromUtf8(info->metadata.maker),
  771. info->uniqueId,
  772. info->io.audioIns,
  773. info->io.audioOuts,
  774. info->io.cvIns,
  775. info->io.cvOuts,
  776. info->io.midiIns,
  777. info->io.midiOuts,
  778. info->io.parameterIns,
  779. info->io.parameterOuts,
  780. };
  781. if (sha1sum != nullptr)
  782. {
  783. QSafeSettings settings("falkTX", "CarlaDatabase2");
  784. settings.setValue(QString("PluginCache/%1").arg(sha1sum), asVariant(pinfo));
  785. }
  786. addPlugin(pinfo);
  787. }
  788. static void _discoveryCallback(void* const ptr, const CarlaPluginDiscoveryInfo* const info, const char* const sha1sum)
  789. {
  790. static_cast<PluginListDialog::Self*>(ptr)->discoveryCallback(info, sha1sum);
  791. }
  792. bool checkCacheCallback(const char*, const char* const sha1sum)
  793. {
  794. if (sha1sum == nullptr)
  795. return false;
  796. // TODO check filename
  797. const QString key = QString("PluginCache/%1").arg(sha1sum);
  798. const QSafeSettings settings("falkTX", "CarlaDatabase2");
  799. if (! settings.contains(key))
  800. return false;
  801. const QByteArray data(settings.valueByteArray(key));
  802. if (data.isEmpty())
  803. return true;
  804. return addPlugin(asPluginInfo(data));
  805. }
  806. static bool _checkCacheCallback(void* const ptr, const char* const filename, const char* const sha1sum)
  807. {
  808. return static_cast<PluginListDialog::Self*>(ptr)->checkCacheCallback(filename, sha1sum);
  809. }
  810. void addPluginToTable(const PluginInfo& pinfo)
  811. {
  812. // PluginInfo plugincopy = plugin;
  813. // switch (ptype)
  814. // {
  815. // case PLUGIN_INTERNAL:
  816. // case PLUGIN_LV2:
  817. // case PLUGIN_SF2:
  818. // case PLUGIN_SFZ:
  819. // case PLUGIN_JSFX:
  820. // plugincopy.build = BINARY_NATIVE;
  821. // break;
  822. // default:
  823. // break;
  824. // }
  825. const int index = fLastTableWidgetIndex++;
  826. #if 0
  827. const bool isFav = bool(self._createFavoritePluginDict(plugin) in self.fFavoritePlugins)
  828. #else
  829. const bool isFav = false;
  830. #endif
  831. QTableWidgetItem* const itemFav = new QTableWidgetItem;
  832. itemFav->setCheckState(isFav ? Qt::Checked : Qt::Unchecked);
  833. itemFav->setText(isFav ? " " : " ");
  834. const QString pluginText = (pinfo.name + pinfo.label + pinfo.maker + pinfo.filename).toLower();
  835. ui.tableWidget->setItem(index, TABLEWIDGET_ITEM_FAVORITE, itemFav);
  836. ui.tableWidget->setItem(index, TABLEWIDGET_ITEM_NAME, new QTableWidgetItem(pinfo.name));
  837. ui.tableWidget->setItem(index, TABLEWIDGET_ITEM_LABEL, new QTableWidgetItem(pinfo.label));
  838. ui.tableWidget->setItem(index, TABLEWIDGET_ITEM_MAKER, new QTableWidgetItem(pinfo.maker));
  839. ui.tableWidget->setItem(index, TABLEWIDGET_ITEM_BINARY, new QTableWidgetItem(QFileInfo(pinfo.filename).fileName()));
  840. QTableWidgetItem* const itemName = ui.tableWidget->item(index, TABLEWIDGET_ITEM_NAME);
  841. itemName->setData(Qt::UserRole+1, asVariant(pinfo));
  842. itemName->setData(Qt::UserRole+2, pluginText);
  843. }
  844. bool idle()
  845. {
  846. // discovery in progress, keep it going
  847. if (fDiscovery.handle != nullptr)
  848. {
  849. if (! carla_plugin_discovery_idle(fDiscovery.handle))
  850. {
  851. carla_plugin_discovery_stop(fDiscovery.handle);
  852. fDiscovery.handle = nullptr;
  853. }
  854. return false;
  855. }
  856. // TESTING
  857. reAddPlugins();
  858. // start next discovery
  859. QString path;
  860. switch (fDiscovery.ptype)
  861. {
  862. case PLUGIN_NONE:
  863. ui.label->setText(tr("Discovering internal plugins..."));
  864. fDiscovery.ptype = PLUGIN_INTERNAL;
  865. break;
  866. case PLUGIN_INTERNAL:
  867. ui.label->setText(tr("Discovering LADSPA plugins..."));
  868. path = fDiscovery.paths.ladspa;
  869. fDiscovery.ptype = PLUGIN_LADSPA;
  870. break;
  871. case PLUGIN_LADSPA:
  872. ui.label->setText(tr("Discovering DSSI plugins..."));
  873. path = fDiscovery.paths.dssi;
  874. fDiscovery.ptype = PLUGIN_DSSI;
  875. break;
  876. case PLUGIN_DSSI:
  877. ui.label->setText(tr("Discovering LV2 plugins..."));
  878. path = fDiscovery.paths.lv2;
  879. fDiscovery.ptype = PLUGIN_LV2;
  880. break;
  881. case PLUGIN_LV2:
  882. ui.label->setText(tr("Discovering VST2 plugins..."));
  883. path = fDiscovery.paths.vst2;
  884. fDiscovery.ptype = PLUGIN_VST2;
  885. break;
  886. case PLUGIN_VST2:
  887. ui.label->setText(tr("Discovering VST3 plugins..."));
  888. path = fDiscovery.paths.vst3;
  889. fDiscovery.ptype = PLUGIN_VST3;
  890. break;
  891. case PLUGIN_VST3:
  892. ui.label->setText(tr("Discovering CLAP plugins..."));
  893. path = fDiscovery.paths.clap;
  894. fDiscovery.ptype = PLUGIN_CLAP;
  895. break;
  896. case PLUGIN_CLAP:
  897. #ifdef CARLA_OS_MAC
  898. ui.label->setText(tr("Discovering AU plugins..."));
  899. fDiscovery.ptype = PLUGIN_AU;
  900. break;
  901. case PLUGIN_AU:
  902. #endif
  903. if (fDiscovery.paths.jsfx.isNotEmpty())
  904. {
  905. ui.label->setText(tr("Discovering JSFX plugins..."));
  906. path = fDiscovery.paths.jsfx;
  907. fDiscovery.ptype = PLUGIN_JSFX;
  908. break;
  909. }
  910. // fall-through
  911. case PLUGIN_JSFX:
  912. ui.label->setText(tr("Discovering SF2 kits..."));
  913. path = fDiscovery.paths.sf2;
  914. fDiscovery.ptype = PLUGIN_SF2;
  915. break;
  916. case PLUGIN_SF2:
  917. if (fDiscovery.paths.sfz.isNotEmpty())
  918. {
  919. ui.label->setText(tr("Discovering SFZ kits..."));
  920. path = fDiscovery.paths.sfz;
  921. fDiscovery.ptype = PLUGIN_SFZ;
  922. break;
  923. }
  924. // fall-through
  925. case PLUGIN_SFZ:
  926. default:
  927. // the end
  928. reAddPlugins();
  929. return true;
  930. }
  931. fDiscovery.handle = carla_plugin_discovery_start(fDiscovery.tool.toUtf8().constData(),
  932. fDiscovery.ptype,
  933. path.toUtf8().constData(),
  934. _discoveryCallback,
  935. _checkCacheCallback,
  936. this);
  937. CARLA_SAFE_ASSERT_RETURN(fDiscovery.handle != nullptr, false);
  938. return false;
  939. }
  940. void reAddPlugins()
  941. {
  942. // ------------------------------------------------------------------------------------------------------------
  943. // count plugins first, so we can create rows in advance
  944. ui.tableWidget->setSortingEnabled(false);
  945. ui.tableWidget->clearContents();
  946. ui.tableWidget->setRowCount(fPluginsInternal.size() +
  947. fPluginsLADSPA.size() +
  948. fPluginsDSSI.size() +
  949. fPluginsLV2.size() +
  950. fPluginsVST2.size() +
  951. fPluginsVST3.size() +
  952. fPluginsCLAP.size() +
  953. #ifdef CARLA_OS_MAC
  954. fPluginsAU.size() +
  955. #endif
  956. fPluginsJSFX.size() +
  957. fPluginsSF2.size() +
  958. fPluginsSFZ.size());
  959. constexpr const char* const txt = "Have %1 Internal, %2 LADSPA, %3 DSSI, %4 LV2, %5 VST2, %6 VST3, %7 CLAP"
  960. #ifdef CARLA_OS_MAC
  961. ", %8 AudioUnit and %9 JSFX plugins, plus %10 Sound Kits"
  962. #endif
  963. " and %8 JSFX plugins, plus %9 Sound Kits";
  964. ui.label->setText(fRealParent->tr(txt)
  965. .arg(QString::number(fPluginsInternal.size()))
  966. .arg(QString::number(fPluginsLADSPA.size()))
  967. .arg(QString::number(fPluginsDSSI.size()))
  968. .arg(QString::number(fPluginsLV2.size()))
  969. .arg(QString::number(fPluginsVST2.size()))
  970. .arg(QString::number(fPluginsVST3.size()))
  971. .arg(QString::number(fPluginsCLAP.size()))
  972. #ifdef CARLA_OS_MAC
  973. .arg(QString::number(fPluginsAU.size()))
  974. #endif
  975. .arg(QString::number(fPluginsJSFX.size()))
  976. .arg(QString::number(fPluginsSF2.size() + fPluginsSFZ.size()))
  977. );
  978. // ------------------------------------------------------------------------------------------------------------
  979. // now add all plugins to the table
  980. fLastTableWidgetIndex = 0;
  981. for (const PluginInfo& plugin : fPluginsInternal)
  982. addPluginToTable(plugin);
  983. for (const PluginInfo& plugin : fPluginsLADSPA)
  984. addPluginToTable(plugin);
  985. for (const PluginInfo& plugin : fPluginsDSSI)
  986. addPluginToTable(plugin);
  987. for (const PluginInfo& plugin : fPluginsLV2)
  988. addPluginToTable(plugin);
  989. for (const PluginInfo& plugin : fPluginsVST2)
  990. addPluginToTable(plugin);
  991. for (const PluginInfo& plugin : fPluginsVST3)
  992. addPluginToTable(plugin);
  993. for (const PluginInfo& plugin : fPluginsCLAP)
  994. addPluginToTable(plugin);
  995. #ifdef CARLA_OS_MAC
  996. for (const PluginInfo& plugin : fPluginsAU)
  997. addPluginToTable(plugin);
  998. #endif
  999. for (const PluginInfo& plugin : fPluginsJSFX)
  1000. addPluginToTable(plugin);
  1001. for (const PluginInfo& plugin : fPluginsSF2)
  1002. addPluginToTable(plugin);
  1003. for (const PluginInfo& plugin : fPluginsSFZ)
  1004. addPluginToTable(plugin);
  1005. CARLA_SAFE_ASSERT_INT2(fLastTableWidgetIndex == ui.tableWidget->rowCount(),
  1006. fLastTableWidgetIndex, ui.tableWidget->rowCount());
  1007. // ------------------------------------------------------------------------------------------------------------
  1008. ui.tableWidget->setSortingEnabled(true);
  1009. checkFilters();
  1010. checkPlugin(ui.tableWidget->currentRow());
  1011. }
  1012. void checkPlugin(const int row)
  1013. {
  1014. if (row >= 0)
  1015. {
  1016. ui.b_add->setEnabled(true);
  1017. PluginInfo plugin = asPluginInfo(ui.tableWidget->item(row, TABLEWIDGET_ITEM_NAME)->data(Qt::UserRole+1));
  1018. const bool isSynth = plugin.hints & PLUGIN_IS_SYNTH;
  1019. const bool isEffect = plugin.audioIns > 0 && plugin.audioOuts > 0 && !isSynth;
  1020. const bool isMidi = plugin.audioIns == 0 &&
  1021. plugin.audioOuts == 0 &&
  1022. plugin.midiIns > 0 && plugin.midiOuts > 0;
  1023. // const bool isKit = plugin['type'] in (PLUGIN_SF2, PLUGIN_SFZ);
  1024. // const bool isOther = ! (isEffect || isSynth || isMidi || isKit);
  1025. QString ptype;
  1026. /**/ if (isSynth)
  1027. ptype = "Instrument";
  1028. else if (isEffect)
  1029. ptype = "Effect";
  1030. else if (isMidi)
  1031. ptype = "MIDI Plugin";
  1032. else
  1033. ptype = "Other";
  1034. QString parch;
  1035. /**/ if (plugin.build == BINARY_NATIVE)
  1036. parch = fTrNative;
  1037. else if (plugin.build == BINARY_POSIX32)
  1038. parch = "posix32";
  1039. else if (plugin.build == BINARY_POSIX64)
  1040. parch = "posix64";
  1041. else if (plugin.build == BINARY_WIN32)
  1042. parch = "win32";
  1043. else if (plugin.build == BINARY_WIN64)
  1044. parch = "win64";
  1045. else if (plugin.build == BINARY_OTHER)
  1046. parch = tr("Other");
  1047. else if (plugin.build == BINARY_WIN32)
  1048. parch = tr("Unknown");
  1049. ui.l_format->setText(getPluginTypeAsString(plugin.type));
  1050. ui.l_type->setText(ptype);
  1051. ui.l_arch->setText(parch);
  1052. ui.l_id->setText(QString::number(plugin.uniqueId));
  1053. ui.l_ains->setText(QString::number(plugin.audioIns));
  1054. ui.l_aouts->setText(QString::number(plugin.audioOuts));
  1055. ui.l_cvins->setText(QString::number(plugin.cvIns));
  1056. ui.l_cvouts->setText(QString::number(plugin.cvOuts));
  1057. ui.l_mins->setText(QString::number(plugin.midiIns));
  1058. ui.l_mouts->setText(QString::number(plugin.midiOuts));
  1059. ui.l_pins->setText(QString::number(plugin.parametersIns));
  1060. ui.l_pouts->setText(QString::number(plugin.parametersOuts));
  1061. ui.l_gui->setText(plugin.hints & PLUGIN_HAS_CUSTOM_UI ? fTrYes : fTrNo);
  1062. ui.l_idisp->setText(plugin.hints & PLUGIN_HAS_INLINE_DISPLAY ? fTrYes : fTrNo);
  1063. ui.l_bridged->setText(plugin.hints & PLUGIN_IS_BRIDGE ? fTrYes : fTrNo);
  1064. ui.l_synth->setText(isSynth ? fTrYes : fTrNo);
  1065. }
  1066. else
  1067. {
  1068. ui.b_add->setEnabled(false);
  1069. ui.l_format->setText("---");
  1070. ui.l_type->setText("---");
  1071. ui.l_arch->setText("---");
  1072. ui.l_id->setText("---");
  1073. ui.l_ains->setText("---");
  1074. ui.l_aouts->setText("---");
  1075. ui.l_cvins->setText("---");
  1076. ui.l_cvouts->setText("---");
  1077. ui.l_mins->setText("---");
  1078. ui.l_mouts->setText("---");
  1079. ui.l_pins->setText("---");
  1080. ui.l_pouts->setText("---");
  1081. ui.l_gui->setText("---");
  1082. ui.l_idisp->setText("---");
  1083. ui.l_bridged->setText("---");
  1084. ui.l_synth->setText("---");
  1085. }
  1086. }
  1087. };
  1088. // --------------------------------------------------------------------------------------------------------------------
  1089. #if QT_VERSION >= 0x60000
  1090. #define PLG_SUFFIX "_2qt6"
  1091. #define TG_SUFFIX "_7qt6"
  1092. #else
  1093. #define PLG_SUFFIX "_2"
  1094. #define TG_SUFFIX "_7"
  1095. #endif
  1096. PluginListDialog::PluginListDialog(QWidget* const parent, const HostSettings& hostSettings)
  1097. : QDialog(parent),
  1098. self(Self::create(parent))
  1099. {
  1100. self.ui.setupUi(this);
  1101. self.hostSettings = hostSettings;
  1102. // ----------------------------------------------------------------------------------------------------------------
  1103. // Set-up GUI
  1104. self.ui.b_add->setEnabled(false);
  1105. addAction(self.ui.act_focus_search);
  1106. QObject::connect(self.ui.act_focus_search, &QAction::triggered,
  1107. this, &PluginListDialog::slot_focusSearchFieldAndSelectAll);
  1108. #if BINARY_NATIVE == BINARY_POSIX32 || BINARY_NATIVE == BINARY_WIN32
  1109. self.ui.ch_bridged->setText(tr("Bridged (64bit)"));
  1110. #else
  1111. self.ui.ch_bridged->setText(tr("Bridged (32bit)"));
  1112. #endif
  1113. #if !(defined(CARLA_OS_LINUX) || defined(CARLA_OS_MAC))
  1114. self.ui.ch_bridged_wine->setChecked(false);
  1115. self.ui.ch_bridged_wine->setEnabled(false);
  1116. #endif
  1117. #ifdef CARLA_OS_MAC
  1118. setWindowModality(Qt::WindowModal);
  1119. #else
  1120. self.ui.ch_au->setChecked(false);
  1121. self.ui.ch_au->setEnabled(false);
  1122. self.ui.ch_au->setVisible(false);
  1123. #endif
  1124. self.ui.tab_info->tabBar()->hide();
  1125. self.ui.tab_reqs->tabBar()->hide();
  1126. // FIXME, why /2 needed?
  1127. self.ui.tab_info->setMinimumWidth(self.ui.la_id->width()/2 +
  1128. fontMetricsHorizontalAdvance(self.ui.l_id->fontMetrics(), "9999999999") + 6*3);
  1129. setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
  1130. // ----------------------------------------------------------------------------------------------------------------
  1131. // Load settings
  1132. loadSettings();
  1133. // ----------------------------------------------------------------------------------------------------------------
  1134. // Disable bridges if not enabled in settings
  1135. #if 0
  1136. // NOTE: We Assume win32 carla build will not run win64 plugins
  1137. if (WINDOWS and not kIs64bit) or not host.showPluginBridges:
  1138. self.ui.ch_native.setChecked(True)
  1139. self.ui.ch_native.setEnabled(False)
  1140. self.ui.ch_native.setVisible(True)
  1141. self.ui.ch_bridged.setChecked(False)
  1142. self.ui.ch_bridged.setEnabled(False)
  1143. self.ui.ch_bridged.setVisible(False)
  1144. self.ui.ch_bridged_wine.setChecked(False)
  1145. self.ui.ch_bridged_wine.setEnabled(False)
  1146. self.ui.ch_bridged_wine.setVisible(False)
  1147. elif not host.showWineBridges:
  1148. self.ui.ch_bridged_wine.setChecked(False)
  1149. self.ui.ch_bridged_wine.setEnabled(False)
  1150. self.ui.ch_bridged_wine.setVisible(False)
  1151. #endif
  1152. // ----------------------------------------------------------------------------------------------------------------
  1153. // Set-up Icons
  1154. if (hostSettings.useSystemIcons)
  1155. {
  1156. #if 0
  1157. self.ui.b_add.setIcon(getIcon('list-add', 16, 'svgz'))
  1158. self.ui.b_cancel.setIcon(getIcon('dialog-cancel', 16, 'svgz'))
  1159. self.ui.b_clear_filters.setIcon(getIcon('edit-clear', 16, 'svgz'))
  1160. self.ui.b_refresh.setIcon(getIcon('view-refresh', 16, 'svgz'))
  1161. QTableWidgetItem* const hhi = self.ui.tableWidget->horizontalHeaderItem(self.TABLEWIDGET_ITEM_FAVORITE);
  1162. hhi.setIcon(getIcon('bookmarks', 16, 'svgz'))
  1163. #endif
  1164. }
  1165. // ----------------------------------------------------------------------------------------------------------------
  1166. // Set-up connections
  1167. QObject::connect(this, &QDialog::finished, this, &PluginListDialog::slot_saveSettings);
  1168. QObject::connect(self.ui.b_add, &QPushButton::clicked, this, &PluginListDialog::slot_addPlugin);
  1169. QObject::connect(self.ui.b_cancel, &QPushButton::clicked, this, &QDialog::reject);
  1170. QObject::connect(self.ui.b_refresh, &QPushButton::clicked, this, &PluginListDialog::slot_refreshPlugins);
  1171. QObject::connect(self.ui.b_clear_filters, &QPushButton::clicked, this, &PluginListDialog::slot_clearFilters);
  1172. QObject::connect(self.ui.lineEdit, &QLineEdit::textChanged, this, &PluginListDialog::slot_checkFilters);
  1173. QObject::connect(self.ui.tableWidget, &QTableWidget::currentCellChanged,
  1174. this, &PluginListDialog::slot_checkPlugin);
  1175. QObject::connect(self.ui.tableWidget, &QTableWidget::cellClicked,
  1176. this, &PluginListDialog::slot_cellClicked);
  1177. QObject::connect(self.ui.tableWidget, &QTableWidget::cellDoubleClicked,
  1178. this, &PluginListDialog::slot_cellDoubleClicked);
  1179. QObject::connect(self.ui.ch_internal, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1180. QObject::connect(self.ui.ch_ladspa, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1181. QObject::connect(self.ui.ch_dssi, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1182. QObject::connect(self.ui.ch_lv2, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1183. QObject::connect(self.ui.ch_vst, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1184. QObject::connect(self.ui.ch_vst3, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1185. QObject::connect(self.ui.ch_clap, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1186. QObject::connect(self.ui.ch_au, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1187. QObject::connect(self.ui.ch_jsfx, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1188. QObject::connect(self.ui.ch_kits, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1189. QObject::connect(self.ui.ch_effects, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1190. QObject::connect(self.ui.ch_instruments, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1191. QObject::connect(self.ui.ch_midi, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1192. QObject::connect(self.ui.ch_other, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1193. QObject::connect(self.ui.ch_native, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1194. QObject::connect(self.ui.ch_bridged, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1195. QObject::connect(self.ui.ch_bridged_wine, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1196. QObject::connect(self.ui.ch_favorites, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1197. QObject::connect(self.ui.ch_rtsafe, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1198. QObject::connect(self.ui.ch_cv, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1199. QObject::connect(self.ui.ch_gui, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1200. QObject::connect(self.ui.ch_inline_display, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1201. QObject::connect(self.ui.ch_stereo, &QCheckBox::clicked, this, &PluginListDialog::slot_checkFilters);
  1202. QObject::connect(self.ui.ch_cat_all, &QCheckBox::clicked,
  1203. this, &PluginListDialog::slot_checkFiltersCategoryAll);
  1204. QObject::connect(self.ui.ch_cat_delay, &QCheckBox::clicked,
  1205. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1206. QObject::connect(self.ui.ch_cat_distortion, &QCheckBox::clicked,
  1207. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1208. QObject::connect(self.ui.ch_cat_dynamics, &QCheckBox::clicked,
  1209. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1210. QObject::connect(self.ui.ch_cat_eq, &QCheckBox::clicked,
  1211. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1212. QObject::connect(self.ui.ch_cat_filter, &QCheckBox::clicked,
  1213. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1214. QObject::connect(self.ui.ch_cat_modulator, &QCheckBox::clicked,
  1215. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1216. QObject::connect(self.ui.ch_cat_synth, &QCheckBox::clicked,
  1217. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1218. QObject::connect(self.ui.ch_cat_utility, &QCheckBox::clicked,
  1219. this, &PluginListDialog::slot_checkFiltersCategorySpecific);
  1220. QObject::connect(self.ui.ch_cat_other, &QCheckBox::clicked, this,
  1221. &PluginListDialog::slot_checkFiltersCategorySpecific);
  1222. // ----------------------------------------------------------------------------------------------------------------
  1223. // Post-connect setup
  1224. self.checkPlugin(-1);
  1225. self.idle();
  1226. slot_focusSearchFieldAndSelectAll();
  1227. self.fTimerId = startTimer(0);
  1228. }
  1229. PluginListDialog::~PluginListDialog()
  1230. {
  1231. if (self.fTimerId != 0)
  1232. killTimer(self.fTimerId);
  1233. delete &self;
  1234. }
  1235. // --------------------------------------------------------------------------------------------------------------------
  1236. // public methods
  1237. const PluginInfo& PluginListDialog::getSelectedPluginInfo() const
  1238. {
  1239. return self.fRetPlugin;
  1240. }
  1241. // --------------------------------------------------------------------------------------------------------------------
  1242. // protected methods
  1243. void PluginListDialog::showEvent(QShowEvent* const event)
  1244. {
  1245. slot_focusSearchFieldAndSelectAll();
  1246. QDialog::showEvent(event);
  1247. }
  1248. void PluginListDialog::timerEvent(QTimerEvent* const event)
  1249. {
  1250. if (event->timerId() == self.fTimerId)
  1251. {
  1252. if (self.idle())
  1253. {
  1254. killTimer(self.fTimerId);
  1255. self.fTimerId = 0;
  1256. }
  1257. }
  1258. QDialog::timerEvent(event);
  1259. }
  1260. // --------------------------------------------------------------------------------------------------------------------
  1261. // private methods
  1262. void PluginListDialog::loadSettings()
  1263. {
  1264. const QSafeSettings settings("falkTX", "CarlaDatabase2");
  1265. self.fFavoritePlugins = settings.valueStringList("PluginDatabase/Favorites");
  1266. self.fFavoritePluginsChanged = false;
  1267. restoreGeometry(settings.valueByteArray("PluginDatabase/Geometry" PLG_SUFFIX));
  1268. self.ui.ch_effects->setChecked(settings.valueBool("PluginDatabase/ShowEffects", true));
  1269. self.ui.ch_instruments->setChecked(settings.valueBool("PluginDatabase/ShowInstruments", true));
  1270. self.ui.ch_midi->setChecked(settings.valueBool("PluginDatabase/ShowMIDI", true));
  1271. self.ui.ch_other->setChecked(settings.valueBool("PluginDatabase/ShowOther", true));
  1272. self.ui.ch_internal->setChecked(settings.valueBool("PluginDatabase/ShowInternal", true));
  1273. self.ui.ch_ladspa->setChecked(settings.valueBool("PluginDatabase/ShowLADSPA", true));
  1274. self.ui.ch_dssi->setChecked(settings.valueBool("PluginDatabase/ShowDSSI", true));
  1275. self.ui.ch_lv2->setChecked(settings.valueBool("PluginDatabase/ShowLV2", true));
  1276. self.ui.ch_vst->setChecked(settings.valueBool("PluginDatabase/ShowVST2", true));
  1277. self.ui.ch_vst3->setChecked(settings.valueBool("PluginDatabase/ShowVST3", true));
  1278. self.ui.ch_clap->setChecked(settings.valueBool("PluginDatabase/ShowCLAP", true));
  1279. #ifdef CARLA_OS_MAC
  1280. self.ui.ch_au->setChecked(settings.valueBool("PluginDatabase/ShowAU", true));
  1281. #endif
  1282. self.ui.ch_jsfx->setChecked(settings.valueBool("PluginDatabase/ShowJSFX", true));
  1283. self.ui.ch_kits->setChecked(settings.valueBool("PluginDatabase/ShowKits", true));
  1284. self.ui.ch_native->setChecked(settings.valueBool("PluginDatabase/ShowNative", true));
  1285. self.ui.ch_bridged->setChecked(settings.valueBool("PluginDatabase/ShowBridged", true));
  1286. self.ui.ch_bridged_wine->setChecked(settings.valueBool("PluginDatabase/ShowBridgedWine", true));
  1287. self.ui.ch_favorites->setChecked(settings.valueBool("PluginDatabase/ShowFavorites", false));
  1288. self.ui.ch_rtsafe->setChecked(settings.valueBool("PluginDatabase/ShowRtSafe", false));
  1289. self.ui.ch_cv->setChecked(settings.valueBool("PluginDatabase/ShowHasCV", false));
  1290. self.ui.ch_gui->setChecked(settings.valueBool("PluginDatabase/ShowHasGUI", false));
  1291. self.ui.ch_inline_display->setChecked(settings.valueBool("PluginDatabase/ShowHasInlineDisplay", false));
  1292. self.ui.ch_stereo->setChecked(settings.valueBool("PluginDatabase/ShowStereoOnly", false));
  1293. self.ui.lineEdit->setText(settings.valueString("PluginDatabase/SearchText", ""));
  1294. const QString categories = settings.valueString("PluginDatabase/ShowCategory", "all");
  1295. if (categories == "all" or categories.length() < 2)
  1296. {
  1297. self.ui.ch_cat_all->setChecked(true);
  1298. self.ui.ch_cat_delay->setChecked(false);
  1299. self.ui.ch_cat_distortion->setChecked(false);
  1300. self.ui.ch_cat_dynamics->setChecked(false);
  1301. self.ui.ch_cat_eq->setChecked(false);
  1302. self.ui.ch_cat_filter->setChecked(false);
  1303. self.ui.ch_cat_modulator->setChecked(false);
  1304. self.ui.ch_cat_synth->setChecked(false);
  1305. self.ui.ch_cat_utility->setChecked(false);
  1306. self.ui.ch_cat_other->setChecked(false);
  1307. }
  1308. else
  1309. {
  1310. self.ui.ch_cat_all->setChecked(false);
  1311. self.ui.ch_cat_delay->setChecked(categories.contains(":delay:"));
  1312. self.ui.ch_cat_distortion->setChecked(categories.contains(":distortion:"));
  1313. self.ui.ch_cat_dynamics->setChecked(categories.contains(":dynamics:"));
  1314. self.ui.ch_cat_eq->setChecked(categories.contains(":eq:"));
  1315. self.ui.ch_cat_filter->setChecked(categories.contains(":filter:"));
  1316. self.ui.ch_cat_modulator->setChecked(categories.contains(":modulator:"));
  1317. self.ui.ch_cat_synth->setChecked(categories.contains(":synth:"));
  1318. self.ui.ch_cat_utility->setChecked(categories.contains(":utility:"));
  1319. self.ui.ch_cat_other->setChecked(categories.contains(":other:"));
  1320. }
  1321. const QByteArray tableGeometry = settings.valueByteArray("PluginDatabase/TableGeometry" TG_SUFFIX);
  1322. QHeaderView* const horizontalHeader = self.ui.tableWidget->horizontalHeader();
  1323. if (! tableGeometry.isNull())
  1324. {
  1325. horizontalHeader->restoreState(tableGeometry);
  1326. }
  1327. else
  1328. {
  1329. self.ui.tableWidget->setColumnWidth(self.TABLEWIDGET_ITEM_NAME, 250);
  1330. self.ui.tableWidget->setColumnWidth(self.TABLEWIDGET_ITEM_LABEL, 200);
  1331. self.ui.tableWidget->setColumnWidth(self.TABLEWIDGET_ITEM_MAKER, 150);
  1332. self.ui.tableWidget->sortByColumn(self.TABLEWIDGET_ITEM_NAME, Qt::AscendingOrder);
  1333. }
  1334. horizontalHeader->setSectionResizeMode(self.TABLEWIDGET_ITEM_FAVORITE, QHeaderView::Fixed);
  1335. self.ui.tableWidget->setColumnWidth(self.TABLEWIDGET_ITEM_FAVORITE, 24);
  1336. self.ui.tableWidget->setSortingEnabled(true);
  1337. }
  1338. // -----------------------------------------------------------------------------------------------------------------
  1339. // private slots
  1340. void PluginListDialog::slot_cellClicked(int row, int column)
  1341. {
  1342. if (column != self.TABLEWIDGET_ITEM_FAVORITE)
  1343. return;
  1344. const QTableWidgetItem* const widget = self.ui.tableWidget->item(row, self.TABLEWIDGET_ITEM_FAVORITE);
  1345. const PluginInfo plugin = asPluginInfo(self.ui.tableWidget->item(row, self.TABLEWIDGET_ITEM_NAME)->data(Qt::UserRole+1));
  1346. #if 0
  1347. plugin = self._createFavoritePluginDict(plugin);
  1348. #endif
  1349. if (widget->checkState() == Qt::Checked)
  1350. {
  1351. #if 0
  1352. if (not plugin in self.fFavoritePlugins)
  1353. {
  1354. self.fFavoritePlugins.append(plugin);
  1355. self.fFavoritePluginsChanged = true;
  1356. }
  1357. #endif
  1358. }
  1359. else
  1360. {
  1361. #if 0
  1362. try:
  1363. self.fFavoritePlugins.remove(plugin);
  1364. self.fFavoritePluginsChanged = True;
  1365. except ValueError:
  1366. pass
  1367. #endif
  1368. }
  1369. }
  1370. void PluginListDialog::slot_cellDoubleClicked(int, int column)
  1371. {
  1372. if (column != self.TABLEWIDGET_ITEM_FAVORITE)
  1373. slot_addPlugin();
  1374. }
  1375. void PluginListDialog::slot_focusSearchFieldAndSelectAll()
  1376. {
  1377. self.ui.lineEdit->setFocus();
  1378. self.ui.lineEdit->selectAll();
  1379. }
  1380. void PluginListDialog::slot_addPlugin()
  1381. {
  1382. if (self.ui.tableWidget->currentRow() >= 0)
  1383. {
  1384. self.fRetPlugin = asPluginInfo(self.ui.tableWidget->item(self.ui.tableWidget->currentRow(),
  1385. self.TABLEWIDGET_ITEM_NAME)->data(Qt::UserRole+1));
  1386. accept();
  1387. }
  1388. else
  1389. {
  1390. reject();
  1391. }
  1392. }
  1393. void PluginListDialog::slot_checkPlugin(const int row)
  1394. {
  1395. self.checkPlugin(row);
  1396. }
  1397. void PluginListDialog::slot_checkFilters()
  1398. {
  1399. self.checkFilters();
  1400. }
  1401. void PluginListDialog::slot_checkFiltersCategoryAll(const bool clicked)
  1402. {
  1403. const bool notClicked = !clicked;
  1404. self.ui.ch_cat_delay->setChecked(notClicked);
  1405. self.ui.ch_cat_distortion->setChecked(notClicked);
  1406. self.ui.ch_cat_dynamics->setChecked(notClicked);
  1407. self.ui.ch_cat_eq->setChecked(notClicked);
  1408. self.ui.ch_cat_filter->setChecked(notClicked);
  1409. self.ui.ch_cat_modulator->setChecked(notClicked);
  1410. self.ui.ch_cat_synth->setChecked(notClicked);
  1411. self.ui.ch_cat_utility->setChecked(notClicked);
  1412. self.ui.ch_cat_other->setChecked(notClicked);
  1413. self.checkFilters();
  1414. }
  1415. void PluginListDialog::slot_checkFiltersCategorySpecific(bool clicked)
  1416. {
  1417. if (clicked)
  1418. {
  1419. self.ui.ch_cat_all->setChecked(false);
  1420. }
  1421. else if (! (self.ui.ch_cat_delay->isChecked() ||
  1422. self.ui.ch_cat_distortion->isChecked() ||
  1423. self.ui.ch_cat_dynamics->isChecked() ||
  1424. self.ui.ch_cat_eq->isChecked() ||
  1425. self.ui.ch_cat_filter->isChecked() ||
  1426. self.ui.ch_cat_modulator->isChecked() ||
  1427. self.ui.ch_cat_synth->isChecked() ||
  1428. self.ui.ch_cat_utility->isChecked() ||
  1429. self.ui.ch_cat_other->isChecked()))
  1430. {
  1431. self.ui.ch_cat_all->setChecked(true);
  1432. }
  1433. self.checkFilters();
  1434. }
  1435. void PluginListDialog::slot_refreshPlugins()
  1436. {
  1437. #if 0
  1438. if (PluginRefreshW(this, self.hostSettings, self.hasLoadedLv2Plugins).exec())
  1439. reAddPlugins();
  1440. #endif
  1441. }
  1442. void PluginListDialog::slot_clearFilters()
  1443. {
  1444. blockSignals(true);
  1445. self.ui.ch_internal->setChecked(true);
  1446. self.ui.ch_ladspa->setChecked(true);
  1447. self.ui.ch_dssi->setChecked(true);
  1448. self.ui.ch_lv2->setChecked(true);
  1449. self.ui.ch_vst->setChecked(true);
  1450. self.ui.ch_vst3->setChecked(true);
  1451. self.ui.ch_clap->setChecked(true);
  1452. self.ui.ch_jsfx->setChecked(true);
  1453. self.ui.ch_kits->setChecked(true);
  1454. self.ui.ch_instruments->setChecked(true);
  1455. self.ui.ch_effects->setChecked(true);
  1456. self.ui.ch_midi->setChecked(true);
  1457. self.ui.ch_other->setChecked(true);
  1458. self.ui.ch_native->setChecked(true);
  1459. self.ui.ch_bridged->setChecked(false);
  1460. self.ui.ch_bridged_wine->setChecked(false);
  1461. self.ui.ch_favorites->setChecked(false);
  1462. self.ui.ch_rtsafe->setChecked(false);
  1463. self.ui.ch_stereo->setChecked(false);
  1464. self.ui.ch_cv->setChecked(false);
  1465. self.ui.ch_gui->setChecked(false);
  1466. self.ui.ch_inline_display->setChecked(false);
  1467. if (self.ui.ch_au->isEnabled())
  1468. self.ui.ch_au->setChecked(true);
  1469. self.ui.ch_cat_all->setChecked(true);
  1470. self.ui.ch_cat_delay->setChecked(false);
  1471. self.ui.ch_cat_distortion->setChecked(false);
  1472. self.ui.ch_cat_dynamics->setChecked(false);
  1473. self.ui.ch_cat_eq->setChecked(false);
  1474. self.ui.ch_cat_filter->setChecked(false);
  1475. self.ui.ch_cat_modulator->setChecked(false);
  1476. self.ui.ch_cat_synth->setChecked(false);
  1477. self.ui.ch_cat_utility->setChecked(false);
  1478. self.ui.ch_cat_other->setChecked(false);
  1479. self.ui.lineEdit->clear();
  1480. blockSignals(false);
  1481. self.checkFilters();
  1482. }
  1483. // --------------------------------------------------------------------------------------------------------------------
  1484. void PluginListDialog::slot_saveSettings()
  1485. {
  1486. QSafeSettings settings("falkTX", "CarlaDatabase2");
  1487. settings.setValue("PluginDatabase/Geometry" PLG_SUFFIX, saveGeometry());
  1488. settings.setValue("PluginDatabase/TableGeometry" TG_SUFFIX, self.ui.tableWidget->horizontalHeader()->saveState());
  1489. settings.setValue("PluginDatabase/ShowEffects", self.ui.ch_effects->isChecked());
  1490. settings.setValue("PluginDatabase/ShowInstruments", self.ui.ch_instruments->isChecked());
  1491. settings.setValue("PluginDatabase/ShowMIDI", self.ui.ch_midi->isChecked());
  1492. settings.setValue("PluginDatabase/ShowOther", self.ui.ch_other->isChecked());
  1493. settings.setValue("PluginDatabase/ShowInternal", self.ui.ch_internal->isChecked());
  1494. settings.setValue("PluginDatabase/ShowLADSPA", self.ui.ch_ladspa->isChecked());
  1495. settings.setValue("PluginDatabase/ShowDSSI", self.ui.ch_dssi->isChecked());
  1496. settings.setValue("PluginDatabase/ShowLV2", self.ui.ch_lv2->isChecked());
  1497. settings.setValue("PluginDatabase/ShowVST2", self.ui.ch_vst->isChecked());
  1498. settings.setValue("PluginDatabase/ShowVST3", self.ui.ch_vst3->isChecked());
  1499. settings.setValue("PluginDatabase/ShowCLAP", self.ui.ch_clap->isChecked());
  1500. settings.setValue("PluginDatabase/ShowAU", self.ui.ch_au->isChecked());
  1501. settings.setValue("PluginDatabase/ShowJSFX", self.ui.ch_jsfx->isChecked());
  1502. settings.setValue("PluginDatabase/ShowKits", self.ui.ch_kits->isChecked());
  1503. settings.setValue("PluginDatabase/ShowNative", self.ui.ch_native->isChecked());
  1504. settings.setValue("PluginDatabase/ShowBridged", self.ui.ch_bridged->isChecked());
  1505. settings.setValue("PluginDatabase/ShowBridgedWine", self.ui.ch_bridged_wine->isChecked());
  1506. settings.setValue("PluginDatabase/ShowFavorites", self.ui.ch_favorites->isChecked());
  1507. settings.setValue("PluginDatabase/ShowRtSafe", self.ui.ch_rtsafe->isChecked());
  1508. settings.setValue("PluginDatabase/ShowHasCV", self.ui.ch_cv->isChecked());
  1509. settings.setValue("PluginDatabase/ShowHasGUI", self.ui.ch_gui->isChecked());
  1510. settings.setValue("PluginDatabase/ShowHasInlineDisplay", self.ui.ch_inline_display->isChecked());
  1511. settings.setValue("PluginDatabase/ShowStereoOnly", self.ui.ch_stereo->isChecked());
  1512. settings.setValue("PluginDatabase/SearchText", self.ui.lineEdit->text());
  1513. if (self.ui.ch_cat_all->isChecked())
  1514. {
  1515. settings.setValue("PluginDatabase/ShowCategory", "all");
  1516. }
  1517. else
  1518. {
  1519. QCarlaString categories;
  1520. if (self.ui.ch_cat_delay->isChecked())
  1521. categories += ":delay";
  1522. if (self.ui.ch_cat_distortion->isChecked())
  1523. categories += ":distortion";
  1524. if (self.ui.ch_cat_dynamics->isChecked())
  1525. categories += ":dynamics";
  1526. if (self.ui.ch_cat_eq->isChecked())
  1527. categories += ":eq";
  1528. if (self.ui.ch_cat_filter->isChecked())
  1529. categories += ":filter";
  1530. if (self.ui.ch_cat_modulator->isChecked())
  1531. categories += ":modulator";
  1532. if (self.ui.ch_cat_synth->isChecked())
  1533. categories += ":synth";
  1534. if (self.ui.ch_cat_utility->isChecked())
  1535. categories += ":utility";
  1536. if (self.ui.ch_cat_other->isChecked())
  1537. categories += ":other";
  1538. if (categories.isNotEmpty())
  1539. categories += ":";
  1540. settings.setValue("PluginDatabase/ShowCategory", categories);
  1541. }
  1542. if (self.fFavoritePluginsChanged)
  1543. settings.setValue("PluginDatabase/Favorites", self.fFavoritePlugins);
  1544. }
  1545. // --------------------------------------------------------------------------------------------------------------------
  1546. const PluginListDialogResults*
  1547. carla_frontend_createAndExecPluginListDialog(void* const parent/*, const HostSettings& hostSettings*/)
  1548. {
  1549. const HostSettings hostSettings = {};
  1550. PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings);
  1551. if (gui.exec())
  1552. {
  1553. static PluginListDialogResults ret;
  1554. static CarlaString category;
  1555. static CarlaString filename;
  1556. static CarlaString name;
  1557. static CarlaString label;
  1558. static CarlaString maker;
  1559. const PluginInfo& plugin(gui.getSelectedPluginInfo());
  1560. category = plugin.category.toUtf8();
  1561. filename = plugin.filename.toUtf8();
  1562. name = plugin.name.toUtf8();
  1563. label = plugin.label.toUtf8();
  1564. maker = plugin.maker.toUtf8();
  1565. ret.API = plugin.API;
  1566. ret.build = plugin.build;
  1567. ret.type = plugin.type;
  1568. ret.hints = plugin.hints;
  1569. ret.category = category;
  1570. ret.filename = filename;
  1571. ret.name = name;
  1572. ret.label = label;
  1573. ret.maker = maker;
  1574. ret.audioIns = plugin.audioIns;
  1575. ret.audioOuts = plugin.audioOuts;
  1576. ret.cvIns = plugin.cvIns;
  1577. ret.cvOuts = plugin.cvOuts;
  1578. ret.midiIns = plugin.midiIns;
  1579. ret.midiOuts = plugin.midiOuts;
  1580. ret.parametersIns = plugin.parametersIns;
  1581. ret.parametersOuts = plugin.parametersOuts;
  1582. return &ret;
  1583. }
  1584. return nullptr;
  1585. }
  1586. // --------------------------------------------------------------------------------------------------------------------