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.

2835 lines
97KB

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