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.

carla_database.cpp 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /*
  2. * Carla plugin database code
  3. * Copyright (C) 2011-2019 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 "carla_database.hpp"
  18. //---------------------------------------------------------------------------------------------------------------------
  19. // Imports (Global)
  20. #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  21. # pragma GCC diagnostic push
  22. # pragma GCC diagnostic ignored "-Wconversion"
  23. # pragma GCC diagnostic ignored "-Weffc++"
  24. # pragma GCC diagnostic ignored "-Wsign-conversion"
  25. #endif
  26. //---------------------------------------------------------------------------------------------------------------------
  27. #include <QtCore/QDir>
  28. #include <QtCore/QFileInfo>
  29. #include <QtWidgets/QPushButton>
  30. //---------------------------------------------------------------------------------------------------------------------
  31. #include "ui_carla_add_jack.hpp"
  32. #include "ui_carla_database.hpp"
  33. #include "ui_carla_refresh.hpp"
  34. //---------------------------------------------------------------------------------------------------------------------
  35. #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  36. # pragma GCC diagnostic pop
  37. #endif
  38. //---------------------------------------------------------------------------------------------------------------------
  39. // Imports (Custom)
  40. #include "carla_host.hpp"
  41. #include "CarlaHost.h"
  42. #include "CarlaLibJackHints.h"
  43. // --------------------------------------------------------------------------------------------------------------------
  44. // Separate Thread for Plugin Search
  45. struct WineSettings {
  46. QString executable;
  47. bool autoPrefix;
  48. QString fallbackPrefix;
  49. WineSettings()
  50. : executable(),
  51. autoPrefix(false),
  52. fallbackPrefix()
  53. {
  54. const QSafeSettings settings("falkTX", "Carla2");
  55. executable = settings.valueString(CARLA_KEY_WINE_EXECUTABLE, CARLA_DEFAULT_WINE_EXECUTABLE);
  56. autoPrefix = settings.valueBool(CARLA_KEY_WINE_AUTO_PREFIX, CARLA_DEFAULT_WINE_AUTO_PREFIX);
  57. fallbackPrefix = settings.valueString(CARLA_KEY_WINE_FALLBACK_PREFIX, CARLA_DEFAULT_WINE_FALLBACK_PREFIX);
  58. }
  59. };
  60. struct SearchPluginsThread::PrivateData {
  61. bool fContinueChecking;
  62. QString fPathBinaries;
  63. bool fCheckNative;
  64. bool fCheckPosix32;
  65. bool fCheckPosix64;
  66. bool fCheckWin32;
  67. bool fCheckWin64;
  68. bool fCheckLADSPA;
  69. bool fCheckDSSI;
  70. bool fCheckLV2;
  71. bool fCheckVST2;
  72. bool fCheckVST3;
  73. bool fCheckAU;
  74. bool fCheckSF2;
  75. bool fCheckSFZ;
  76. WineSettings fWineSettings;
  77. QString fToolNative;
  78. uint fCurCount;
  79. uint fCurPercentValue;
  80. uint fLastCheckValue;
  81. bool fSomethingChanged;
  82. PrivateData(void*, const QString pathBinaries)
  83. : fContinueChecking(false),
  84. fPathBinaries(pathBinaries),
  85. fCheckNative(false),
  86. fCheckPosix32(false),
  87. fCheckPosix64(false),
  88. fCheckWin32(false),
  89. fCheckWin64(false),
  90. fCheckLADSPA(false),
  91. fCheckDSSI(false),
  92. fCheckLV2(false),
  93. fCheckVST2(false),
  94. fCheckVST3(false),
  95. fCheckAU(false),
  96. fCheckSF2(false),
  97. fCheckSFZ(false),
  98. fWineSettings(),
  99. fToolNative(),
  100. fCurCount(0),
  101. fCurPercentValue(0),
  102. fLastCheckValue(0),
  103. fSomethingChanged(false)
  104. {
  105. }
  106. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  107. };
  108. SearchPluginsThread::SearchPluginsThread(QObject* parent, const QString pathBinaries)
  109. : QThread(parent),
  110. self(new PrivateData(this, pathBinaries))
  111. {
  112. }
  113. SearchPluginsThread::~SearchPluginsThread()
  114. {
  115. delete self;
  116. }
  117. void SearchPluginsThread::run()
  118. {
  119. }
  120. // --------------------------------------------------------------------------------------------------------------------
  121. // Plugin Refresh Dialog
  122. struct PluginRefreshW::PrivateData {
  123. Ui::PluginRefreshW ui;
  124. SearchPluginsThread fThread;
  125. QPixmap fIconYes;
  126. QPixmap fIconNo;
  127. PrivateData(PluginRefreshW* const refreshDialog, const CarlaHost& host)
  128. : ui(),
  129. fThread(refreshDialog, host.pathBinaries),
  130. fIconYes(":/16x16/dialog-ok-apply.svgz"),
  131. fIconNo(":/16x16/dialog-error.svgz")
  132. {
  133. ui.setupUi(refreshDialog);
  134. // ------------------------------------------------------------------------------------------------------------
  135. // Internal stuff
  136. const bool hasNative = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-native");
  137. const bool hasPosix32 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-posix32");
  138. const bool hasPosix64 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-posix64");
  139. const bool hasWin32 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-win32.exe");
  140. const bool hasWin64 = QFileInfo::exists(host.pathBinaries + CARLA_OS_SEP_STR "carla-discovery-win64.exe");
  141. }
  142. void loadSettings()
  143. {
  144. }
  145. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  146. };
  147. PluginRefreshW::PluginRefreshW(QWidget* const parent, const CarlaHost& host)
  148. : QDialog(parent),
  149. self(new PrivateData(this, host))
  150. {
  151. // ----------------------------------------------------------------------------------------------------------------
  152. // Resize to minimum size, as it's very likely UI stuff was hidden
  153. resize(minimumSize());
  154. // ----------------------------------------------------------------------------------------------------------------
  155. // Set-up connections
  156. connect(this, SIGNAL(finished(int)), SLOT(slot_saveSettings()));
  157. connect(self->ui.b_start, SIGNAL(clicked()), SLOT(slot_start()));
  158. connect(self->ui.b_skip, SIGNAL(clicked()), SLOT(slot_skip()));
  159. connect(self->ui.ch_native, SIGNAL(clicked()), SLOT(slot_checkTools()));
  160. connect(self->ui.ch_posix32, SIGNAL(clicked()), SLOT(slot_checkTools()));
  161. connect(self->ui.ch_posix64, SIGNAL(clicked()), SLOT(slot_checkTools()));
  162. connect(self->ui.ch_win32, SIGNAL(clicked()), SLOT(slot_checkTools()));
  163. connect(self->ui.ch_win64, SIGNAL(clicked()), SLOT(slot_checkTools()));
  164. connect(self->ui.ch_ladspa, SIGNAL(clicked()), SLOT(slot_checkTools()));
  165. connect(self->ui.ch_dssi, SIGNAL(clicked()), SLOT(slot_checkTools()));
  166. connect(self->ui.ch_lv2, SIGNAL(clicked()), SLOT(slot_checkTools()));
  167. connect(self->ui.ch_vst, SIGNAL(clicked()), SLOT(slot_checkTools()));
  168. connect(self->ui.ch_vst3, SIGNAL(clicked()), SLOT(slot_checkTools()));
  169. connect(self->ui.ch_au, SIGNAL(clicked()), SLOT(slot_checkTools()));
  170. connect(self->ui.ch_sf2, SIGNAL(clicked()), SLOT(slot_checkTools()));
  171. connect(self->ui.ch_sfz, SIGNAL(clicked()), SLOT(slot_checkTools()));
  172. connect(&self->fThread, SIGNAL(pluginLook(float, QString)), SLOT(slot_handlePluginLook(float, QString)));
  173. connect(&self->fThread, SIGNAL(finished(int)), SLOT(slot_handlePluginThreadFinished()));
  174. // ----------------------------------------------------------------------------------------------------------------
  175. // Post-connect setup
  176. slot_checkTools();
  177. }
  178. PluginRefreshW::~PluginRefreshW()
  179. {
  180. delete self;
  181. }
  182. void PluginRefreshW::getValues(QString& audioDevice, uint& bufferSize, double& sampleRate)
  183. {
  184. }
  185. void PluginRefreshW::closeEvent(QCloseEvent* event)
  186. {
  187. }
  188. void PluginRefreshW::slot_saveSettings()
  189. {
  190. }
  191. void PluginRefreshW::slot_start()
  192. {
  193. }
  194. void PluginRefreshW::slot_skip()
  195. {
  196. }
  197. void PluginRefreshW::slot_checkTools()
  198. {
  199. }
  200. void PluginRefreshW::slot_handlePluginLook(float percent, QString plugin)
  201. {
  202. }
  203. void PluginRefreshW::slot_handlePluginThreadFinished()
  204. {
  205. }
  206. // --------------------------------------------------------------------------------------------------------------------
  207. // Plugin Database Dialog
  208. struct PluginDatabaseW::PrivateData {
  209. PrivateData(void*)
  210. {
  211. }
  212. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  213. };
  214. PluginDatabaseW::PluginDatabaseW(QWidget* parent, const CarlaHost& host, bool hasCanvas, bool hasCanvasGL)
  215. : QDialog(parent),
  216. self(new PrivateData(this))
  217. {
  218. }
  219. PluginDatabaseW::~PluginDatabaseW()
  220. {
  221. delete self;
  222. }
  223. void PluginDatabaseW::showEvent(QShowEvent* event)
  224. {
  225. }
  226. void PluginDatabaseW::slot_cellClicked(int row, int column)
  227. {
  228. }
  229. void PluginDatabaseW::slot_cellDoubleClicked(int row, int column)
  230. {
  231. }
  232. void PluginDatabaseW::slot_addPlugin()
  233. {
  234. }
  235. void PluginDatabaseW::slot_checkPlugin(int row)
  236. {
  237. }
  238. void PluginDatabaseW::slot_checkFilters()
  239. {
  240. }
  241. void PluginDatabaseW::slot_refreshPlugins()
  242. {
  243. }
  244. void PluginDatabaseW::slot_clearFilters()
  245. {
  246. }
  247. void PluginDatabaseW::slot_saveSettings()
  248. {
  249. }
  250. // --------------------------------------------------------------------------------------------------------------------
  251. // Jack Application Dialog
  252. // NOTE: index matches the one in the UI
  253. enum UiSessionManager {
  254. UI_SESSION_NONE,
  255. UI_SESSION_LADISH,
  256. UI_SESSION_NSM
  257. };
  258. struct JackApplicationW::PrivateData {
  259. Ui::Dialog ui;
  260. PrivateData(JackApplicationW* const dialog)
  261. : ui()
  262. {
  263. ui.setupUi(dialog);
  264. // ------------------------------------------------------------------------------------------------------------
  265. // Load settings
  266. loadSettings();
  267. }
  268. void checkIfButtonBoxShouldBeEnabled(int index, const QString text)
  269. {
  270. static QList<QChar> badFirstChars = { '.', '/' };
  271. bool enabled = text.length() > 0;
  272. // NSM applications must not be abstract or absolute paths, and must not contain arguments
  273. if (enabled && index == UI_SESSION_NSM)
  274. enabled = ! (badFirstChars.contains(text[0]) || text.contains(' '));
  275. if (QPushButton* const button = ui.buttonBox->button(QDialogButtonBox::Ok))
  276. button->setEnabled(enabled);
  277. }
  278. void loadSettings()
  279. {
  280. const QSafeSettings settings("falkTX", "CarlaAddJackApp");
  281. const QString smName = settings.valueString("SessionManager", "");
  282. if (smName == "LADISH (SIGUSR1)")
  283. ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH);
  284. else if (smName == "NSM")
  285. ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM);
  286. else
  287. ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE);
  288. ui.le_command->setText(settings.valueString("Command", ""));
  289. ui.le_name->setText(settings.valueString("Name", ""));
  290. ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
  291. ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
  292. ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2));
  293. ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0));
  294. ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0));
  295. ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true));
  296. ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false));
  297. ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false));
  298. checkIfButtonBoxShouldBeEnabled(ui.cb_session_mgr->currentIndex(), ui.le_command->text());
  299. }
  300. void saveSettings()
  301. {
  302. QSafeSettings settings("falkTX", "CarlaAddJackApp");
  303. settings.setValue("Command", ui.le_command->text());
  304. settings.setValue("Name", ui.le_name->text());
  305. settings.setValue("SessionManager", ui.cb_session_mgr->currentText());
  306. settings.setValue("NumAudioIns", ui.sb_audio_ins->value());
  307. settings.setValue("NumAudioOuts", ui.sb_audio_outs->value());
  308. settings.setValue("NumMidiIns", ui.sb_midi_ins->value());
  309. settings.setValue("NumMidiOuts", ui.sb_midi_outs->value());
  310. settings.setValue("ManageWindow", ui.cb_manage_window->isChecked());
  311. settings.setValue("CaptureFirstWindow", ui.cb_capture_first_window->isChecked());
  312. settings.setValue("MidiOutMixdown", ui.cb_out_midi_mixdown->isChecked());
  313. }
  314. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData)
  315. };
  316. JackApplicationW::JackApplicationW(QWidget* parent)
  317. : QDialog(parent),
  318. self(new PrivateData(this))
  319. {
  320. setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
  321. // ----------------------------------------------------------------------------------------------------------------
  322. // Set-up connections
  323. connect(this, SIGNAL(finished(int)), SLOT(slot_saveSettings()));
  324. connect(self->ui.cb_session_mgr, SIGNAL(currentIndexChanged(int)), SLOT(slot_sessionManagerChanged(int)));
  325. connect(self->ui.le_command, SIGNAL(textChanged(QString)), SLOT(slot_commandChanged(QString)));
  326. }
  327. JackApplicationW::~JackApplicationW()
  328. {
  329. delete self;
  330. }
  331. void JackApplicationW::getCommandAndFlags(QString& command, QString& name, QString& labelSetup)
  332. {
  333. name = self->ui.le_name->text();
  334. command = self->ui.le_command->text();
  335. if (name.isEmpty())
  336. {
  337. name = QFileInfo(command.split(' ').first()).baseName();
  338. // FIXME
  339. name[0] = name[0].toTitleCase();
  340. }
  341. SessionManager smgr;
  342. switch (self->ui.cb_session_mgr->currentIndex())
  343. {
  344. case UI_SESSION_LADISH:
  345. smgr = LIBJACK_SESSION_MANAGER_LADISH;
  346. break;
  347. case UI_SESSION_NSM:
  348. smgr = LIBJACK_SESSION_MANAGER_NSM;
  349. break;
  350. default:
  351. smgr = LIBJACK_SESSION_MANAGER_NONE;
  352. break;
  353. }
  354. uint flags = 0x0;
  355. if (self->ui.cb_manage_window->isChecked())
  356. flags |= LIBJACK_FLAG_CONTROL_WINDOW;
  357. if (self->ui.cb_capture_first_window->isChecked())
  358. flags |= LIBJACK_FLAG_CAPTURE_FIRST_WINDOW;
  359. if (self->ui.cb_buffers_addition_mode->isChecked())
  360. flags |= LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION;
  361. if (self->ui.cb_out_midi_mixdown->isChecked())
  362. flags |= LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN;
  363. if (self->ui.cb_external_start->isChecked())
  364. flags |= LIBJACK_FLAG_EXTERNAL_START;
  365. labelSetup = QString("%1%2%3%4%5%6").arg(QChar('0' + self->ui.sb_audio_ins->value()))
  366. .arg(QChar('0' + self->ui.sb_audio_outs->value()))
  367. .arg(QChar('0' + self->ui.sb_midi_ins->value()))
  368. .arg(QChar('0' + self->ui.sb_midi_outs->value()))
  369. .arg(QChar('0' + smgr))
  370. .arg(QChar('0' + flags));
  371. }
  372. void JackApplicationW::slot_commandChanged(const QString text)
  373. {
  374. self->checkIfButtonBoxShouldBeEnabled(self->ui.cb_session_mgr->currentIndex(), text);
  375. }
  376. void JackApplicationW::slot_sessionManagerChanged(const int index)
  377. {
  378. self->checkIfButtonBoxShouldBeEnabled(index, self->ui.le_command->text());
  379. }
  380. void JackApplicationW::slot_saveSettings()
  381. {
  382. self->saveSettings();
  383. }
  384. // --------------------------------------------------------------------------------------------------------------------