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.

2805 lines
95KB

  1. /*
  2. * Carla plugin host
  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_host.hpp"
  18. //---------------------------------------------------------------------------------------------------------------------
  19. // Imports (Global)
  20. #include <QtCore/QDir>
  21. #include <QtCore/QStringList>
  22. #include <QtCore/QTimer>
  23. #include <QtGui/QPainter>
  24. #include <QtWidgets/QFileDialog>
  25. #include <QtWidgets/QFileSystemModel>
  26. #include <QtWidgets/QMainWindow>
  27. #include <QtWidgets/QMessageBox>
  28. //---------------------------------------------------------------------------------------------------------------------
  29. // Imports (Custom)
  30. #include "ui_carla_host.hpp"
  31. #include "carla_database.hpp"
  32. #include "carla_settings.hpp"
  33. #include "carla_skin.hpp"
  34. #include "CarlaHost.h"
  35. #include "CarlaUtils.h"
  36. #include "CarlaBackendUtils.hpp"
  37. #include "CarlaMathUtils.hpp"
  38. #include "CarlaString.hpp"
  39. // FIXME put in right place
  40. static QString fixLogText(QString text)
  41. {
  42. //v , Qt::CaseSensitive
  43. return text.replace("\x1b[30;1m", "").replace("\x1b[31m", "").replace("\x1b[0m", "");
  44. }
  45. //---------------------------------------------------------------------------------------------------------------------
  46. // Session Management support
  47. static const char* const CARLA_CLIENT_NAME = getenv("CARLA_CLIENT_NAME");
  48. static const char* const LADISH_APP_NAME = getenv("LADISH_APP_NAME");
  49. static const char* const NSM_URL = getenv("NSM_URL");
  50. //---------------------------------------------------------------------------------------------------------------------
  51. CarlaHost::CarlaHost()
  52. : QObject(),
  53. isControl(false),
  54. isPlugin(false),
  55. isRemote(false),
  56. nsmOK(false),
  57. processMode(ENGINE_PROCESS_MODE_PATCHBAY),
  58. transportMode(ENGINE_TRANSPORT_MODE_INTERNAL),
  59. transportExtra(),
  60. nextProcessMode(processMode),
  61. processModeForced(false),
  62. audioDriverForced(),
  63. experimental(false),
  64. exportLV2(false),
  65. forceStereo(false),
  66. manageUIs(false),
  67. maxParameters(false),
  68. preferPluginBridges(false),
  69. preferUIBridges(false),
  70. preventBadBehaviour(false),
  71. showLogs(false),
  72. showPluginBridges(false),
  73. showWineBridges(false),
  74. uiBridgesTimeout(0),
  75. uisAlwaysOnTop(false),
  76. pathBinaries(),
  77. pathResources() {}
  78. //---------------------------------------------------------------------------------------------------------------------
  79. // Carla Host Window
  80. enum CustomActions {
  81. CUSTOM_ACTION_NONE,
  82. CUSTOM_ACTION_APP_CLOSE,
  83. CUSTOM_ACTION_PROJECT_LOAD
  84. };
  85. struct CachedSavedSettings {
  86. uint _CARLA_KEY_MAIN_REFRESH_INTERVAL = 0;
  87. bool _CARLA_KEY_MAIN_CONFIRM_EXIT = false;
  88. bool _CARLA_KEY_CANVAS_FANCY_EYE_CANDY = false;
  89. };
  90. //---------------------------------------------------------------------------------------------------------------------
  91. struct CarlaHostWindow::PrivateData {
  92. Ui::CarlaHostW ui;
  93. CarlaHost& host;
  94. CarlaHostWindow* const hostWindow;
  95. //-----------------------------------------------------------------------------------------------------------------
  96. // Internal stuff
  97. QWidget* const fParentOrSelf;
  98. int fIdleTimerNull; // to keep application signals alive
  99. int fIdleTimerFast;
  100. int fIdleTimerSlow;
  101. bool fLadspaRdfNeedsUpdate;
  102. QList<void*> fLadspaRdfList;
  103. int fPluginCount;
  104. QList<QWidget*> fPluginList;
  105. void* fPluginDatabaseDialog;
  106. QStringList fFavoritePlugins;
  107. QCarlaString fProjectFilename;
  108. bool fIsProjectLoading;
  109. bool fCurrentlyRemovingAllPlugins;
  110. double fLastTransportBPM;
  111. uint64_t fLastTransportFrame;
  112. bool fLastTransportState;
  113. uint fBufferSize;
  114. double fSampleRate;
  115. QCarlaString fOscAddressTCP;
  116. QCarlaString fOscAddressUDP;
  117. QCarlaString fOscReportedHost;
  118. #ifdef CARLA_OS_MAC
  119. bool fMacClosingHelper;
  120. #endif
  121. // CancelableActionCallback Box
  122. void* fCancelableActionBox;
  123. // run a custom action after engine is properly closed
  124. CustomActions fCustomStopAction;
  125. // first attempt of auto-start engine doesn't show an error
  126. bool fFirstEngineInit;
  127. // to be filled with key-value pairs of current settings
  128. CachedSavedSettings fSavedSettings;
  129. QCarlaString fClientName;
  130. QCarlaString fSessionManagerName;
  131. //-----------------------------------------------------------------------------------------------------------------
  132. // Internal stuff (patchbay)
  133. QImage fExportImage;
  134. bool fPeaksCleared;
  135. bool fExternalPatchbay;
  136. QList<uint> fSelectedPlugins;
  137. int fCanvasWidth;
  138. int fCanvasHeight;
  139. int fMiniCanvasUpdateTimeout;
  140. const bool fWithCanvas;
  141. //-----------------------------------------------------------------------------------------------------------------
  142. // GUI stuff (disk)
  143. QFileSystemModel fDirModel;
  144. //-----------------------------------------------------------------------------------------------------------------
  145. // CarlaHostWindow* hostWindow,
  146. PrivateData(CarlaHostWindow* const hw, CarlaHost& h, const bool withCanvas)
  147. : ui(),
  148. host(h),
  149. hostWindow(hw),
  150. // Internal stuff
  151. fParentOrSelf(hw->parentWidget() != nullptr ? hw->parentWidget() : hw),
  152. fIdleTimerNull(0),
  153. fIdleTimerFast(0),
  154. fIdleTimerSlow(0),
  155. fLadspaRdfNeedsUpdate(true),
  156. fLadspaRdfList(),
  157. fPluginCount(0),
  158. fPluginList(),
  159. fPluginDatabaseDialog(nullptr),
  160. fFavoritePlugins(),
  161. fProjectFilename(),
  162. fIsProjectLoading(false),
  163. fCurrentlyRemovingAllPlugins(false),
  164. fLastTransportBPM(0.0),
  165. fLastTransportFrame(0),
  166. fLastTransportState(false),
  167. fBufferSize(0),
  168. fSampleRate(0.0),
  169. fOscAddressTCP(),
  170. fOscAddressUDP(),
  171. fOscReportedHost(),
  172. #ifdef CARLA_OS_MAC
  173. fMacClosingHelper(true),
  174. #endif
  175. fCancelableActionBox(nullptr),
  176. fCustomStopAction(CUSTOM_ACTION_NONE),
  177. fFirstEngineInit(true),
  178. fSavedSettings(),
  179. fClientName(),
  180. fSessionManagerName(),
  181. // Internal stuff (patchbay)
  182. fExportImage(),
  183. fPeaksCleared(true),
  184. fExternalPatchbay(false),
  185. fSelectedPlugins(),
  186. fCanvasWidth(0),
  187. fCanvasHeight(0),
  188. fMiniCanvasUpdateTimeout(0),
  189. fWithCanvas(withCanvas),
  190. // disk
  191. fDirModel(hostWindow)
  192. {
  193. ui.setupUi(hostWindow);
  194. //-------------------------------------------------------------------------------------------------------------
  195. // Internal stuff
  196. if (host.isControl)
  197. {
  198. fClientName = "Carla-Control";
  199. fSessionManagerName = "Control";
  200. }
  201. else if (host.isPlugin)
  202. {
  203. fClientName = "Carla-Plugin";
  204. fSessionManagerName = "Plugin";
  205. }
  206. else if (LADISH_APP_NAME != nullptr)
  207. {
  208. fClientName = LADISH_APP_NAME;
  209. fSessionManagerName = "LADISH";
  210. }
  211. else if (NSM_URL != nullptr && host.nsmOK)
  212. {
  213. fClientName = "Carla.tmp";
  214. fSessionManagerName = "Non Session Manager TMP";
  215. }
  216. else
  217. {
  218. fClientName = CARLA_CLIENT_NAME != nullptr ? CARLA_CLIENT_NAME : "Carla";
  219. fSessionManagerName = "";
  220. }
  221. //-------------------------------------------------------------------------------------------------------------
  222. // Set up GUI (engine stopped)
  223. if (host.isPlugin || host.isControl)
  224. {
  225. ui.act_file_save->setVisible(false);
  226. ui.act_engine_start->setEnabled(false);
  227. ui.act_engine_start->setVisible(false);
  228. ui.act_engine_stop->setEnabled(false);
  229. ui.act_engine_stop->setVisible(false);
  230. ui.menu_Engine->setEnabled(false);
  231. ui.menu_Engine->setVisible(false);
  232. if (QAction* const action = ui.menu_Engine->menuAction())
  233. action->setVisible(false);
  234. ui.tabWidget->removeTab(2);
  235. if (host.isControl)
  236. {
  237. ui.act_file_new->setVisible(false);
  238. ui.act_file_open->setVisible(false);
  239. ui.act_file_save_as->setVisible(false);
  240. ui.tabUtils->removeTab(0);
  241. }
  242. else
  243. {
  244. ui.act_file_save_as->setText(tr("Export as..."));
  245. if (! withCanvas)
  246. if (QTabBar* const tabBar = ui.tabWidget->tabBar())
  247. tabBar->hide();
  248. }
  249. }
  250. else
  251. {
  252. ui.act_engine_start->setEnabled(true);
  253. #ifdef CARLA_OS_WIN
  254. ui.tabWidget->removeTab(2);
  255. #endif
  256. }
  257. if (host.isControl)
  258. {
  259. ui.act_file_refresh->setEnabled(false);
  260. }
  261. else
  262. {
  263. ui.act_file_connect->setEnabled(false);
  264. ui.act_file_connect->setVisible(false);
  265. ui.act_file_refresh->setEnabled(false);
  266. ui.act_file_refresh->setVisible(false);
  267. }
  268. if (fSessionManagerName.isNotEmpty() && ! host.isPlugin)
  269. ui.act_file_new->setEnabled(false);
  270. ui.act_file_open->setEnabled(false);
  271. ui.act_file_save->setEnabled(false);
  272. ui.act_file_save_as->setEnabled(false);
  273. ui.act_engine_stop->setEnabled(false);
  274. ui.act_plugin_remove_all->setEnabled(false);
  275. ui.act_canvas_show_internal->setChecked(false);
  276. ui.act_canvas_show_internal->setVisible(false);
  277. ui.act_canvas_show_external->setChecked(false);
  278. ui.act_canvas_show_external->setVisible(false);
  279. ui.menu_PluginMacros->setEnabled(false);
  280. ui.menu_Canvas->setEnabled(false);
  281. QWidget* const dockWidgetTitleBar = new QWidget(hostWindow);
  282. ui.dockWidget->setTitleBarWidget(dockWidgetTitleBar);
  283. if (! withCanvas)
  284. {
  285. ui.act_canvas_show_internal->setVisible(false);
  286. ui.act_canvas_show_external->setVisible(false);
  287. ui.act_canvas_arrange->setVisible(false);
  288. ui.act_canvas_refresh->setVisible(false);
  289. ui.act_canvas_save_image->setVisible(false);
  290. ui.act_canvas_zoom_100->setVisible(false);
  291. ui.act_canvas_zoom_fit->setVisible(false);
  292. ui.act_canvas_zoom_in->setVisible(false);
  293. ui.act_canvas_zoom_out->setVisible(false);
  294. ui.act_settings_show_meters->setVisible(false);
  295. ui.act_settings_show_keyboard->setVisible(false);
  296. ui.menu_Canvas_Zoom->setEnabled(false);
  297. ui.menu_Canvas_Zoom->setVisible(false);
  298. if (QAction* const action = ui.menu_Canvas_Zoom->menuAction())
  299. action->setVisible(false);
  300. ui.menu_Canvas->setEnabled(false);
  301. ui.menu_Canvas->setVisible(false);
  302. if (QAction* const action = ui.menu_Canvas->menuAction())
  303. action->setVisible(false);
  304. ui.tw_miniCanvas->hide();
  305. ui.tabWidget->removeTab(1);
  306. #ifdef CARLA_OS_WIN
  307. ui.tabWidget->tabBar().hide()
  308. #endif
  309. }
  310. //-------------------------------------------------------------------------------------------------------------
  311. // Set up GUI (disk)
  312. const QString home(QDir::homePath());
  313. fDirModel.setRootPath(home);
  314. if (const char* const* const exts = carla_get_supported_file_extensions())
  315. {
  316. QStringList filters;
  317. const QString prefix("*.");
  318. for (uint i=0; exts[i] != nullptr; ++i)
  319. filters.append(prefix + exts[i]);
  320. fDirModel.setNameFilters(filters);
  321. }
  322. ui.fileTreeView->setModel(&fDirModel);
  323. ui.fileTreeView->setRootIndex(fDirModel.index(home));
  324. ui.fileTreeView->setColumnHidden(1, true);
  325. ui.fileTreeView->setColumnHidden(2, true);
  326. ui.fileTreeView->setColumnHidden(3, true);
  327. ui.fileTreeView->setHeaderHidden(true);
  328. //-------------------------------------------------------------------------------------------------------------
  329. // Set up GUI (transport)
  330. const QFontMetrics fontMetrics(ui.l_transport_bbt->fontMetrics());
  331. int minValueWidth = fontMetricsHorizontalAdvance(fontMetrics, "000|00|0000");
  332. int minLabelWidth = fontMetricsHorizontalAdvance(fontMetrics, ui.label_transport_frame->text());
  333. int labelTimeWidth = fontMetricsHorizontalAdvance(fontMetrics, ui.label_transport_time->text());
  334. int labelBBTWidth = fontMetricsHorizontalAdvance(fontMetrics, ui.label_transport_bbt->text());
  335. if (minLabelWidth < labelTimeWidth)
  336. minLabelWidth = labelTimeWidth;
  337. if (minLabelWidth < labelBBTWidth)
  338. minLabelWidth = labelBBTWidth;
  339. ui.label_transport_frame->setMinimumWidth(minLabelWidth + 3);
  340. ui.label_transport_time->setMinimumWidth(minLabelWidth + 3);
  341. ui.label_transport_bbt->setMinimumWidth(minLabelWidth + 3);
  342. ui.l_transport_bbt->setMinimumWidth(minValueWidth + 3);
  343. ui.l_transport_frame->setMinimumWidth(minValueWidth + 3);
  344. ui.l_transport_time->setMinimumWidth(minValueWidth + 3);
  345. if (host.isPlugin)
  346. {
  347. ui.b_transport_play->setEnabled(false);
  348. ui.b_transport_stop->setEnabled(false);
  349. ui.b_transport_backwards->setEnabled(false);
  350. ui.b_transport_forwards->setEnabled(false);
  351. ui.group_transport_controls->setEnabled(false);
  352. ui.group_transport_controls->setVisible(false);
  353. ui.cb_transport_link->setEnabled(false);
  354. ui.cb_transport_link->setVisible(false);
  355. ui.cb_transport_jack->setEnabled(false);
  356. ui.cb_transport_jack->setVisible(false);
  357. ui.dsb_transport_bpm->setEnabled(false);
  358. ui.dsb_transport_bpm->setReadOnly(true);
  359. }
  360. ui.w_transport->setEnabled(false);
  361. //-------------------------------------------------------------------------------------------------------------
  362. // Set up GUI (rack)
  363. // ui.listWidget->setHostAndParent(host, self);
  364. if (QScrollBar* const sb = ui.listWidget->verticalScrollBar())
  365. {
  366. ui.rackScrollBar->setMinimum(sb->minimum());
  367. ui.rackScrollBar->setMaximum(sb->maximum());
  368. ui.rackScrollBar->setValue(sb->value());
  369. /*
  370. sb->rangeChanged.connect(ui.rackScrollBar.setRange);
  371. sb->valueChanged.connect(ui.rackScrollBar.setValue);
  372. ui.rackScrollBar->rangeChanged.connect(sb.setRange);
  373. ui.rackScrollBar->valueChanged.connect(sb.setValue);
  374. */
  375. }
  376. updateStyle();
  377. ui.rack->setStyleSheet(" \
  378. CarlaRackList#CarlaRackList { \
  379. background-color: black; \
  380. } \
  381. ");
  382. //-------------------------------------------------------------------------------------------------------------
  383. // Set up GUI (patchbay)
  384. /*
  385. ui.peak_in->setChannelCount(2);
  386. ui.peak_in->setMeterColor(DigitalPeakMeter.COLOR_BLUE);
  387. ui.peak_in->setMeterOrientation(DigitalPeakMeter.VERTICAL);
  388. */
  389. ui.peak_in->setFixedWidth(25);
  390. /*
  391. ui.peak_out->setChannelCount(2);
  392. ui.peak_out->setMeterColor(DigitalPeakMeter.COLOR_GREEN);
  393. ui.peak_out->setMeterOrientation(DigitalPeakMeter.VERTICAL);
  394. */
  395. ui.peak_out->setFixedWidth(25);
  396. /*
  397. ui.scrollArea = PixmapKeyboardHArea(ui.patchbay);
  398. ui.keyboard = ui.scrollArea.keyboard;
  399. ui.patchbay.layout().addWidget(ui.scrollArea, 1, 0, 1, 0);
  400. ui.scrollArea->setEnabled(false);
  401. ui.miniCanvasPreview->setRealParent(self);
  402. */
  403. if (QTabBar* const tabBar = ui.tw_miniCanvas->tabBar())
  404. tabBar->hide();
  405. //-------------------------------------------------------------------------------------------------------------
  406. // Set up GUI (special stuff for Mac OS)
  407. #ifdef CARLA_OS_MAC
  408. ui.act_file_quit->setMenuRole(QAction::QuitRole);
  409. ui.act_settings_configure->setMenuRole(QAction::PreferencesRole);
  410. ui.act_help_about->setMenuRole(QAction::AboutRole);
  411. ui.act_help_about_qt->setMenuRole(QAction::AboutQtRole);
  412. ui.menu_Settings->setTitle("Panels");
  413. if (QAction* const action = ui.menu_Help.menuAction())
  414. action->setVisible(false);
  415. #endif
  416. //-------------------------------------------------------------------------------------------------------------
  417. // Load Settings
  418. loadSettings(true);
  419. //-------------------------------------------------------------------------------------------------------------
  420. // Final setup
  421. ui.text_logs->clear();
  422. setProperWindowTitle();
  423. // Disable non-supported features
  424. const char* const* const features = carla_get_supported_features();
  425. if (! stringArrayContainsString(features, "link"))
  426. {
  427. ui.cb_transport_link->setEnabled(false);
  428. ui.cb_transport_link->setVisible(false);
  429. }
  430. if (! stringArrayContainsString(features, "juce"))
  431. {
  432. ui.act_help_about_juce->setEnabled(false);
  433. ui.act_help_about_juce->setVisible(false);
  434. }
  435. // Plugin needs to have timers always running so it receives messages
  436. if (host.isPlugin || host.isRemote)
  437. {
  438. startTimers();
  439. }
  440. // Load initial project file if set
  441. else
  442. {
  443. /*
  444. projectFile = getInitialProjectFile(QApplication.instance());
  445. if (projectFile)
  446. loadProjectLater(projectFile);
  447. */
  448. }
  449. }
  450. //-----------------------------------------------------------------------------------------------------------------
  451. // Setup
  452. #if 0
  453. def compactPlugin(self, pluginId):
  454. if pluginId > self.fPluginCount:
  455. return
  456. pitem = self.fPluginList[pluginId]
  457. if pitem is None:
  458. return
  459. pitem.recreateWidget(True)
  460. def changePluginColor(self, pluginId, color, colorStr):
  461. if pluginId > self.fPluginCount:
  462. return
  463. pitem = self.fPluginList[pluginId]
  464. if pitem is None:
  465. return
  466. self.host.set_custom_data(pluginId, CUSTOM_DATA_TYPE_PROPERTY, "CarlaColor", colorStr)
  467. pitem.recreateWidget(newColor = color)
  468. def changePluginSkin(self, pluginId, skin):
  469. if pluginId > self.fPluginCount:
  470. return
  471. pitem = self.fPluginList[pluginId]
  472. if pitem is None:
  473. return
  474. self.host.set_custom_data(pluginId, CUSTOM_DATA_TYPE_PROPERTY, "CarlaSkin", skin)
  475. if skin not in ("default","rncbc","presets","mpresets"):
  476. pitem.recreateWidget(newSkin = skin, newColor = (255,255,255))
  477. else:
  478. pitem.recreateWidget(newSkin = skin)
  479. def switchPlugins(self, pluginIdA, pluginIdB):
  480. if pluginIdA == pluginIdB:
  481. return
  482. if pluginIdA < 0 or pluginIdB < 0:
  483. return
  484. if pluginIdA >= self.fPluginCount or pluginIdB >= self.fPluginCount:
  485. return
  486. self.host.switch_plugins(pluginIdA, pluginIdB)
  487. itemA = self.fPluginList[pluginIdA]
  488. compactA = itemA.isCompacted()
  489. guiShownA = itemA.isGuiShown()
  490. itemB = self.fPluginList[pluginIdB]
  491. compactB = itemB.isCompacted()
  492. guiShownB = itemB.isGuiShown()
  493. itemA.setPluginId(pluginIdA)
  494. itemA.recreateWidget2(compactB, guiShownB)
  495. itemB.setPluginId(pluginIdB)
  496. itemB.recreateWidget2(compactA, guiShownA)
  497. if self.fWithCanvas:
  498. self.slot_canvasRefresh()
  499. #endif
  500. void setLoadRDFsNeeded() noexcept
  501. {
  502. fLadspaRdfNeedsUpdate = true;
  503. }
  504. void setProperWindowTitle()
  505. {
  506. QString title(fClientName);
  507. /*
  508. if (fProjectFilename.isNotEmpty() && ! host.nsmOK)
  509. title += QString(" - %s").arg(os.path.basename(fProjectFilename));
  510. */
  511. if (fSessionManagerName.isNotEmpty())
  512. title += QString(" (%s)").arg(fSessionManagerName);
  513. hostWindow->setWindowTitle(title);
  514. }
  515. void updateBufferSize(const uint newBufferSize)
  516. {
  517. if (fBufferSize == newBufferSize)
  518. return;
  519. fBufferSize = newBufferSize;
  520. ui.cb_buffer_size->clear();
  521. ui.cb_buffer_size->addItem(QString("%1").arg(newBufferSize));
  522. ui.cb_buffer_size->setCurrentIndex(0);
  523. }
  524. void updateSampleRate(const double newSampleRate)
  525. {
  526. if (carla_isEqual(fSampleRate, newSampleRate))
  527. return;
  528. fSampleRate = newSampleRate;
  529. ui.cb_sample_rate->clear();
  530. ui.cb_sample_rate->addItem(QString("%1").arg(newSampleRate));
  531. ui.cb_sample_rate->setCurrentIndex(0);
  532. refreshTransport(true);
  533. }
  534. //-----------------------------------------------------------------------------------------------------------------
  535. // Files
  536. #if 0
  537. def makeExtraFilename(self):
  538. return self.fProjectFilename.rsplit(".",1)[0]+".json"
  539. #endif
  540. void loadProjectNow()
  541. {
  542. if (fProjectFilename.isEmpty())
  543. return qCritical("ERROR: loading project without filename set");
  544. /*
  545. if (host.nsmOK && ! os.path.exists(self.fProjectFilename))
  546. return;
  547. */
  548. projectLoadingStarted();
  549. fIsProjectLoading = true;
  550. if (! carla_load_project(fProjectFilename.toUtf8()))
  551. {
  552. fIsProjectLoading = false;
  553. projectLoadingFinished();
  554. CustomMessageBox(hostWindow,
  555. QMessageBox::Critical,
  556. tr("Error"),
  557. tr("Failed to load project"),
  558. carla_get_last_error(),
  559. QMessageBox::Ok, QMessageBox::Ok);
  560. }
  561. }
  562. #if 0
  563. def loadProjectLater(self, filename):
  564. self.fProjectFilename = QFileInfo(filename).absoluteFilePath()
  565. self.setProperWindowTitle()
  566. QTimer.singleShot(1, self.slot_loadProjectNow)
  567. def saveProjectNow(self):
  568. if not self.fProjectFilename:
  569. return qCritical("ERROR: saving project without filename set")
  570. if not self.host.save_project(self.fProjectFilename):
  571. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to save project"),
  572. self.host.get_last_error(),
  573. QMessageBox.Ok, QMessageBox.Ok)
  574. return
  575. if not self.fWithCanvas:
  576. return
  577. with open(self.makeExtraFilename(), 'w') as fh:
  578. json.dump({
  579. 'canvas': patchcanvas.saveGroupPositions(),
  580. }, fh)
  581. #endif
  582. void projectLoadingStarted()
  583. {
  584. ui.rack->setEnabled(false);
  585. ui.graphicsView->setEnabled(false);
  586. }
  587. void projectLoadingFinished()
  588. {
  589. ui.rack->setEnabled(true);
  590. ui.graphicsView->setEnabled(true);
  591. if (! fWithCanvas)
  592. return;
  593. QTimer::singleShot(1000, hostWindow, SLOT(slot_canvasRefresh()));
  594. /*
  595. const QString extrafile = makeExtraFilename();
  596. if not os.path.exists(extrafile):
  597. return;
  598. try:
  599. with open(extrafile, "r") as fh:
  600. canvasdata = json.load(fh)['canvas']
  601. except:
  602. return
  603. patchcanvas.restoreGroupPositions(canvasdata)
  604. */
  605. }
  606. //-----------------------------------------------------------------------------------------------------------------
  607. // Engine (menu actions)
  608. void engineStopFinal()
  609. {
  610. killTimers();
  611. if (carla_is_engine_running())
  612. {
  613. if (fCustomStopAction == CUSTOM_ACTION_PROJECT_LOAD)
  614. {
  615. removeAllPlugins();
  616. }
  617. else if (fPluginCount != 0)
  618. {
  619. fCurrentlyRemovingAllPlugins = true;
  620. projectLoadingStarted();
  621. }
  622. if (! carla_remove_all_plugins())
  623. {
  624. ui.text_logs->appendPlainText("Failed to remove all plugins, error was:");
  625. ui.text_logs->appendPlainText(carla_get_last_error());
  626. }
  627. if (! carla_engine_close())
  628. {
  629. ui.text_logs->appendPlainText("Failed to stop engine, error was:");
  630. ui.text_logs->appendPlainText(carla_get_last_error());
  631. }
  632. }
  633. if (fCustomStopAction == CUSTOM_ACTION_APP_CLOSE)
  634. {
  635. hostWindow->close();
  636. }
  637. else if (fCustomStopAction == CUSTOM_ACTION_PROJECT_LOAD)
  638. {
  639. hostWindow->slot_engineStart();
  640. loadProjectNow();
  641. carla_nsm_ready(NSM_CALLBACK_OPEN);
  642. }
  643. fCustomStopAction = CUSTOM_ACTION_NONE;
  644. }
  645. //-----------------------------------------------------------------------------------------------------------------
  646. // Plugins
  647. void removeAllPlugins()
  648. {
  649. }
  650. //-----------------------------------------------------------------------------------------------------------------
  651. // Plugins (menu actions)
  652. void showAddPluginDialog()
  653. {
  654. }
  655. void showAddJackAppDialog()
  656. {
  657. }
  658. void pluginRemoveAll()
  659. {
  660. }
  661. //-----------------------------------------------------------------------------------------------------------------
  662. // Canvas
  663. void clearSideStuff()
  664. {
  665. }
  666. void setupCanvas()
  667. {
  668. }
  669. void updateCanvasInitialPos()
  670. {
  671. }
  672. void updateMiniCanvasLater()
  673. {
  674. }
  675. //-----------------------------------------------------------------------------------------------------------------
  676. // Settings
  677. void saveSettings()
  678. {
  679. QSafeSettings settings;
  680. settings.setValue("Geometry", hostWindow->saveGeometry());
  681. settings.setValue("ShowToolbar", ui.toolBar->isEnabled());
  682. if (! host.isControl)
  683. settings.setValue("ShowSidePanel", ui.dockWidget->isEnabled());
  684. QStringList diskFolders;
  685. /*
  686. for i in range(ui.cb_disk.count()):
  687. diskFolders.append(ui.cb_disk->itemData(i))
  688. */
  689. settings.setValue("DiskFolders", diskFolders);
  690. settings.setValue("LastBPM", fLastTransportBPM);
  691. settings.setValue("ShowMeters", ui.act_settings_show_meters->isChecked());
  692. settings.setValue("ShowKeyboard", ui.act_settings_show_keyboard->isChecked());
  693. settings.setValue("HorizontalScrollBarValue", ui.graphicsView->horizontalScrollBar()->value());
  694. settings.setValue("VerticalScrollBarValue", ui.graphicsView->verticalScrollBar()->value());
  695. settings.setValue(CARLA_KEY_ENGINE_TRANSPORT_MODE, host.transportMode);
  696. settings.setValue(CARLA_KEY_ENGINE_TRANSPORT_EXTRA, host.transportExtra);
  697. }
  698. void loadSettings(bool firstTime)
  699. {
  700. const QSafeSettings settings;
  701. if (firstTime)
  702. {
  703. const QByteArray geometry(settings.valueByteArray("Geometry"));
  704. if (! geometry.isNull())
  705. hostWindow->restoreGeometry(geometry);
  706. // if settings.contains("SplitterState"):
  707. //ui.splitter.restoreState(settings.value("SplitterState", b""))
  708. //else:
  709. //ui.splitter.setSizes([210, 99999])
  710. const bool toolbarVisible = settings.valueBool("ShowToolbar", true);
  711. ui.act_settings_show_toolbar->setChecked(toolbarVisible);
  712. showToolbar(toolbarVisible);
  713. const bool sidePanelVisible = settings.valueBool("ShowSidePanel", true) && ! host.isControl;
  714. ui.act_settings_show_side_panel->setChecked(sidePanelVisible);
  715. showSidePanel(sidePanelVisible);
  716. QStringList diskFolders;
  717. diskFolders.append(QDir::homePath());
  718. diskFolders = settings.valueStringList("DiskFolders", diskFolders);
  719. ui.cb_disk->setItemData(0, QDir::homePath());
  720. for (const auto& folder : diskFolders)
  721. {
  722. /*
  723. if i == 0: continue;
  724. folder = diskFolders[i];
  725. ui.cb_disk->addItem(os.path.basename(folder), folder);
  726. */
  727. }
  728. //if MACOS and not settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, true, bool):
  729. // setUnifiedTitleAndToolBarOnMac(true)
  730. const bool showMeters = settings.valueBool("ShowMeters", true);
  731. ui.act_settings_show_meters->setChecked(showMeters);
  732. ui.peak_in->setVisible(showMeters);
  733. ui.peak_out->setVisible(showMeters);
  734. const bool showKeyboard = settings.valueBool("ShowKeyboard", true);
  735. ui.act_settings_show_keyboard->setChecked(showKeyboard);
  736. /*
  737. ui.scrollArea->setVisible(showKeyboard);
  738. */
  739. const QSafeSettings settingsDBf("falkTX", "CarlaDatabase2");
  740. fFavoritePlugins = settingsDBf.valueStringList("PluginDatabase/Favorites");
  741. QTimer::singleShot(100, hostWindow, SLOT(slot_restoreCanvasScrollbarValues()));
  742. }
  743. // TODO - complete this
  744. fSavedSettings._CARLA_KEY_MAIN_CONFIRM_EXIT = settings.valueBool(CARLA_KEY_MAIN_CONFIRM_EXIT,
  745. CARLA_DEFAULT_MAIN_CONFIRM_EXIT);
  746. fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL = settings.valueUInt(CARLA_KEY_MAIN_REFRESH_INTERVAL,
  747. CARLA_DEFAULT_MAIN_REFRESH_INTERVAL);
  748. fSavedSettings._CARLA_KEY_CANVAS_FANCY_EYE_CANDY = settings.valueBool(CARLA_KEY_CANVAS_FANCY_EYE_CANDY,
  749. CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY);
  750. /*
  751. {
  752. CARLA_KEY_MAIN_PROJECT_FOLDER: settings.value(CARLA_KEY_MAIN_PROJECT_FOLDER, CARLA_DEFAULT_MAIN_PROJECT_FOLDER, str),
  753. CARLA_KEY_MAIN_EXPERIMENTAL: settings.value(CARLA_KEY_MAIN_EXPERIMENTAL, CARLA_DEFAULT_MAIN_EXPERIMENTAL, bool),
  754. CARLA_KEY_CANVAS_THEME: settings.value(CARLA_KEY_CANVAS_THEME, CARLA_DEFAULT_CANVAS_THEME, str),
  755. CARLA_KEY_CANVAS_SIZE: settings.value(CARLA_KEY_CANVAS_SIZE, CARLA_DEFAULT_CANVAS_SIZE, str),
  756. CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS: settings.value(CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS, CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS, bool),
  757. CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS: settings.value(CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS, CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS, bool),
  758. CARLA_KEY_CANVAS_USE_BEZIER_LINES: settings.value(CARLA_KEY_CANVAS_USE_BEZIER_LINES, CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES, bool),
  759. CARLA_KEY_CANVAS_EYE_CANDY: settings.value(CARLA_KEY_CANVAS_EYE_CANDY, CARLA_DEFAULT_CANVAS_EYE_CANDY, bool),
  760. CARLA_KEY_CANVAS_USE_OPENGL: settings.value(CARLA_KEY_CANVAS_USE_OPENGL, CARLA_DEFAULT_CANVAS_USE_OPENGL, bool),
  761. CARLA_KEY_CANVAS_ANTIALIASING: settings.value(CARLA_KEY_CANVAS_ANTIALIASING, CARLA_DEFAULT_CANVAS_ANTIALIASING, int),
  762. CARLA_KEY_CANVAS_HQ_ANTIALIASING: settings.value(CARLA_KEY_CANVAS_HQ_ANTIALIASING, CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING, bool),
  763. CARLA_KEY_CANVAS_FULL_REPAINTS: settings.value(CARLA_KEY_CANVAS_FULL_REPAINTS, CARLA_DEFAULT_CANVAS_FULL_REPAINTS, bool),
  764. CARLA_KEY_CANVAS_INLINE_DISPLAYS: settings.value(CARLA_KEY_CANVAS_INLINE_DISPLAYS, CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS, bool),
  765. CARLA_KEY_CUSTOM_PAINTING: (settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, true, bool) and
  766. settings.value(CARLA_KEY_MAIN_PRO_THEME_COLOR, "Black", str).lower() == "black"),
  767. }
  768. */
  769. const QSafeSettings settings2("falkTX", "Carla2");
  770. if (host.experimental)
  771. {
  772. const bool visible = settings2.valueBool(CARLA_KEY_EXPERIMENTAL_JACK_APPS,
  773. CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS);
  774. ui.act_plugin_add_jack->setVisible(visible);
  775. }
  776. else
  777. {
  778. ui.act_plugin_add_jack->setVisible(false);
  779. }
  780. fMiniCanvasUpdateTimeout = fSavedSettings._CARLA_KEY_CANVAS_FANCY_EYE_CANDY ? 1000 : 0;
  781. setEngineSettings(host);
  782. restartTimersIfNeeded();
  783. }
  784. void enableTransport(const bool enabled)
  785. {
  786. ui.group_transport_controls->setEnabled(enabled);
  787. ui.group_transport_settings->setEnabled(enabled);
  788. }
  789. void showSidePanel(const bool yesNo)
  790. {
  791. ui.dockWidget->setEnabled(yesNo);
  792. ui.dockWidget->setVisible(yesNo);
  793. }
  794. void showToolbar(const bool yesNo)
  795. {
  796. ui.toolBar->setEnabled(yesNo);
  797. ui.toolBar->setVisible(yesNo);
  798. }
  799. //-----------------------------------------------------------------------------------------------------------------
  800. // Transport
  801. void refreshTransport(const bool forced = false)
  802. {
  803. if (! ui.l_transport_time->isVisible())
  804. return;
  805. if (carla_isZero(fSampleRate) or ! carla_is_engine_running())
  806. return;
  807. const CarlaTransportInfo* const timeInfo = carla_get_transport_info();
  808. const bool playing = timeInfo->playing;
  809. const uint64_t frame = timeInfo->frame;
  810. const double bpm = timeInfo->bpm;
  811. if (playing != fLastTransportState || forced)
  812. {
  813. if (playing)
  814. {
  815. const QIcon icon(":/16x16/media-playback-pause.svgz");
  816. ui.b_transport_play->setChecked(true);
  817. ui.b_transport_play->setIcon(icon);
  818. // ui.b_transport_play->setText(tr("&Pause"));
  819. }
  820. else
  821. {
  822. const QIcon icon(":/16x16/media-playback-start.svgz");
  823. ui.b_transport_play->setChecked(false);
  824. ui.b_transport_play->setIcon(icon);
  825. // ui.b_play->setText(tr("&Play"));
  826. }
  827. fLastTransportState = playing;
  828. }
  829. if (frame != fLastTransportFrame || forced)
  830. {
  831. fLastTransportFrame = frame;
  832. const uint32_t time = frame / fSampleRate;
  833. const uint32_t secs = time % 60;
  834. const uint32_t mins = (time / 60) % 60;
  835. const uint32_t hrs = (time / 3600) % 60;
  836. ui.l_transport_time->setText(QString("%1:%2:%3").arg(hrs, 2, 10, QChar('0')).arg(mins, 2, 10, QChar('0')).arg(secs, 2, 10, QChar('0')));
  837. const uint32_t frame1 = frame % 1000;
  838. const uint32_t frame2 = (frame / 1000) % 1000;
  839. const uint32_t frame3 = (frame / 1000000) % 1000;
  840. ui.l_transport_frame->setText(QString("%1'%2'%3").arg(frame3, 3, 10, QChar('0')).arg(frame2, 3, 10, QChar('0')).arg(frame1, 3, 10, QChar('0')));
  841. const int32_t bar = timeInfo->bar;
  842. const int32_t beat = timeInfo->beat;
  843. const int32_t tick = timeInfo->tick;
  844. ui.l_transport_bbt->setText(QString("%1|%2|%3").arg(bar, 3, 10, QChar('0')).arg(beat, 2, 10, QChar('0')).arg(tick, 4, 10, QChar('0')));
  845. }
  846. if (carla_isNotEqual(bpm, fLastTransportBPM) || forced)
  847. {
  848. fLastTransportBPM = bpm;
  849. if (bpm > 0.0)
  850. {
  851. ui.dsb_transport_bpm->blockSignals(true);
  852. ui.dsb_transport_bpm->setValue(bpm);
  853. ui.dsb_transport_bpm->blockSignals(false);
  854. ui.dsb_transport_bpm->setStyleSheet("");
  855. }
  856. else
  857. {
  858. ui.dsb_transport_bpm->setStyleSheet("QDoubleSpinBox { color: palette(mid); }");
  859. }
  860. }
  861. }
  862. //-----------------------------------------------------------------------------------------------------------------
  863. // Timers
  864. void startTimers()
  865. {
  866. if (fIdleTimerFast == 0)
  867. fIdleTimerFast = hostWindow->startTimer(fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL);
  868. if (fIdleTimerSlow == 0)
  869. fIdleTimerSlow = hostWindow->startTimer(fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL*4);
  870. }
  871. void restartTimersIfNeeded()
  872. {
  873. if (fIdleTimerFast != 0)
  874. {
  875. hostWindow->killTimer(fIdleTimerFast);
  876. fIdleTimerFast = hostWindow->startTimer(fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL);
  877. }
  878. if (fIdleTimerSlow != 0)
  879. {
  880. hostWindow->killTimer(fIdleTimerSlow);
  881. fIdleTimerSlow = hostWindow->startTimer(fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL*4);;
  882. }
  883. }
  884. void killTimers()
  885. {
  886. if (fIdleTimerFast != 0)
  887. {
  888. hostWindow->killTimer(fIdleTimerFast);
  889. fIdleTimerFast = 0;
  890. }
  891. if (fIdleTimerSlow != 0)
  892. {
  893. hostWindow->killTimer(fIdleTimerSlow);
  894. fIdleTimerSlow = 0;
  895. }
  896. }
  897. //-----------------------------------------------------------------------------------------------------------------
  898. // Internal stuff
  899. void* getExtraPtr(/*self, plugin*/)
  900. {
  901. return nullptr;
  902. }
  903. void maybeLoadRDFs()
  904. {
  905. }
  906. //-----------------------------------------------------------------------------------------------------------------
  907. /*
  908. def getPluginCount(self):
  909. return self.fPluginCount
  910. def getPluginItem(self, pluginId):
  911. if pluginId >= self.fPluginCount:
  912. return None
  913. pitem = self.fPluginList[pluginId]
  914. if pitem is None:
  915. return None
  916. #if False:
  917. #return CarlaRackItem(self, 0, False)
  918. return pitem
  919. def getPluginEditDialog(self, pluginId):
  920. if pluginId >= self.fPluginCount:
  921. return None
  922. pitem = self.fPluginList[pluginId]
  923. if pitem is None:
  924. return None
  925. if False:
  926. return PluginEdit(self, self.host, 0)
  927. return pitem.getEditDialog()
  928. def getPluginSlotWidget(self, pluginId):
  929. if pluginId >= self.fPluginCount:
  930. return None
  931. pitem = self.fPluginList[pluginId]
  932. if pitem is None:
  933. return None
  934. #if False:
  935. #return AbstractPluginSlot()
  936. return pitem.getWidget()
  937. */
  938. //-----------------------------------------------------------------------------------------------------------------
  939. // timer event
  940. void refreshRuntimeInfo(const float load, const int xruns)
  941. {
  942. const QString txt1(xruns >= 0 ? QString("%1").arg(xruns) : QString("--"));
  943. const QString txt2(xruns == 1 ? "" : "s");
  944. ui.b_xruns->setText(QString("%1 Xrun%2").arg(txt1).arg(txt2));
  945. ui.pb_dsp_load->setValue(int(load));
  946. }
  947. void getAndRefreshRuntimeInfo()
  948. {
  949. if (! ui.pb_dsp_load->isVisible())
  950. return;
  951. if (! carla_is_engine_running())
  952. return;
  953. const CarlaRuntimeEngineInfo* const info = carla_get_runtime_engine_info();
  954. refreshRuntimeInfo(info->load, info->xruns);
  955. }
  956. void idleFast()
  957. {
  958. carla_engine_idle();
  959. refreshTransport();
  960. if (fPluginCount == 0 || fCurrentlyRemovingAllPlugins)
  961. return;
  962. for (auto& pitem : fPluginList)
  963. {
  964. if (pitem == nullptr)
  965. break;
  966. /*
  967. pitem->getWidget().idleFast();
  968. */
  969. }
  970. for (uint pluginId : fSelectedPlugins)
  971. {
  972. fPeaksCleared = false;
  973. if (ui.peak_in->isVisible())
  974. {
  975. /*
  976. ui.peak_in->displayMeter(1, carla_get_input_peak_value(pluginId, true))
  977. ui.peak_in->displayMeter(2, carla_get_input_peak_value(pluginId, false))
  978. */
  979. }
  980. if (ui.peak_out->isVisible())
  981. {
  982. /*
  983. ui.peak_out->displayMeter(1, carla_get_output_peak_value(pluginId, true))
  984. ui.peak_out->displayMeter(2, carla_get_output_peak_value(pluginId, false))
  985. */
  986. }
  987. return;
  988. }
  989. if (fPeaksCleared)
  990. return;
  991. fPeaksCleared = true;
  992. /*
  993. ui.peak_in->displayMeter(1, 0.0, true);
  994. ui.peak_in->displayMeter(2, 0.0, true);
  995. ui.peak_out->displayMeter(1, 0.0, true);
  996. ui.peak_out->displayMeter(2, 0.0, true);
  997. */
  998. }
  999. void idleSlow()
  1000. {
  1001. getAndRefreshRuntimeInfo();
  1002. if (fPluginCount == 0 || fCurrentlyRemovingAllPlugins)
  1003. return;
  1004. for (auto& pitem : fPluginList)
  1005. {
  1006. if (pitem == nullptr)
  1007. break;
  1008. /*
  1009. pitem->getWidget().idleSlow();
  1010. */
  1011. }
  1012. }
  1013. //-----------------------------------------------------------------------------------------------------------------
  1014. // color/style change event
  1015. void updateStyle()
  1016. {
  1017. // Rack padding images setup
  1018. QImage rack_imgL(":/bitmaps/rack_padding_left.png");
  1019. QImage rack_imgR(":/bitmaps/rack_padding_right.png");
  1020. const qreal min_value = 0.07;
  1021. #if QT_VERSION >= 0x50600
  1022. const qreal value_fix = 1.0/(1.0-rack_imgL.scaled(1, 1, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).pixelColor(0,0).blackF());
  1023. #else
  1024. const qreal value_fix = 1.5;
  1025. #endif
  1026. const QColor bg_color = ui.rack->palette().window().color();
  1027. const qreal bg_value = 1.0 - bg_color.blackF();
  1028. QColor pad_color;
  1029. if (carla_isNotZero(bg_value) && bg_value < min_value)
  1030. pad_color = bg_color.lighter(100*min_value/bg_value*value_fix);
  1031. else
  1032. pad_color = QColor::fromHsvF(0.0, 0.0, min_value*value_fix);
  1033. QPainter painter;
  1034. QRect fillRect(rack_imgL.rect().adjusted(-1,-1,1,1));
  1035. painter.begin(&rack_imgL);
  1036. painter.setCompositionMode(QPainter::CompositionMode_Multiply);
  1037. painter.setBrush(pad_color);
  1038. painter.drawRect(fillRect);
  1039. painter.end();
  1040. const QPixmap rack_pixmapL(QPixmap::fromImage(rack_imgL));
  1041. QPalette imgL_palette; //(ui.pad_left->palette());
  1042. imgL_palette.setBrush(QPalette::Window, QBrush(rack_pixmapL));
  1043. ui.pad_left->setPalette(imgL_palette);
  1044. ui.pad_left->setAutoFillBackground(true);
  1045. painter.begin(&rack_imgR);
  1046. painter.setCompositionMode(QPainter::CompositionMode_Multiply);
  1047. painter.setBrush(pad_color);
  1048. painter.drawRect(fillRect);
  1049. painter.end();
  1050. const QPixmap rack_pixmapR(QPixmap::fromImage(rack_imgR));
  1051. QPalette imgR_palette; //(ui.pad_right->palette());
  1052. imgR_palette.setBrush(QPalette::Window, QBrush(rack_pixmapR));
  1053. ui.pad_right->setPalette(imgR_palette);
  1054. ui.pad_right->setAutoFillBackground(true);
  1055. }
  1056. //-----------------------------------------------------------------------------------------------------------------
  1057. // close event
  1058. bool shouldIgnoreClose()
  1059. {
  1060. if (host.isControl || host.isPlugin)
  1061. return false;
  1062. if (fCustomStopAction == CUSTOM_ACTION_APP_CLOSE)
  1063. return false;
  1064. if (fSavedSettings._CARLA_KEY_MAIN_CONFIRM_EXIT)
  1065. return QMessageBox::question(hostWindow,
  1066. tr("Quit"),
  1067. tr("Are you sure you want to quit Carla?"),
  1068. QMessageBox::Yes|QMessageBox::No) == QMessageBox::No;
  1069. return false;
  1070. }
  1071. };
  1072. //---------------------------------------------------------------------------------------------------------------------
  1073. CarlaHostWindow::CarlaHostWindow(CarlaHost& host, const bool withCanvas, QWidget* const parent)
  1074. : QMainWindow(parent),
  1075. self(new PrivateData(this, host, withCanvas))
  1076. {
  1077. gCarla.gui = this;
  1078. self->fIdleTimerNull = startTimer(1000);
  1079. //-----------------------------------------------------------------------------------------------------------------
  1080. // Set-up Canvas
  1081. /*
  1082. if (withCanvas)
  1083. {
  1084. self->scene = patchcanvas.PatchScene(self, self->ui.graphicsView);
  1085. self->ui.graphicsView->setScene(self->scene);
  1086. if (self->fSavedSettings[CARLA_KEY_CANVAS_USE_OPENGL])
  1087. {
  1088. self->ui.glView = QGLWidget(self);
  1089. self->ui.graphicsView.setViewport(self->ui.glView);
  1090. }
  1091. setupCanvas();
  1092. }
  1093. */
  1094. //-----------------------------------------------------------------------------------------------------------------
  1095. // Connect actions to functions
  1096. // TODO
  1097. connect(self->ui.act_file_new, SIGNAL(triggered()), SLOT(slot_fileNew()));
  1098. connect(self->ui.act_file_open, SIGNAL(triggered()), SLOT(slot_fileOpen()));
  1099. connect(self->ui.act_file_save, SIGNAL(triggered()), SLOT(slot_fileSave()));
  1100. connect(self->ui.act_file_save_as, SIGNAL(triggered()), SLOT(slot_fileSaveAs()));
  1101. connect(self->ui.act_engine_start, SIGNAL(triggered()), SLOT(slot_engineStart()));
  1102. connect(self->ui.act_engine_stop, SIGNAL(triggered()), SLOT(slot_engineStop()));
  1103. connect(self->ui.act_engine_panic, SIGNAL(triggered()), SLOT(slot_pluginsDisable()));
  1104. connect(self->ui.act_engine_config, SIGNAL(triggered()), SLOT(slot_engineConfig()));
  1105. connect(self->ui.act_plugin_add, SIGNAL(triggered()), SLOT(slot_pluginAdd()));
  1106. connect(self->ui.act_plugin_add_jack, SIGNAL(triggered()), SLOT(slot_jackAppAdd()));
  1107. connect(self->ui.act_plugin_remove_all, SIGNAL(triggered()), SLOT(slot_confirmRemoveAll()));
  1108. connect(self->ui.act_plugins_enable, SIGNAL(triggered()), SLOT(slot_pluginsEnable()));
  1109. connect(self->ui.act_plugins_disable, SIGNAL(triggered()), SLOT(slot_pluginsDisable()));
  1110. connect(self->ui.act_plugins_volume100, SIGNAL(triggered()), SLOT(slot_pluginsVolume100()));
  1111. connect(self->ui.act_plugins_mute, SIGNAL(triggered()), SLOT(slot_pluginsMute()));
  1112. connect(self->ui.act_plugins_wet100, SIGNAL(triggered()), SLOT(slot_pluginsWet100()));
  1113. connect(self->ui.act_plugins_bypass, SIGNAL(triggered()), SLOT(slot_pluginsBypass()));
  1114. connect(self->ui.act_plugins_center, SIGNAL(triggered()), SLOT(slot_pluginsCenter()));
  1115. connect(self->ui.act_plugins_compact, SIGNAL(triggered()), SLOT(slot_pluginsCompact()));
  1116. connect(self->ui.act_plugins_expand, SIGNAL(triggered()), SLOT(slot_pluginsExpand()));
  1117. connect(self->ui.act_settings_show_toolbar, SIGNAL(toggled(bool)), SLOT(slot_showToolbar(bool)));
  1118. connect(self->ui.act_settings_show_meters, SIGNAL(toggled(bool)), SLOT(slot_showCanvasMeters(bool)));
  1119. connect(self->ui.act_settings_show_keyboard, SIGNAL(toggled(bool)), SLOT(slot_showCanvasKeyboard(bool)));
  1120. connect(self->ui.act_settings_show_side_panel, SIGNAL(toggled(bool)), SLOT(slot_showSidePanel(bool)));
  1121. connect(self->ui.act_settings_configure, SIGNAL(triggered()), SLOT(slot_configureCarla()));
  1122. connect(self->ui.act_help_about, SIGNAL(triggered()), SLOT(slot_aboutCarla()));
  1123. connect(self->ui.act_help_about_juce, SIGNAL(triggered()), SLOT(slot_aboutJuce()));
  1124. connect(self->ui.act_help_about_qt, SIGNAL(triggered()), SLOT(slot_aboutQt()));
  1125. connect(self->ui.cb_disk, SIGNAL(currentIndexChanged(int)), SLOT(slot_diskFolderChanged(int)));
  1126. connect(self->ui.b_disk_add, SIGNAL(clicked()), SLOT(slot_diskFolderAdd()));
  1127. connect(self->ui.b_disk_remove, SIGNAL(clicked()), SLOT(slot_diskFolderRemove()));
  1128. connect(self->ui.fileTreeView, SIGNAL(doubleClicked(QModelIndex*)), SLOT(slot_fileTreeDoubleClicked(QModelIndex*)));
  1129. connect(self->ui.b_transport_play, SIGNAL(clicked(bool)), SLOT(slot_transportPlayPause(bool)));
  1130. connect(self->ui.b_transport_stop, SIGNAL(clicked()), SLOT(slot_transportStop()));
  1131. connect(self->ui.b_transport_backwards, SIGNAL(clicked()), SLOT(slot_transportBackwards()));
  1132. connect(self->ui.b_transport_forwards, SIGNAL(clicked()), SLOT(slot_transportForwards()));
  1133. connect(self->ui.dsb_transport_bpm, SIGNAL(valueChanged(qreal)), SLOT(slot_transportBpmChanged(qreal)));
  1134. connect(self->ui.cb_transport_jack, SIGNAL(clicked(bool)), SLOT(slot_transportJackEnabled(bool)));
  1135. connect(self->ui.cb_transport_link, SIGNAL(clicked(bool)), SLOT(slot_transportLinkEnabled(bool)));
  1136. connect(self->ui.b_xruns, SIGNAL(clicked()), SLOT(slot_xrunClear()));
  1137. connect(self->ui.listWidget, SIGNAL(customContextMenuRequested()), SLOT(slot_showPluginActionsMenu()));
  1138. /*
  1139. connect(self->ui.keyboard, SIGNAL(noteOn(int)), SLOT(slot_noteOn(int)));
  1140. connect(self->ui.keyboard, SIGNAL(noteOff(int)), SLOT(slot_noteOff(int)));
  1141. */
  1142. connect(self->ui.tabWidget, SIGNAL(currentChanged(int)), SLOT(slot_tabChanged(int)));
  1143. if (withCanvas)
  1144. {
  1145. connect(self->ui.act_canvas_show_internal, SIGNAL(triggered()), SLOT(slot_canvasShowInternal()));
  1146. connect(self->ui.act_canvas_show_external, SIGNAL(triggered()), SLOT(slot_canvasShowExternal()));
  1147. connect(self->ui.act_canvas_arrange, SIGNAL(triggered()), SLOT(slot_canvasArrange()));
  1148. connect(self->ui.act_canvas_refresh, SIGNAL(triggered()), SLOT(slot_canvasRefresh()));
  1149. connect(self->ui.act_canvas_zoom_fit, SIGNAL(triggered()), SLOT(slot_canvasZoomFit()));
  1150. connect(self->ui.act_canvas_zoom_in, SIGNAL(triggered()), SLOT(slot_canvasZoomIn()));
  1151. connect(self->ui.act_canvas_zoom_out, SIGNAL(triggered()), SLOT(slot_canvasZoomOut()));
  1152. connect(self->ui.act_canvas_zoom_100, SIGNAL(triggered()), SLOT(slot_canvasZoomReset()));
  1153. connect(self->ui.act_canvas_save_image, SIGNAL(triggered()), SLOT(slot_canvasSaveImage()));
  1154. self->ui.act_canvas_arrange->setEnabled(false); // TODO, later
  1155. connect(self->ui.graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slot_horizontalScrollBarChanged(int)));
  1156. connect(self->ui.graphicsView->verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slot_verticalScrollBarChanged(int)));
  1157. /*
  1158. connect(self->ui.miniCanvasPreview, SIGNAL(miniCanvasMoved(qreal, qreal)), SLOT(slot_miniCanvasMoved(qreal, qreal)));
  1159. connect(self.scene, SIGNAL(scaleChanged()), SLOT(slot_canvasScaleChanged()));
  1160. connect(self.scene, SIGNAL(sceneGroupMoved()), SLOT(slot_canvasItemMoved()));
  1161. connect(self.scene, SIGNAL(pluginSelected()), SLOT(slot_canvasPluginSelected()));
  1162. connect(self.scene, SIGNAL(selectionChanged()), SLOT(slot_canvasSelectionChanged()));
  1163. */
  1164. }
  1165. connect(&host, SIGNAL(SIGUSR1()), SLOT(slot_handleSIGUSR1()));
  1166. connect(&host, SIGNAL(SIGTERM()), SLOT(slot_handleSIGTERM()));
  1167. connect(&host, SIGNAL(EngineStartedCallback(uint, int, int, int, float, QString)), SLOT(slot_handleEngineStartedCallback(uint, int, int, int, float, QString)));
  1168. connect(&host, SIGNAL(EngineStoppedCallback()), SLOT(slot_handleEngineStoppedCallback()));
  1169. connect(&host, SIGNAL(TransportModeChangedCallback()), SLOT(slot_handleTransportModeChangedCallback()));
  1170. connect(&host, SIGNAL(BufferSizeChangedCallback()), SLOT(slot_handleBufferSizeChangedCallback()));
  1171. connect(&host, SIGNAL(SampleRateChangedCallback()), SLOT(slot_handleSampleRateChangedCallback()));
  1172. connect(&host, SIGNAL(CancelableActionCallback()), SLOT(slot_handleCancelableActionCallback()));
  1173. connect(&host, SIGNAL(ProjectLoadFinishedCallback()), SLOT(slot_handleProjectLoadFinishedCallback()));
  1174. connect(&host, SIGNAL(PluginAddedCallback()), SLOT(slot_handlePluginAddedCallback()));
  1175. connect(&host, SIGNAL(PluginRemovedCallback()), SLOT(slot_handlePluginRemovedCallback()));
  1176. connect(&host, SIGNAL(ReloadAllCallback()), SLOT(slot_handleReloadAllCallback()));
  1177. connect(&host, SIGNAL(NoteOnCallback()), SLOT(slot_handleNoteOnCallback()));
  1178. connect(&host, SIGNAL(NoteOffCallback()), SLOT(slot_handleNoteOffCallback()));
  1179. connect(&host, SIGNAL(UpdateCallback()), SLOT(slot_handleUpdateCallback()));
  1180. connect(&host, SIGNAL(PatchbayClientAddedCallback()), SLOT(slot_handlePatchbayClientAddedCallback()));
  1181. connect(&host, SIGNAL(PatchbayClientRemovedCallback()), SLOT(slot_handlePatchbayClientRemovedCallback()));
  1182. connect(&host, SIGNAL(PatchbayClientRenamedCallback()), SLOT(slot_handlePatchbayClientRenamedCallback()));
  1183. connect(&host, SIGNAL(PatchbayClientDataChangedCallback()), SLOT(slot_handlePatchbayClientDataChangedCallback()));
  1184. connect(&host, SIGNAL(PatchbayPortAddedCallback()), SLOT(slot_handlePatchbayPortAddedCallback()));
  1185. connect(&host, SIGNAL(PatchbayPortRemovedCallback()), SLOT(slot_handlePatchbayPortRemovedCallback()));
  1186. connect(&host, SIGNAL(PatchbayPortChangedCallback()), SLOT(slot_handlePatchbayPortChangedCallback()));
  1187. connect(&host, SIGNAL(PatchbayPortGroupAddedCallback()), SLOT(slot_handlePatchbayPortGroupAddedCallback()));
  1188. connect(&host, SIGNAL(PatchbayPortGroupRemovedCallback()), SLOT(slot_handlePatchbayPortGroupRemovedCallback()));
  1189. connect(&host, SIGNAL(PatchbayPortGroupChangedCallback()), SLOT(slot_handlePatchbayPortGroupChangedCallback()));
  1190. connect(&host, SIGNAL(PatchbayConnectionAddedCallback()), SLOT(slot_handlePatchbayConnectionAddedCallback()));
  1191. connect(&host, SIGNAL(PatchbayConnectionRemovedCallback()), SLOT(slot_handlePatchbayConnectionRemovedCallback()));
  1192. connect(&host, SIGNAL(NSMCallback()), SLOT(slot_handleNSMCallback()));
  1193. connect(&host, SIGNAL(DebugCallback()), SLOT(slot_handleDebugCallback()));
  1194. connect(&host, SIGNAL(InfoCallback()), SLOT(slot_handleInfoCallback()));
  1195. connect(&host, SIGNAL(ErrorCallback()), SLOT(slot_handleErrorCallback()));
  1196. connect(&host, SIGNAL(QuitCallback()), SLOT(slot_handleQuitCallback()));
  1197. connect(&host, SIGNAL(InlineDisplayRedrawCallback()), SLOT(slot_handleInlineDisplayRedrawCallback()));
  1198. //-----------------------------------------------------------------------------------------------------------------
  1199. // Final setup
  1200. // Qt needs this so it properly creates & resizes the canvas
  1201. self->ui.tabWidget->blockSignals(true);
  1202. self->ui.tabWidget->setCurrentIndex(1);
  1203. self->ui.tabWidget->setCurrentIndex(0);
  1204. self->ui.tabWidget->blockSignals(false);
  1205. // Start in patchbay tab if using forced patchbay mode
  1206. if (host.processModeForced && host.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
  1207. self->ui.tabWidget->setCurrentIndex(1);
  1208. // For NSM we wait for the open message
  1209. if (NSM_URL != nullptr && host.nsmOK)
  1210. {
  1211. carla_nsm_ready(NSM_CALLBACK_INIT);
  1212. return;
  1213. }
  1214. if (! host.isControl)
  1215. QTimer::singleShot(0, this, SLOT(slot_engineStart()));
  1216. }
  1217. CarlaHostWindow::~CarlaHostWindow()
  1218. {
  1219. delete self;
  1220. }
  1221. //---------------------------------------------------------------------------------------------------------------------
  1222. // Plugin Editor Parent
  1223. void CarlaHostWindow::editDialogVisibilityChanged(int pluginId, bool visible)
  1224. {
  1225. }
  1226. void CarlaHostWindow::editDialogPluginHintsChanged(int pluginId, int hints)
  1227. {
  1228. }
  1229. void CarlaHostWindow::editDialogParameterValueChanged(int pluginId, int parameterId, float value)
  1230. {
  1231. }
  1232. void CarlaHostWindow::editDialogProgramChanged(int pluginId, int index)
  1233. {
  1234. }
  1235. void CarlaHostWindow::editDialogMidiProgramChanged(int pluginId, int index)
  1236. {
  1237. }
  1238. void CarlaHostWindow::editDialogNotePressed(int pluginId, int note)
  1239. {
  1240. }
  1241. void CarlaHostWindow::editDialogNoteReleased(int pluginId, int note)
  1242. {
  1243. }
  1244. void CarlaHostWindow::editDialogMidiActivityChanged(int pluginId, bool onOff)
  1245. {
  1246. }
  1247. //---------------------------------------------------------------------------------------------------------------------
  1248. // show/hide event
  1249. void CarlaHostWindow::showEvent(QShowEvent* event)
  1250. {
  1251. QMainWindow::showEvent(event);
  1252. }
  1253. void CarlaHostWindow::hideEvent(QHideEvent* event)
  1254. {
  1255. QMainWindow::hideEvent(event);
  1256. }
  1257. //---------------------------------------------------------------------------------------------------------------------
  1258. // resize event
  1259. void CarlaHostWindow::resizeEvent(QResizeEvent* event)
  1260. {
  1261. QMainWindow::resizeEvent(event);
  1262. }
  1263. //---------------------------------------------------------------------------------------------------------------------
  1264. // timer event
  1265. void CarlaHostWindow::timerEvent(QTimerEvent* const event)
  1266. {
  1267. if (event->timerId() == self->fIdleTimerFast)
  1268. self->idleFast();
  1269. else if (event->timerId() == self->fIdleTimerSlow)
  1270. self->idleSlow();
  1271. QMainWindow::timerEvent(event);
  1272. }
  1273. //---------------------------------------------------------------------------------------------------------------------
  1274. // color/style change event
  1275. void CarlaHostWindow::changeEvent(QEvent* const event)
  1276. {
  1277. switch (event->type())
  1278. {
  1279. case QEvent::PaletteChange:
  1280. case QEvent::StyleChange:
  1281. self->updateStyle();
  1282. break;
  1283. default:
  1284. break;
  1285. }
  1286. QMainWindow::changeEvent(event);
  1287. }
  1288. //---------------------------------------------------------------------------------------------------------------------
  1289. // close event
  1290. void CarlaHostWindow::closeEvent(QCloseEvent* const event)
  1291. {
  1292. if (self->shouldIgnoreClose())
  1293. {
  1294. event->ignore();
  1295. return;
  1296. }
  1297. #ifdef CARLA_OS_MAC
  1298. if (self->fMacClosingHelper && ! (self->host.isControl || self->host.isPlugin))
  1299. {
  1300. self->fCustomStopAction = CUSTOM_ACTION_APP_CLOSE;
  1301. self->fMacClosingHelper = false;
  1302. event->ignore();
  1303. for i in reversed(range(self->fPluginCount)):
  1304. carla_show_custom_ui(i, false);
  1305. QTimer::singleShot(100, SIGNAL(close()));
  1306. return;
  1307. }
  1308. #endif
  1309. self->killTimers();
  1310. self->saveSettings();
  1311. if (carla_is_engine_running() && ! (self->host.isControl or self->host.isPlugin))
  1312. {
  1313. if (! slot_engineStop(true))
  1314. {
  1315. self->fCustomStopAction = CUSTOM_ACTION_APP_CLOSE;
  1316. event->ignore();
  1317. return;
  1318. }
  1319. }
  1320. QMainWindow::closeEvent(event);
  1321. }
  1322. //---------------------------------------------------------------------------------------------------------------------
  1323. // Files (menu actions)
  1324. void CarlaHostWindow::slot_fileNew()
  1325. {
  1326. }
  1327. void CarlaHostWindow::slot_fileOpen()
  1328. {
  1329. }
  1330. void CarlaHostWindow::slot_fileSave(const bool saveAs)
  1331. {
  1332. }
  1333. void CarlaHostWindow::slot_fileSaveAs()
  1334. {
  1335. }
  1336. void CarlaHostWindow::slot_loadProjectNow()
  1337. {
  1338. }
  1339. //---------------------------------------------------------------------------------------------------------------------
  1340. // Engine (menu actions)
  1341. void CarlaHostWindow::slot_engineStart()
  1342. {
  1343. const QString audioDriver = setEngineSettings(self->host);
  1344. const bool firstInit = self->fFirstEngineInit;
  1345. self->fFirstEngineInit = false;
  1346. self->ui.text_logs->appendPlainText("======= Starting engine =======");
  1347. if (carla_engine_init(audioDriver.toUtf8(), self->fClientName.toUtf8()))
  1348. {
  1349. if (firstInit && ! (self->host.isControl or self->host.isPlugin))
  1350. {
  1351. QSafeSettings settings;
  1352. const double lastBpm = settings.valueDouble("LastBPM", 120.0);
  1353. if (lastBpm >= 20.0)
  1354. carla_transport_bpm(lastBpm);
  1355. }
  1356. return;
  1357. }
  1358. else if (firstInit)
  1359. {
  1360. self->ui.text_logs->appendPlainText("Failed to start engine on first try, ignored");
  1361. return;
  1362. }
  1363. const QCarlaString audioError(carla_get_last_error());
  1364. if (audioError.isNotEmpty())
  1365. {
  1366. QMessageBox::critical(this,
  1367. tr("Error"),
  1368. tr("Could not connect to Audio backend '%1', possible reasons:\n%2").arg(audioDriver).arg(audioError));
  1369. }
  1370. else
  1371. {
  1372. QMessageBox::critical(this,
  1373. tr("Error"),
  1374. tr("Could not connect to Audio backend '%1'").arg(audioDriver));
  1375. }
  1376. }
  1377. bool CarlaHostWindow::slot_engineStop(const bool forced)
  1378. {
  1379. self->ui.text_logs->appendPlainText("======= Stopping engine =======");
  1380. if (self->fPluginCount == 0)
  1381. {
  1382. self->engineStopFinal();
  1383. return true;
  1384. }
  1385. if (! forced)
  1386. {
  1387. const QMessageBox::StandardButton ask = QMessageBox::question(this,
  1388. tr("Warning"),
  1389. tr("There are still some plugins loaded, you need to remove them to stop the engine.\n"
  1390. "Do you want to do this now?"),
  1391. QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
  1392. if (ask != QMessageBox::Yes)
  1393. return false;
  1394. }
  1395. return slot_engineStopTryAgain();
  1396. }
  1397. void CarlaHostWindow::slot_engineConfig()
  1398. {
  1399. RuntimeDriverSettingsW dialog(self->fParentOrSelf);
  1400. if (dialog.exec())
  1401. return;
  1402. QString audioDevice;
  1403. uint bufferSize;
  1404. double sampleRate;
  1405. dialog.getValues(audioDevice, bufferSize, sampleRate);
  1406. if (carla_is_engine_running())
  1407. {
  1408. carla_set_engine_buffer_size_and_sample_rate(bufferSize, sampleRate);
  1409. }
  1410. else
  1411. {
  1412. carla_set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice.toUtf8());
  1413. carla_set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, bufferSize, "");
  1414. carla_set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, sampleRate, "");
  1415. }
  1416. }
  1417. bool CarlaHostWindow::slot_engineStopTryAgain()
  1418. {
  1419. if (carla_is_engine_running() && ! carla_set_engine_about_to_close())
  1420. {
  1421. QTimer::singleShot(0, this, SLOT(slot_engineStopTryAgain()));
  1422. return false;
  1423. }
  1424. self->engineStopFinal();
  1425. return true;
  1426. }
  1427. //---------------------------------------------------------------------------------------------------------------------
  1428. // Engine (host callbacks)
  1429. void CarlaHostWindow::slot_handleEngineStartedCallback(uint pluginCount, int processMode, int transportMode, int bufferSize, float sampleRate, QString driverName)
  1430. {
  1431. self->ui.menu_PluginMacros->setEnabled(true);
  1432. self->ui.menu_Canvas->setEnabled(true);
  1433. self->ui.w_transport->setEnabled(true);
  1434. self->ui.act_canvas_show_internal->blockSignals(true);
  1435. self->ui.act_canvas_show_external->blockSignals(true);
  1436. if (processMode == ENGINE_PROCESS_MODE_PATCHBAY) // && ! self->host.isPlugin:
  1437. {
  1438. self->ui.act_canvas_show_internal->setChecked(true);
  1439. self->ui.act_canvas_show_internal->setVisible(true);
  1440. self->ui.act_canvas_show_external->setChecked(false);
  1441. self->ui.act_canvas_show_external->setVisible(true);
  1442. self->fExternalPatchbay = false;
  1443. }
  1444. else
  1445. {
  1446. self->ui.act_canvas_show_internal->setChecked(false);
  1447. self->ui.act_canvas_show_internal->setVisible(false);
  1448. self->ui.act_canvas_show_external->setChecked(true);
  1449. self->ui.act_canvas_show_external->setVisible(false);
  1450. self->fExternalPatchbay = true;
  1451. }
  1452. self->ui.act_canvas_show_internal->blockSignals(false);
  1453. self->ui.act_canvas_show_external->blockSignals(false);
  1454. if (! (self->host.isControl or self->host.isPlugin))
  1455. {
  1456. const bool canSave = (self->fProjectFilename.isNotEmpty() && QFile(self->fProjectFilename).exists()) || self->fSessionManagerName.isEmpty();
  1457. self->ui.act_file_save->setEnabled(canSave);
  1458. self->ui.act_engine_start->setEnabled(false);
  1459. self->ui.act_engine_stop->setEnabled(true);
  1460. }
  1461. if (! self->host.isPlugin)
  1462. self->enableTransport(transportMode != ENGINE_TRANSPORT_MODE_DISABLED);
  1463. if (self->host.isPlugin || self->fSessionManagerName.isEmpty())
  1464. {
  1465. self->ui.act_file_open->setEnabled(true);
  1466. self->ui.act_file_save_as->setEnabled(true);
  1467. }
  1468. self->ui.cb_transport_jack->setChecked(transportMode == ENGINE_TRANSPORT_MODE_JACK);
  1469. self->ui.cb_transport_jack->setEnabled(driverName == "JACK" and processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS);
  1470. if (self->ui.cb_transport_link->isEnabled())
  1471. self->ui.cb_transport_link->setChecked(self->host.transportExtra.contains(":link:"));
  1472. self->updateBufferSize(bufferSize);
  1473. self->updateSampleRate(int(sampleRate));
  1474. self->refreshRuntimeInfo(0.0, 0);
  1475. self->startTimers();
  1476. self->ui.text_logs->appendPlainText("======= Engine started ========");
  1477. self->ui.text_logs->appendPlainText("Carla engine started, details:");
  1478. self->ui.text_logs->appendPlainText(QString(" Driver name: %1").arg(driverName));
  1479. self->ui.text_logs->appendPlainText(QString(" Sample rate: %1").arg(int(sampleRate)));
  1480. self->ui.text_logs->appendPlainText(QString(" Process mode: %1").arg(EngineProcessMode2Str((EngineProcessMode)processMode)));
  1481. }
  1482. void CarlaHostWindow::slot_handleEngineStoppedCallback()
  1483. {
  1484. self->ui.text_logs->appendPlainText("======= Engine stopped ========");
  1485. /*
  1486. // TODO
  1487. patchcanvas.clear();
  1488. */
  1489. self->killTimers();
  1490. // just in case
  1491. self->removeAllPlugins();
  1492. self->refreshRuntimeInfo(0.0, 0);
  1493. self->ui.menu_PluginMacros->setEnabled(false);
  1494. self->ui.menu_Canvas->setEnabled(false);
  1495. self->ui.w_transport->setEnabled(false);
  1496. if (! (self->host.isControl || self->host.isPlugin))
  1497. {
  1498. self->ui.act_file_save->setEnabled(false);
  1499. self->ui.act_engine_start->setEnabled(true);
  1500. self->ui.act_engine_stop->setEnabled(false);
  1501. }
  1502. if (self->host.isPlugin || self->fSessionManagerName.isEmpty())
  1503. {
  1504. self->ui.act_file_open->setEnabled(false);
  1505. self->ui.act_file_save_as->setEnabled(false);
  1506. }
  1507. }
  1508. void CarlaHostWindow::slot_handleTransportModeChangedCallback(int transportMode, QString transportExtra)
  1509. {
  1510. }
  1511. void CarlaHostWindow::slot_handleBufferSizeChangedCallback(int newBufferSize)
  1512. {
  1513. }
  1514. void CarlaHostWindow::slot_handleSampleRateChangedCallback(double newSampleRate)
  1515. {
  1516. }
  1517. void CarlaHostWindow::slot_handleCancelableActionCallback(int pluginId, bool started, QString action)
  1518. {
  1519. }
  1520. void CarlaHostWindow::slot_canlableActionBoxClicked()
  1521. {
  1522. }
  1523. void CarlaHostWindow::slot_handleProjectLoadFinishedCallback()
  1524. {
  1525. }
  1526. //---------------------------------------------------------------------------------------------------------------------
  1527. // Plugins (menu actions)
  1528. void CarlaHostWindow::slot_favoritePluginAdd()
  1529. {
  1530. }
  1531. void CarlaHostWindow::slot_showPluginActionsMenu()
  1532. {
  1533. }
  1534. void CarlaHostWindow::slot_pluginAdd()
  1535. {
  1536. }
  1537. void CarlaHostWindow::slot_confirmRemoveAll()
  1538. {
  1539. }
  1540. void CarlaHostWindow::slot_jackAppAdd()
  1541. {
  1542. }
  1543. //---------------------------------------------------------------------------------------------------------------------
  1544. // Plugins (macros)
  1545. void CarlaHostWindow::slot_pluginsEnable()
  1546. {
  1547. }
  1548. void CarlaHostWindow::slot_pluginsDisable()
  1549. {
  1550. }
  1551. void CarlaHostWindow::slot_pluginsVolume100()
  1552. {
  1553. }
  1554. void CarlaHostWindow::slot_pluginsMute()
  1555. {
  1556. }
  1557. void CarlaHostWindow::slot_pluginsWet100()
  1558. {
  1559. }
  1560. void CarlaHostWindow::slot_pluginsBypass()
  1561. {
  1562. }
  1563. void CarlaHostWindow::slot_pluginsCenter()
  1564. {
  1565. }
  1566. void CarlaHostWindow::slot_pluginsCompact()
  1567. {
  1568. }
  1569. void CarlaHostWindow::slot_pluginsExpand()
  1570. {
  1571. }
  1572. //---------------------------------------------------------------------------------------------------------------------
  1573. // Plugins (host callbacks)
  1574. void CarlaHostWindow::slot_handlePluginAddedCallback(int pluginId, QString pluginName)
  1575. {
  1576. }
  1577. void CarlaHostWindow::slot_handlePluginRemovedCallback(int pluginId)
  1578. {
  1579. }
  1580. //---------------------------------------------------------------------------------------------------------------------
  1581. // Canvas (menu actions)
  1582. void CarlaHostWindow::slot_canvasShowInternal()
  1583. {
  1584. }
  1585. void CarlaHostWindow::slot_canvasShowExternal()
  1586. {
  1587. }
  1588. void CarlaHostWindow::slot_canvasArrange()
  1589. {
  1590. }
  1591. void CarlaHostWindow::slot_canvasRefresh()
  1592. {
  1593. }
  1594. void CarlaHostWindow::slot_canvasZoomFit()
  1595. {
  1596. }
  1597. void CarlaHostWindow::slot_canvasZoomIn()
  1598. {
  1599. }
  1600. void CarlaHostWindow::slot_canvasZoomOut()
  1601. {
  1602. }
  1603. void CarlaHostWindow::slot_canvasZoomReset()
  1604. {
  1605. }
  1606. void CarlaHostWindow::slot_canvasSaveImage()
  1607. {
  1608. }
  1609. //---------------------------------------------------------------------------------------------------------------------
  1610. // Canvas (canvas callbacks)
  1611. void CarlaHostWindow::slot_canvasItemMoved(int group_id, int split_mode, QPointF pos)
  1612. {
  1613. }
  1614. void CarlaHostWindow::slot_canvasSelectionChanged()
  1615. {
  1616. }
  1617. void CarlaHostWindow::slot_canvasScaleChanged(double scale)
  1618. {
  1619. }
  1620. void CarlaHostWindow::slot_canvasPluginSelected(QList<void*> pluginList)
  1621. {
  1622. }
  1623. //---------------------------------------------------------------------------------------------------------------------
  1624. // Canvas (host callbacks)
  1625. void CarlaHostWindow::slot_handlePatchbayClientAddedCallback(int clientId, int clientIcon, int pluginId, QString clientName)
  1626. {
  1627. }
  1628. void CarlaHostWindow::slot_handlePatchbayClientRemovedCallback(int clientId)
  1629. {
  1630. }
  1631. void CarlaHostWindow::slot_handlePatchbayClientRenamedCallback(int clientId, QString newClientName)
  1632. {
  1633. }
  1634. void CarlaHostWindow::slot_handlePatchbayClientDataChangedCallback(int clientId, int clientIcon, int pluginId)
  1635. {
  1636. }
  1637. void CarlaHostWindow::slot_handlePatchbayPortAddedCallback(int clientId, int portId, int portFlags, int portGroupId, QString portName)
  1638. {
  1639. }
  1640. void CarlaHostWindow::slot_handlePatchbayPortRemovedCallback(int groupId, int portId)
  1641. {
  1642. }
  1643. void CarlaHostWindow::slot_handlePatchbayPortChangedCallback(int groupId, int portId, int portFlags, int portGroupId, QString newPortName)
  1644. {
  1645. }
  1646. void CarlaHostWindow::slot_handlePatchbayPortGroupAddedCallback(int groupId, int portId, int portGroupId, QString newPortName)
  1647. {
  1648. }
  1649. void CarlaHostWindow::slot_handlePatchbayPortGroupRemovedCallback(int groupId, int portId)
  1650. {
  1651. }
  1652. void CarlaHostWindow::slot_handlePatchbayPortGroupChangedCallback(int groupId, int portId, int portGroupId, QString newPortName)
  1653. {
  1654. }
  1655. void CarlaHostWindow::slot_handlePatchbayConnectionAddedCallback(int connectionId, int groupOutId, int portOutId, int groupInId, int portInId)
  1656. {
  1657. }
  1658. void CarlaHostWindow::slot_handlePatchbayConnectionRemovedCallback(int connectionId, int portOutId, int portInId)
  1659. {
  1660. }
  1661. //---------------------------------------------------------------------------------------------------------------------
  1662. // Settings (helpers)
  1663. void CarlaHostWindow::slot_restoreCanvasScrollbarValues()
  1664. {
  1665. }
  1666. //---------------------------------------------------------------------------------------------------------------------
  1667. // Settings (menu actions)
  1668. void CarlaHostWindow::slot_showSidePanel(const bool yesNo)
  1669. {
  1670. self->showSidePanel(yesNo);
  1671. }
  1672. void CarlaHostWindow::slot_showToolbar(const bool yesNo)
  1673. {
  1674. self->showToolbar(yesNo);
  1675. }
  1676. void CarlaHostWindow::slot_showCanvasMeters(const bool yesNo)
  1677. {
  1678. self->ui.peak_in->setVisible(yesNo);
  1679. self->ui.peak_out->setVisible(yesNo);
  1680. QTimer::singleShot(0, this, SLOT(slot_miniCanvasCheckAll()));
  1681. }
  1682. void CarlaHostWindow::slot_showCanvasKeyboard(const bool yesNo)
  1683. {
  1684. /*
  1685. // TODO
  1686. self->ui.scrollArea->setVisible(yesNo);
  1687. */
  1688. QTimer::singleShot(0, this, SLOT(slot_miniCanvasCheckAll()));
  1689. }
  1690. void CarlaHostWindow::slot_configureCarla()
  1691. {
  1692. const bool hasGL = true;
  1693. CarlaSettingsW dialog(self->fParentOrSelf, self->host, true, hasGL);
  1694. if (! dialog.exec())
  1695. return;
  1696. self->loadSettings(false);
  1697. /*
  1698. // TODO
  1699. patchcanvas.clear()
  1700. setupCanvas();
  1701. */
  1702. slot_miniCanvasCheckAll();
  1703. if (self->host.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK && self->host.isPlugin)
  1704. pass();
  1705. else if (carla_is_engine_running())
  1706. carla_patchbay_refresh(self->fExternalPatchbay);
  1707. }
  1708. //---------------------------------------------------------------------------------------------------------------------
  1709. // About (menu actions)
  1710. void CarlaHostWindow::slot_aboutCarla()
  1711. {
  1712. CarlaAboutW(self->fParentOrSelf, self->host).exec();
  1713. }
  1714. void CarlaHostWindow::slot_aboutJuce()
  1715. {
  1716. JuceAboutW(self->fParentOrSelf).exec();
  1717. }
  1718. void CarlaHostWindow::slot_aboutQt()
  1719. {
  1720. qApp->aboutQt();
  1721. }
  1722. //---------------------------------------------------------------------------------------------------------------------
  1723. // Disk (menu actions)
  1724. void CarlaHostWindow::slot_diskFolderChanged(int index)
  1725. {
  1726. }
  1727. void CarlaHostWindow::slot_diskFolderAdd()
  1728. {
  1729. }
  1730. void CarlaHostWindow::slot_diskFolderRemove()
  1731. {
  1732. }
  1733. void CarlaHostWindow::slot_fileTreeDoubleClicked(QModelIndex* modelIndex)
  1734. {
  1735. }
  1736. //---------------------------------------------------------------------------------------------------------------------
  1737. // Transport (menu actions)
  1738. void CarlaHostWindow::slot_transportPlayPause(const bool toggled)
  1739. {
  1740. if (self->host.isPlugin || ! carla_is_engine_running())
  1741. return;
  1742. if (toggled)
  1743. carla_transport_play();
  1744. else
  1745. carla_transport_pause();
  1746. self->refreshTransport();
  1747. }
  1748. void CarlaHostWindow::slot_transportStop()
  1749. {
  1750. if (self->host.isPlugin || ! carla_is_engine_running())
  1751. return;
  1752. carla_transport_pause();
  1753. carla_transport_relocate(0);
  1754. self->refreshTransport();
  1755. }
  1756. void CarlaHostWindow::slot_transportBackwards()
  1757. {
  1758. if (self->host.isPlugin || ! carla_is_engine_running())
  1759. return;
  1760. int64_t newFrame = carla_get_current_transport_frame() - 100000;
  1761. if (newFrame < 0)
  1762. newFrame = 0;
  1763. carla_transport_relocate(newFrame);
  1764. }
  1765. void CarlaHostWindow::slot_transportBpmChanged(const qreal newValue)
  1766. {
  1767. carla_transport_bpm(newValue);
  1768. }
  1769. void CarlaHostWindow::slot_transportForwards()
  1770. {
  1771. if (carla_isZero(self->fSampleRate) || self->host.isPlugin || ! carla_is_engine_running())
  1772. return;
  1773. const int64_t newFrame = carla_get_current_transport_frame() + int(self->fSampleRate*2.5);
  1774. carla_transport_relocate(newFrame);
  1775. }
  1776. void CarlaHostWindow::slot_transportJackEnabled(const bool clicked)
  1777. {
  1778. if (! carla_is_engine_running())
  1779. return;
  1780. self->host.transportMode = clicked ? ENGINE_TRANSPORT_MODE_JACK : ENGINE_TRANSPORT_MODE_INTERNAL;
  1781. carla_set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, self->host.transportMode, self->host.transportExtra.toUtf8());
  1782. }
  1783. void CarlaHostWindow::slot_transportLinkEnabled(const bool clicked)
  1784. {
  1785. if (! carla_is_engine_running())
  1786. return;
  1787. const char* const extra = clicked ? ":link:" : "";
  1788. self->host.transportExtra = extra;
  1789. carla_set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, self->host.transportMode, self->host.transportExtra.toUtf8());
  1790. }
  1791. //---------------------------------------------------------------------------------------------------------------------
  1792. // Other
  1793. void CarlaHostWindow::slot_xrunClear()
  1794. {
  1795. carla_clear_engine_xruns();
  1796. }
  1797. //---------------------------------------------------------------------------------------------------------------------
  1798. // Canvas scrollbars
  1799. void CarlaHostWindow::slot_horizontalScrollBarChanged(int value)
  1800. {
  1801. }
  1802. void CarlaHostWindow::slot_verticalScrollBarChanged(int value)
  1803. {
  1804. }
  1805. //---------------------------------------------------------------------------------------------------------------------
  1806. // Canvas keyboard
  1807. void CarlaHostWindow::slot_noteOn(int note)
  1808. {
  1809. }
  1810. void CarlaHostWindow::slot_noteOff(int note)
  1811. {
  1812. }
  1813. //---------------------------------------------------------------------------------------------------------------------
  1814. // Canvas keyboard (host callbacks)
  1815. void CarlaHostWindow::slot_handleNoteOnCallback(int pluginId, int channel, int note, int velocity)
  1816. {
  1817. }
  1818. void CarlaHostWindow::slot_handleNoteOffCallback(int pluginId, int channel, int note)
  1819. {
  1820. }
  1821. //---------------------------------------------------------------------------------------------------------------------
  1822. void CarlaHostWindow::slot_handleUpdateCallback(int pluginId)
  1823. {
  1824. }
  1825. //---------------------------------------------------------------------------------------------------------------------
  1826. // MiniCanvas stuff
  1827. void CarlaHostWindow::slot_miniCanvasCheckAll()
  1828. {
  1829. }
  1830. void CarlaHostWindow::slot_miniCanvasCheckSize()
  1831. {
  1832. }
  1833. void CarlaHostWindow::slot_miniCanvasMoved(qreal xp, qreal yp)
  1834. {
  1835. }
  1836. //---------------------------------------------------------------------------------------------------------------------
  1837. // Misc
  1838. void CarlaHostWindow::slot_tabChanged(int index)
  1839. {
  1840. }
  1841. void CarlaHostWindow::slot_handleReloadAllCallback(int pluginId)
  1842. {
  1843. }
  1844. //---------------------------------------------------------------------------------------------------------------------
  1845. void CarlaHostWindow::slot_handleNSMCallback(int opcode, int valueInt, QString valueStr)
  1846. {
  1847. }
  1848. //---------------------------------------------------------------------------------------------------------------------
  1849. void CarlaHostWindow::slot_handleDebugCallback(int pluginId, int value1, int value2, int value3, float valuef, QString valueStr)
  1850. {
  1851. }
  1852. void CarlaHostWindow::slot_handleInfoCallback(QString info)
  1853. {
  1854. }
  1855. void CarlaHostWindow::slot_handleErrorCallback(QString error)
  1856. {
  1857. }
  1858. void CarlaHostWindow::slot_handleQuitCallback()
  1859. {
  1860. }
  1861. void CarlaHostWindow::slot_handleInlineDisplayRedrawCallback(int pluginId)
  1862. {
  1863. }
  1864. //---------------------------------------------------------------------------------------------------------------------
  1865. void CarlaHostWindow::slot_handleSIGUSR1()
  1866. {
  1867. }
  1868. void CarlaHostWindow::slot_handleSIGTERM()
  1869. {
  1870. }
  1871. //---------------------------------------------------------------------------------------------------------------------
  1872. // Canvas callback
  1873. void _canvasCallback(void* const ptr, const int action, int value1, int value2, QString valueStr)
  1874. {
  1875. CarlaHost* const host = (CarlaHost*)(ptr);
  1876. CARLA_SAFE_ASSERT_RETURN(host != nullptr,);
  1877. switch (action)
  1878. {
  1879. }
  1880. }
  1881. //---------------------------------------------------------------------------------------------------------------------
  1882. // Engine callback
  1883. void _engineCallback(void* const ptr, const EngineCallbackOpcode action, uint pluginId, int value1, int value2, int value3, float valuef, const char* const valueStr)
  1884. {
  1885. /*
  1886. carla_stdout("_engineCallback(%p, %i:%s, %u, %i, %i, %i, %f, %s)",
  1887. ptr, action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valuef, valueStr);
  1888. */
  1889. CarlaHost* const host = (CarlaHost*)(ptr);
  1890. CARLA_SAFE_ASSERT_RETURN(host != nullptr,);
  1891. switch (action)
  1892. {
  1893. case ENGINE_CALLBACK_ENGINE_STARTED:
  1894. host->processMode = static_cast<EngineProcessMode>(value1);
  1895. host->transportMode = static_cast<EngineTransportMode>(value2);
  1896. break;
  1897. case ENGINE_CALLBACK_PROCESS_MODE_CHANGED:
  1898. host->processMode = static_cast<EngineProcessMode>(value1);
  1899. break;
  1900. case ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED:
  1901. host->transportMode = static_cast<EngineTransportMode>(value1);
  1902. host->transportExtra = valueStr;
  1903. break;
  1904. default:
  1905. break;
  1906. }
  1907. // TODO
  1908. switch (action)
  1909. {
  1910. case ENGINE_CALLBACK_ENGINE_STARTED:
  1911. emit host->EngineStartedCallback(pluginId, value1, value2, value3, valuef, valueStr);
  1912. break;
  1913. case ENGINE_CALLBACK_ENGINE_STOPPED:
  1914. emit host->EngineStoppedCallback();
  1915. break;
  1916. // FIXME
  1917. default:
  1918. break;
  1919. }
  1920. }
  1921. //---------------------------------------------------------------------------------------------------------------------
  1922. // File callback
  1923. static const char* _fileCallback(void*, const FileCallbackOpcode action, const bool isDir, const char* const title, const char* const filter)
  1924. {
  1925. QString ret;
  1926. const QFileDialog::Options options = QFileDialog::Options(isDir ? QFileDialog::ShowDirsOnly : 0x0);
  1927. switch (action)
  1928. {
  1929. case FILE_CALLBACK_DEBUG:
  1930. break;
  1931. case FILE_CALLBACK_OPEN:
  1932. ret = QFileDialog::getOpenFileName(gCarla.gui, title, "", filter, nullptr, options);
  1933. break;
  1934. case FILE_CALLBACK_SAVE:
  1935. ret = QFileDialog::getSaveFileName(gCarla.gui, title, "", filter, nullptr, options);
  1936. break;
  1937. }
  1938. if (ret.isEmpty())
  1939. return nullptr;
  1940. static QByteArray byteRet;
  1941. byteRet = ret.toUtf8();
  1942. return byteRet.constData();
  1943. }
  1944. //---------------------------------------------------------------------------------------------------------------------
  1945. // Init host
  1946. CarlaHost& initHost(const QString initName, const bool isControl, const bool isPlugin, const bool failError)
  1947. {
  1948. QString pathBinaries, pathResources;
  1949. getPaths(pathBinaries, pathResources);
  1950. //-----------------------------------------------------------------------------------------------------------------
  1951. // Fail if binary dir is not found
  1952. if (! QDir(pathBinaries).exists())
  1953. {
  1954. if (failError)
  1955. {
  1956. QMessageBox::critical(nullptr, "Error", "Failed to find the carla binaries, cannot continue");
  1957. std::exit(1);
  1958. }
  1959. // FIXME?
  1960. // return;
  1961. }
  1962. //-----------------------------------------------------------------------------------------------------------------
  1963. // Print info
  1964. carla_stdout(QString("Carla %1 started, status:").arg(CARLA_VERSION_STRING).toUtf8());
  1965. carla_stdout(QString(" Qt version: %1").arg(QT_VERSION_STR).toUtf8());
  1966. carla_stdout(QString(" Binary dir: %1").arg(pathBinaries).toUtf8());
  1967. carla_stdout(QString(" Resources dir: %1").arg(pathResources).toUtf8());
  1968. // ----------------------------------------------------------------------------------------------------------------
  1969. // Init host
  1970. // TODO
  1971. if (failError)
  1972. {
  1973. // # no try
  1974. // host = HostClass() if HostClass is not None else CarlaHostQtDLL(libname, loadGlobal)
  1975. }
  1976. else
  1977. {
  1978. // try:
  1979. // host = HostClass() if HostClass is not None else CarlaHostQtDLL(libname, loadGlobal)
  1980. // except:
  1981. // host = CarlaHostQtNull()
  1982. }
  1983. static CarlaHost host;
  1984. host.isControl = isControl;
  1985. host.isPlugin = isPlugin;
  1986. carla_set_engine_callback(_engineCallback, &host);
  1987. carla_set_file_callback(_fileCallback, nullptr);
  1988. // If it's a plugin the paths are already set
  1989. if (! isPlugin)
  1990. {
  1991. host.pathBinaries = pathBinaries;
  1992. host.pathResources = pathResources;
  1993. carla_set_engine_option(ENGINE_OPTION_PATH_BINARIES, 0, pathBinaries.toUtf8());
  1994. carla_set_engine_option(ENGINE_OPTION_PATH_RESOURCES, 0, pathResources.toUtf8());
  1995. if (! isControl)
  1996. host.nsmOK = carla_nsm_init(getpid(), initName.toUtf8());
  1997. }
  1998. // ----------------------------------------------------------------------------------------------------------------
  1999. // Done
  2000. gCarla.host = &host;
  2001. return host;
  2002. }
  2003. //---------------------------------------------------------------------------------------------------------------------
  2004. // Load host settings
  2005. void loadHostSettings(CarlaHost& host)
  2006. {
  2007. const QSafeSettings settings("falkTX", "Carla2");
  2008. host.experimental = settings.valueBool(CARLA_KEY_MAIN_EXPERIMENTAL, CARLA_DEFAULT_MAIN_EXPERIMENTAL);
  2009. host.exportLV2 = settings.valueBool(CARLA_KEY_EXPERIMENTAL_EXPORT_LV2, CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT);
  2010. host.manageUIs = settings.valueBool(CARLA_KEY_ENGINE_MANAGE_UIS, CARLA_DEFAULT_MANAGE_UIS);
  2011. host.maxParameters = settings.valueUInt(CARLA_KEY_ENGINE_MAX_PARAMETERS, CARLA_DEFAULT_MAX_PARAMETERS);
  2012. host.forceStereo = settings.valueBool(CARLA_KEY_ENGINE_FORCE_STEREO, CARLA_DEFAULT_FORCE_STEREO);
  2013. host.preferPluginBridges = settings.valueBool(CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES, CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES);
  2014. host.preferUIBridges = settings.valueBool(CARLA_KEY_ENGINE_PREFER_UI_BRIDGES, CARLA_DEFAULT_PREFER_UI_BRIDGES);
  2015. host.preventBadBehaviour = settings.valueBool(CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR, CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR);
  2016. host.showLogs = settings.valueBool(CARLA_KEY_MAIN_SHOW_LOGS, CARLA_DEFAULT_MAIN_SHOW_LOGS);
  2017. host.showPluginBridges = settings.valueBool(CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES, CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES);
  2018. host.showWineBridges = settings.valueBool(CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES, CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES);
  2019. host.uiBridgesTimeout = settings.valueUInt(CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT, CARLA_DEFAULT_UI_BRIDGES_TIMEOUT);
  2020. host.uisAlwaysOnTop = settings.valueBool(CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP, CARLA_DEFAULT_UIS_ALWAYS_ON_TOP);
  2021. if (host.isPlugin)
  2022. return;
  2023. host.transportExtra = settings.valueString(CARLA_KEY_ENGINE_TRANSPORT_EXTRA, "");
  2024. // enums
  2025. /*
  2026. // TODO
  2027. if (host.audioDriverForced.isNotEmpty())
  2028. host.transportMode = settings.valueUInt(CARLA_KEY_ENGINE_TRANSPORT_MODE, CARLA_DEFAULT_TRANSPORT_MODE);
  2029. if (! host.processModeForced)
  2030. host.processMode = settings.valueUInt(CARLA_KEY_ENGINE_PROCESS_MODE, CARLA_DEFAULT_PROCESS_MODE);
  2031. */
  2032. host.nextProcessMode = host.processMode;
  2033. // ----------------------------------------------------------------------------------------------------------------
  2034. // fix things if needed
  2035. if (host.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
  2036. {
  2037. if (LADISH_APP_NAME)
  2038. {
  2039. carla_stdout("LADISH detected but using multiple clients (not allowed), forcing single client now");
  2040. host.nextProcessMode = host.processMode = ENGINE_PROCESS_MODE_SINGLE_CLIENT;
  2041. }
  2042. else
  2043. {
  2044. host.transportMode = ENGINE_TRANSPORT_MODE_JACK;
  2045. }
  2046. }
  2047. if (gCarla.nogui)
  2048. host.showLogs = false;
  2049. // ----------------------------------------------------------------------------------------------------------------
  2050. // run headless host now if nogui option enabled
  2051. if (gCarla.nogui)
  2052. runHostWithoutUI(host);
  2053. }
  2054. //---------------------------------------------------------------------------------------------------------------------
  2055. // Set host settings
  2056. void setHostSettings(const CarlaHost& host)
  2057. {
  2058. carla_set_engine_option(ENGINE_OPTION_FORCE_STEREO, host.forceStereo, "");
  2059. carla_set_engine_option(ENGINE_OPTION_MAX_PARAMETERS, host.maxParameters, "");
  2060. carla_set_engine_option(ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, host.preferPluginBridges, "");
  2061. carla_set_engine_option(ENGINE_OPTION_PREFER_UI_BRIDGES, host.preferUIBridges, "");
  2062. carla_set_engine_option(ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR, host.preventBadBehaviour, "");
  2063. carla_set_engine_option(ENGINE_OPTION_UI_BRIDGES_TIMEOUT, host.uiBridgesTimeout, "");
  2064. carla_set_engine_option(ENGINE_OPTION_UIS_ALWAYS_ON_TOP, host.uisAlwaysOnTop, "");
  2065. if (host.isPlugin || host.isRemote || carla_is_engine_running())
  2066. return;
  2067. carla_set_engine_option(ENGINE_OPTION_PROCESS_MODE, host.nextProcessMode, "");
  2068. carla_set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, host.transportMode, host.transportExtra.toUtf8());
  2069. carla_set_engine_option(ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT, host.showLogs, "");
  2070. }
  2071. //---------------------------------------------------------------------------------------------------------------------
  2072. // Set Engine settings according to carla preferences. Returns selected audio driver.
  2073. QString setEngineSettings(CarlaHost& host)
  2074. {
  2075. //-----------------------------------------------------------------------------------------------------------------
  2076. // do nothing if control
  2077. if (host.isControl)
  2078. return "Control";
  2079. //-----------------------------------------------------------------------------------------------------------------
  2080. const QSafeSettings settings("falkTX", "Carla2");
  2081. //-----------------------------------------------------------------------------------------------------------------
  2082. // main settings
  2083. setHostSettings(host);
  2084. //-----------------------------------------------------------------------------------------------------------------
  2085. // file paths
  2086. QStringList FILE_PATH_AUDIO = settings.valueStringList(CARLA_KEY_PATHS_AUDIO, CARLA_DEFAULT_FILE_PATH_AUDIO);
  2087. QStringList FILE_PATH_MIDI = settings.valueStringList(CARLA_KEY_PATHS_MIDI, CARLA_DEFAULT_FILE_PATH_MIDI);
  2088. /*
  2089. // TODO
  2090. carla_set_engine_option(ENGINE_OPTION_FILE_PATH, FILE_AUDIO, splitter.join(FILE_PATH_AUDIO));
  2091. carla_set_engine_option(ENGINE_OPTION_FILE_PATH, FILE_MIDI, splitter.join(FILE_PATH_MIDI));
  2092. */
  2093. // CARLA_PATH_SPLITTER
  2094. //-----------------------------------------------------------------------------------------------------------------
  2095. // plugin paths
  2096. QStringList LADSPA_PATH = settings.valueStringList(CARLA_KEY_PATHS_LADSPA, CARLA_DEFAULT_LADSPA_PATH);
  2097. QStringList DSSI_PATH = settings.valueStringList(CARLA_KEY_PATHS_DSSI, CARLA_DEFAULT_DSSI_PATH);
  2098. QStringList LV2_PATH = settings.valueStringList(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH);
  2099. QStringList VST2_PATH = settings.valueStringList(CARLA_KEY_PATHS_VST2, CARLA_DEFAULT_VST2_PATH);
  2100. QStringList VST3_PATH = settings.valueStringList(CARLA_KEY_PATHS_VST3, CARLA_DEFAULT_VST3_PATH);
  2101. QStringList SF2_PATH = settings.valueStringList(CARLA_KEY_PATHS_SF2, CARLA_DEFAULT_SF2_PATH);
  2102. QStringList SFZ_PATH = settings.valueStringList(CARLA_KEY_PATHS_SFZ, CARLA_DEFAULT_SFZ_PATH);
  2103. /*
  2104. // TODO
  2105. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_LADSPA, splitter.join(LADSPA_PATH))
  2106. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_DSSI, splitter.join(DSSI_PATH))
  2107. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_LV2, splitter.join(LV2_PATH))
  2108. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_VST2, splitter.join(VST2_PATH))
  2109. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_VST3, splitter.join(VST3_PATH))
  2110. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_SF2, splitter.join(SF2_PATH))
  2111. carla_set_engine_option(ENGINE_OPTION_PLUGIN_PATH, PLUGIN_SFZ, splitter.join(SFZ_PATH))
  2112. */
  2113. //-----------------------------------------------------------------------------------------------------------------
  2114. // don't continue if plugin
  2115. if (host.isPlugin)
  2116. return "Plugin";
  2117. //-----------------------------------------------------------------------------------------------------------------
  2118. // osc settings
  2119. const bool oscEnabled = settings.valueBool(CARLA_KEY_OSC_ENABLED, CARLA_DEFAULT_OSC_ENABLED);
  2120. int portNumTCP, portNumUDP;
  2121. if (! settings.valueBool(CARLA_KEY_OSC_TCP_PORT_ENABLED, CARLA_DEFAULT_OSC_TCP_PORT_ENABLED))
  2122. portNumTCP = -1;
  2123. else if (settings.valueBool(CARLA_KEY_OSC_TCP_PORT_RANDOM, CARLA_DEFAULT_OSC_TCP_PORT_RANDOM))
  2124. portNumTCP = 0;
  2125. else
  2126. portNumTCP = settings.valueUInt(CARLA_KEY_OSC_TCP_PORT_NUMBER, CARLA_DEFAULT_OSC_TCP_PORT_NUMBER);
  2127. if (! settings.valueBool(CARLA_KEY_OSC_UDP_PORT_ENABLED, CARLA_DEFAULT_OSC_UDP_PORT_ENABLED))
  2128. portNumUDP = -1;
  2129. else if (settings.valueBool(CARLA_KEY_OSC_UDP_PORT_RANDOM, CARLA_DEFAULT_OSC_UDP_PORT_RANDOM))
  2130. portNumUDP = 0;
  2131. else
  2132. portNumUDP = settings.valueUInt(CARLA_KEY_OSC_UDP_PORT_NUMBER, CARLA_DEFAULT_OSC_UDP_PORT_NUMBER);
  2133. carla_set_engine_option(ENGINE_OPTION_OSC_ENABLED, oscEnabled ? 1 : 0, "");
  2134. carla_set_engine_option(ENGINE_OPTION_OSC_PORT_TCP, portNumTCP, "");
  2135. carla_set_engine_option(ENGINE_OPTION_OSC_PORT_UDP, portNumUDP, "");
  2136. //-----------------------------------------------------------------------------------------------------------------
  2137. // wine settings
  2138. const QString optWineExecutable = settings.valueString(CARLA_KEY_WINE_EXECUTABLE, CARLA_DEFAULT_WINE_EXECUTABLE);
  2139. const bool optWineAutoPrefix = settings.valueBool(CARLA_KEY_WINE_AUTO_PREFIX, CARLA_DEFAULT_WINE_AUTO_PREFIX);
  2140. const QString optWineFallbackPrefix = settings.valueString(CARLA_KEY_WINE_FALLBACK_PREFIX, CARLA_DEFAULT_WINE_FALLBACK_PREFIX);
  2141. const bool optWineRtPrioEnabled = settings.valueBool(CARLA_KEY_WINE_RT_PRIO_ENABLED, CARLA_DEFAULT_WINE_RT_PRIO_ENABLED);
  2142. const uint optWineBaseRtPrio = settings.valueUInt(CARLA_KEY_WINE_BASE_RT_PRIO, CARLA_DEFAULT_WINE_BASE_RT_PRIO);
  2143. const uint optWineServerRtPrio = settings.valueUInt(CARLA_KEY_WINE_SERVER_RT_PRIO, CARLA_DEFAULT_WINE_SERVER_RT_PRIO);
  2144. carla_set_engine_option(ENGINE_OPTION_WINE_EXECUTABLE, 0, optWineExecutable.toUtf8());
  2145. carla_set_engine_option(ENGINE_OPTION_WINE_AUTO_PREFIX, optWineAutoPrefix ? 1 : 0, "");
  2146. /*
  2147. // TODO
  2148. carla_set_engine_option(ENGINE_OPTION_WINE_FALLBACK_PREFIX, 0, os.path.expanduser(optWineFallbackPrefix));
  2149. */
  2150. carla_set_engine_option(ENGINE_OPTION_WINE_RT_PRIO_ENABLED, optWineRtPrioEnabled ? 1 : 0, "");
  2151. carla_set_engine_option(ENGINE_OPTION_WINE_BASE_RT_PRIO, optWineBaseRtPrio, "");
  2152. carla_set_engine_option(ENGINE_OPTION_WINE_SERVER_RT_PRIO, optWineServerRtPrio, "");
  2153. //-----------------------------------------------------------------------------------------------------------------
  2154. // driver and device settings
  2155. QString audioDriver;
  2156. // driver name
  2157. if (host.audioDriverForced.isNotEmpty())
  2158. audioDriver = host.audioDriverForced;
  2159. else
  2160. audioDriver = settings.valueString(CARLA_KEY_ENGINE_AUDIO_DRIVER, CARLA_DEFAULT_AUDIO_DRIVER);
  2161. // driver options
  2162. const QString prefix(QString("%1%2").arg(CARLA_KEY_ENGINE_DRIVER_PREFIX).arg(audioDriver));
  2163. const QString audioDevice = settings.valueString(QString("%1/Device").arg(prefix), "");
  2164. const uint audioBufferSize = settings.valueUInt(QString("%1/BufferSize").arg(prefix), CARLA_DEFAULT_AUDIO_BUFFER_SIZE);
  2165. const uint audioSampleRate = settings.valueUInt(QString("%1/SampleRate").arg(prefix), CARLA_DEFAULT_AUDIO_SAMPLE_RATE);
  2166. const bool audioTripleBuffer = settings.valueBool(QString("%1/TripleBuffer").arg(prefix), CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER);
  2167. // Only setup audio things if engine is not running
  2168. if (! carla_is_engine_running())
  2169. {
  2170. carla_set_engine_option(ENGINE_OPTION_AUDIO_DRIVER, 0, audioDriver.toUtf8());
  2171. carla_set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice.toUtf8());
  2172. if (! audioDriver.startsWith("JACK"))
  2173. {
  2174. carla_set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, audioBufferSize, "");
  2175. carla_set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, audioSampleRate, "");
  2176. carla_set_engine_option(ENGINE_OPTION_AUDIO_TRIPLE_BUFFER, audioTripleBuffer ? 1 : 0, "");
  2177. }
  2178. }
  2179. //-----------------------------------------------------------------------------------------------------------------
  2180. // fix things if needed
  2181. if (audioDriver != "JACK" && host.transportMode == ENGINE_TRANSPORT_MODE_JACK)
  2182. {
  2183. host.transportMode = ENGINE_TRANSPORT_MODE_INTERNAL;
  2184. carla_set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, ENGINE_TRANSPORT_MODE_INTERNAL, host.transportExtra.toUtf8());
  2185. }
  2186. //-----------------------------------------------------------------------------------------------------------------
  2187. // return selected driver name
  2188. return audioDriver;
  2189. }
  2190. //---------------------------------------------------------------------------------------------------------------------
  2191. // Run Carla without showing UI
  2192. void runHostWithoutUI(CarlaHost& host)
  2193. {
  2194. //-----------------------------------------------------------------------------------------------------------------
  2195. // Some initial checks
  2196. if (! gCarla.nogui)
  2197. return;
  2198. const QString projectFile = getInitialProjectFile(true);
  2199. if (projectFile.isEmpty())
  2200. {
  2201. carla_stdout("Carla no-gui mode can only be used together with a project file.");
  2202. std::exit(1);
  2203. }
  2204. //-----------------------------------------------------------------------------------------------------------------
  2205. // Init engine
  2206. const QString audioDriver = setEngineSettings(host);
  2207. if (! carla_engine_init(audioDriver.toUtf8(), "Carla"))
  2208. {
  2209. carla_stdout("Engine failed to initialize, possible reasons:\n%s", carla_get_last_error());
  2210. std::exit(1);
  2211. }
  2212. if (! carla_load_project(projectFile.toUtf8()))
  2213. {
  2214. carla_stdout("Failed to load selected project file, possible reasons:\n%s", carla_get_last_error());
  2215. carla_engine_close();
  2216. std::exit(1);
  2217. }
  2218. //-----------------------------------------------------------------------------------------------------------------
  2219. // Idle
  2220. carla_stdout("Carla ready!");
  2221. while (carla_is_engine_running() && ! gCarla.term)
  2222. {
  2223. carla_engine_idle();
  2224. carla_msleep(33); // 30 Hz
  2225. }
  2226. //-----------------------------------------------------------------------------------------------------------------
  2227. // Stop
  2228. carla_engine_close();
  2229. std::exit(0);
  2230. }
  2231. //---------------------------------------------------------------------------------------------------------------------