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.

454 lines
14KB

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