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.

2848 lines
98KB

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