/* * Carla plugin host * Copyright (C) 2011-2019 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ //--------------------------------------------------------------------------------------------------------------------- // Imports (Global) #include #include #include #include #include #include #include //--------------------------------------------------------------------------------------------------------------------- // Imports (Custom) #include "host.hpp" #include "ui_carla_host.hpp" #include "../../backend/CarlaHost.h" #include "../../backend/CarlaUtils.h" #include "../../utils/CarlaBackendUtils.hpp" #include "../../utils/CarlaMathUtils.hpp" #include "../../utils/CarlaString.hpp" //--------------------------------------------------------------------------------------------------------------------- CarlaObject gCarla; //--------------------------------------------------------------------------------------------------------------------- Host::Host() : isControl(false), isPlugin(false), isRemote(false), nsmOK(false), processMode(ENGINE_PROCESS_MODE_PATCHBAY), transportMode(ENGINE_TRANSPORT_MODE_INTERNAL), transportExtra(), nextProcessMode(processMode), processModeForced(false), audioDriverForced(), experimental(false), exportLV2(false), forceStereo(false), manageUIs(false), maxParameters(false), preferPluginBridges(false), preferUIBridges(false), preventBadBehaviour(false), showLogs(false), showPluginBridges(false), showWineBridges(false), uiBridgesTimeout(0), uisAlwaysOnTop(false), pathBinaries(), pathResources() {} //--------------------------------------------------------------------------------------------------------------------- struct CachedSavedSettings { uint _CARLA_KEY_MAIN_REFRESH_INTERVAL = 0; bool _CARLA_KEY_MAIN_CONFIRM_EXIT = false; bool _CARLA_KEY_CANVAS_FANCY_EYE_CANDY = false; }; //--------------------------------------------------------------------------------------------------------------------- // Host Private Data struct CarlaHostWindow::PrivateData { Ui::CarlaHostW ui; int fIdleTimerNull = 0; int fIdleTimerFast = 0; int fIdleTimerSlow = 0; bool fLadspaRdfNeedsUpdate = true; QStringList fLadspaRdfList; int fPluginCount = 0; QList fPluginList; void* fPluginDatabaseDialog = nullptr; QStringList fFavoritePlugins; QCarlaString fProjectFilename; bool fIsProjectLoading = false; bool fCurrentlyRemovingAllPlugins = false; double fLastTransportBPM = 0.0; uint64_t fLastTransportFrame = 0; bool fLastTransportState = false; uint fBufferSize = 0; double fSampleRate = 0.0; QCarlaString fOscAddressTCP; QCarlaString fOscAddressUDP; QCarlaString fOscReportedHost; #ifdef CARLA_OS_MAC bool fMacClosingHelper = true; #endif // CancelableActionCallback Box void* fCancelableActionBox = nullptr; // run a custom action after engine is properly closed CustomActions fCustomStopAction = CUSTOM_ACTION_NONE; // first attempt of auto-start engine doesn't show an error bool fFirstEngineInit = true; // to be filled with key-value pairs of current settings CachedSavedSettings fSavedSettings; QCarlaString fClientName; QCarlaString fSessionManagerName; //----------------------------------------------------------------------------------------------------------------- // Internal stuff (patchbay) QImage fExportImage; bool fPeaksCleared = true; bool fExternalPatchbay = false; QList fSelectedPlugins; int fCanvasWidth = 0; int fCanvasHeight = 0; int fMiniCanvasUpdateTimeout = 0; bool fWithCanvas; //----------------------------------------------------------------------------------------------------------------- // GUI stuff (disk) QFileSystemModel fDirModel; //----------------------------------------------------------------------------------------------------------------- // CarlaHostWindow* hostWindow, PrivateData(CarlaHostWindow* const hostWindow, const bool withCanvas) : fWithCanvas(withCanvas), fDirModel(hostWindow) { ui.setupUi(hostWindow); } }; //--------------------------------------------------------------------------------------------------------------------- // Host Window CarlaHostWindow::CarlaHostWindow(Host& h, const bool withCanvas, QWidget* const parent) : QMainWindow(parent), host(h), self(new PrivateData(this, withCanvas)) { gCarla.gui = this; static const char* const CARLA_CLIENT_NAME = getenv("CARLA_CLIENT_NAME"); static const char* const LADISH_APP_NAME = getenv("LADISH_APP_NAME"); static const char* const NSM_URL = getenv("NSM_URL"); //----------------------------------------------------------------------------------------------------------------- // Internal stuff // keep application signals alive self->fIdleTimerNull = startTimer(1000); if (host.isControl) { self->fClientName = "Carla-Control"; self->fSessionManagerName = "Control"; } else if (host.isPlugin) { self->fClientName = "Carla-Plugin"; self->fSessionManagerName = "Plugin"; } else if (LADISH_APP_NAME != nullptr) { self->fClientName = LADISH_APP_NAME; self->fSessionManagerName = "LADISH"; } else if (NSM_URL != nullptr && host.nsmOK) { self->fClientName = "Carla.tmp"; self->fSessionManagerName = "Non Session Manager TMP"; } else { self->fClientName = CARLA_CLIENT_NAME != nullptr ? CARLA_CLIENT_NAME : "Carla"; self->fSessionManagerName = ""; } //----------------------------------------------------------------------------------------------------------------- // Set up GUI (engine stopped) if (host.isPlugin || host.isControl) { self->ui.act_file_save->setVisible(false); self->ui.act_engine_start->setEnabled(false); self->ui.act_engine_start->setVisible(false); self->ui.act_engine_stop->setEnabled(false); self->ui.act_engine_stop->setVisible(false); self->ui.menu_Engine->setEnabled(false); self->ui.menu_Engine->setVisible(false); if (QAction* const action = self->ui.menu_Engine->menuAction()) action->setVisible(false); self->ui.tabWidget->removeTab(2); if (host.isControl) { self->ui.act_file_new->setVisible(false); self->ui.act_file_open->setVisible(false); self->ui.act_file_save_as->setVisible(false); self->ui.tabUtils->removeTab(0); } else { self->ui.act_file_save_as->setText(tr("Export as...")); if (! withCanvas) if (QTabBar* const tabBar = self->ui.tabWidget->tabBar()) tabBar->hide(); } } else { self->ui.act_engine_start->setEnabled(true); #ifdef CARLA_OS_WIN self->ui.tabWidget->removeTab(2); #endif } if (host.isControl) { self->ui.act_file_refresh->setEnabled(false); } else { self->ui.act_file_connect->setEnabled(false); self->ui.act_file_connect->setVisible(false); self->ui.act_file_refresh->setEnabled(false); self->ui.act_file_refresh->setVisible(false); } if (self->fSessionManagerName.isNotEmpty() && ! host.isPlugin) self->ui.act_file_new->setEnabled(false); self->ui.act_file_open->setEnabled(false); self->ui.act_file_save->setEnabled(false); self->ui.act_file_save_as->setEnabled(false); self->ui.act_engine_stop->setEnabled(false); self->ui.act_plugin_remove_all->setEnabled(false); self->ui.act_canvas_show_internal->setChecked(false); self->ui.act_canvas_show_internal->setVisible(false); self->ui.act_canvas_show_external->setChecked(false); self->ui.act_canvas_show_external->setVisible(false); self->ui.menu_PluginMacros->setEnabled(false); self->ui.menu_Canvas->setEnabled(false); QWidget* const dockWidgetTitleBar = new QWidget(this); self->ui.dockWidget->setTitleBarWidget(dockWidgetTitleBar); if (! withCanvas) { self->ui.act_canvas_show_internal->setVisible(false); self->ui.act_canvas_show_external->setVisible(false); self->ui.act_canvas_arrange->setVisible(false); self->ui.act_canvas_refresh->setVisible(false); self->ui.act_canvas_save_image->setVisible(false); self->ui.act_canvas_zoom_100->setVisible(false); self->ui.act_canvas_zoom_fit->setVisible(false); self->ui.act_canvas_zoom_in->setVisible(false); self->ui.act_canvas_zoom_out->setVisible(false); self->ui.act_settings_show_meters->setVisible(false); self->ui.act_settings_show_keyboard->setVisible(false); self->ui.menu_Canvas_Zoom->setEnabled(false); self->ui.menu_Canvas_Zoom->setVisible(false); if (QAction* const action = self->ui.menu_Canvas_Zoom->menuAction()) action->setVisible(false); self->ui.menu_Canvas->setEnabled(false); self->ui.menu_Canvas->setVisible(false); if (QAction* const action = self->ui.menu_Canvas->menuAction()) action->setVisible(false); self->ui.tw_miniCanvas->hide(); self->ui.tabWidget->removeTab(1); #ifdef CARLA_OS_WIN self->ui.tabWidget->tabBar().hide() #endif } //----------------------------------------------------------------------------------------------------------------- // Set up GUI (disk) const QString home(QDir::homePath()); self->fDirModel.setRootPath(home); if (const char* const* const exts = carla_get_supported_file_extensions()) { QStringList filters; const QString prefix("*."); for (uint i=0; exts[i] != nullptr; ++i) filters.append(prefix + exts[i]); self->fDirModel.setNameFilters(filters); } self->ui.fileTreeView->setModel(&self->fDirModel); self->ui.fileTreeView->setRootIndex(self->fDirModel.index(home)); self->ui.fileTreeView->setColumnHidden(1, true); self->ui.fileTreeView->setColumnHidden(2, true); self->ui.fileTreeView->setColumnHidden(3, true); self->ui.fileTreeView->setHeaderHidden(true); //----------------------------------------------------------------------------------------------------------------- // Set up GUI (transport) const QFontMetrics fontMetrics(self->ui.l_transport_bbt->fontMetrics()); int minValueWidth = fontMetricsHorizontalAdvance(fontMetrics, "000|00|0000"); int minLabelWidth = fontMetricsHorizontalAdvance(fontMetrics, self->ui.label_transport_frame->text()); int labelTimeWidth = fontMetricsHorizontalAdvance(fontMetrics, self->ui.label_transport_time->text()); int labelBBTWidth = fontMetricsHorizontalAdvance(fontMetrics, self->ui.label_transport_bbt->text()); if (minLabelWidth < labelTimeWidth) minLabelWidth = labelTimeWidth; if (minLabelWidth < labelBBTWidth) minLabelWidth = labelBBTWidth; self->ui.label_transport_frame->setMinimumWidth(minLabelWidth + 3); self->ui.label_transport_time->setMinimumWidth(minLabelWidth + 3); self->ui.label_transport_bbt->setMinimumWidth(minLabelWidth + 3); self->ui.l_transport_bbt->setMinimumWidth(minValueWidth + 3); self->ui.l_transport_frame->setMinimumWidth(minValueWidth + 3); self->ui.l_transport_time->setMinimumWidth(minValueWidth + 3); if (host.isPlugin) { self->ui.b_transport_play->setEnabled(false); self->ui.b_transport_stop->setEnabled(false); self->ui.b_transport_backwards->setEnabled(false); self->ui.b_transport_forwards->setEnabled(false); self->ui.group_transport_controls->setEnabled(false); self->ui.group_transport_controls->setVisible(false); self->ui.cb_transport_link->setEnabled(false); self->ui.cb_transport_link->setVisible(false); self->ui.cb_transport_jack->setEnabled(false); self->ui.cb_transport_jack->setVisible(false); self->ui.dsb_transport_bpm->setEnabled(false); self->ui.dsb_transport_bpm->setReadOnly(true); } self->ui.w_transport->setEnabled(false); //----------------------------------------------------------------------------------------------------------------- // Set up GUI (rack) // self->ui.listWidget->setHostAndParent(self->host, self); if (QScrollBar* const sb = self->ui.listWidget->verticalScrollBar()) { self->ui.rackScrollBar->setMinimum(sb->minimum()); self->ui.rackScrollBar->setMaximum(sb->maximum()); self->ui.rackScrollBar->setValue(sb->value()); /* sb->rangeChanged.connect(self->ui.rackScrollBar.setRange); sb->valueChanged.connect(self->ui.rackScrollBar.setValue); self->ui.rackScrollBar->rangeChanged.connect(sb.setRange); self->ui.rackScrollBar->valueChanged.connect(sb.setValue); */ } /* updateStyle(); */ self->ui.rack->setStyleSheet(" \ CarlaRackList#CarlaRackList { \ background-color: black; \ } \ "); //----------------------------------------------------------------------------------------------------------------- // Set up GUI (patchbay) /* self->ui.peak_in->setChannelCount(2); self->ui.peak_in->setMeterColor(DigitalPeakMeter.COLOR_BLUE); self->ui.peak_in->setMeterOrientation(DigitalPeakMeter.VERTICAL); */ self->ui.peak_in->setFixedWidth(25); /* self->ui.peak_out->setChannelCount(2); self->ui.peak_out->setMeterColor(DigitalPeakMeter.COLOR_GREEN); self->ui.peak_out->setMeterOrientation(DigitalPeakMeter.VERTICAL); */ self->ui.peak_out->setFixedWidth(25); /* self->ui.scrollArea = PixmapKeyboardHArea(self->ui.patchbay); self->ui.keyboard = self->ui.scrollArea.keyboard; self->ui.patchbay.layout().addWidget(self->ui.scrollArea, 1, 0, 1, 0); self->ui.scrollArea->setEnabled(false); self->ui.miniCanvasPreview->setRealParent(self); */ if (QTabBar* const tabBar = self->ui.tw_miniCanvas->tabBar()) tabBar->hide(); //----------------------------------------------------------------------------------------------------------------- // Set up GUI (special stuff for Mac OS) #ifdef CARLA_OS_MAC self->ui.act_file_quit->setMenuRole(QAction::QuitRole); self->ui.act_settings_configure->setMenuRole(QAction::PreferencesRole); self->ui.act_help_about->setMenuRole(QAction::AboutRole); self->ui.act_help_about_qt->setMenuRole(QAction::AboutQtRole); self->ui.menu_Settings->setTitle("Panels"); if (QAction* const action = self->ui.menu_Help.menuAction()) action->setVisible(false); #endif //----------------------------------------------------------------------------------------------------------------- // Load Settings loadSettings(true); //----------------------------------------------------------------------------------------------------------------- // Set-up Canvas /* if (withCanvas) { self->scene = patchcanvas.PatchScene(self, self->ui.graphicsView); self->ui.graphicsView->setScene(self->scene); if (self->fSavedSettings[CARLA_KEY_CANVAS_USE_OPENGL]) { self->ui.glView = QGLWidget(self); self->ui.graphicsView.setViewport(self->ui.glView); } setupCanvas(); } */ //----------------------------------------------------------------------------------------------------------------- // Connect actions to functions // TODO connect(self->ui.b_transport_play, SIGNAL(clicked(bool)), SLOT(slot_transportPlayPause(bool))); connect(self->ui.b_transport_stop, SIGNAL(clicked()), SLOT(slot_transportStop())); connect(self->ui.b_transport_backwards, SIGNAL(clicked()), SLOT(slot_transportBackwards())); connect(self->ui.b_transport_forwards, SIGNAL(clicked()), SLOT(slot_transportForwards())); connect(self->ui.dsb_transport_bpm, SIGNAL(valueChanged(qreal)), SLOT(slot_transportBpmChanged(qreal))); connect(self->ui.cb_transport_jack, SIGNAL(clicked(bool)), SLOT(slot_transportJackEnabled(bool))); connect(self->ui.cb_transport_link, SIGNAL(clicked(bool)), SLOT(slot_transportLinkEnabled(bool))); connect(self->ui.b_xruns, SIGNAL(clicked()), SLOT(slot_xrunClear())); connect(&host, SIGNAL(EngineStartedCallback(uint, int, int, int, float, QString)), SLOT(slot_handleEngineStartedCallback(uint, int, int, int, float, QString))); connect(&host, SIGNAL(EngineStoppedCallback()), SLOT(slot_handleEngineStoppedCallback())); //----------------------------------------------------------------------------------------------------------------- // Final setup self->ui.text_logs->clear(); setProperWindowTitle(); // Disable non-supported features const char* const* const features = carla_get_supported_features(); if (! stringArrayContainsString(features, "link")) { self->ui.cb_transport_link->setEnabled(false); self->ui.cb_transport_link->setVisible(false); } if (! stringArrayContainsString(features, "juce")) { self->ui.act_help_about_juce->setEnabled(false); self->ui.act_help_about_juce->setVisible(false); } // Plugin needs to have timers always running so it receives messages if (host.isPlugin || host.isRemote) startTimers(); // Qt needs this so it properly creates & resizes the canvas self->ui.tabWidget->blockSignals(true); self->ui.tabWidget->setCurrentIndex(1); self->ui.tabWidget->setCurrentIndex(0); self->ui.tabWidget->blockSignals(false); // Start in patchbay tab if using forced patchbay mode if (host.processModeForced && host.processMode == ENGINE_PROCESS_MODE_PATCHBAY) self->ui.tabWidget->setCurrentIndex(1); // Load initial project file if set if (! (host.isControl || host.isPlugin)) { /* projectFile = getInitialProjectFile(QApplication.instance()); if (projectFile) loadProjectLater(projectFile); */ } // For NSM we wait for the open message if (NSM_URL != nullptr && host.nsmOK) { carla_nsm_ready(NSM_CALLBACK_INIT); return; } if (! host.isControl) QTimer::singleShot(0, this, SLOT(slot_engineStart())); } CarlaHostWindow::~CarlaHostWindow() { delete self; } //--------------------------------------------------------------------------------------------------------------------- // Setup #if 0 def compactPlugin(self, pluginId): if pluginId > self->fPluginCount: return pitem = self->fPluginList[pluginId] if pitem is None: return pitem.recreateWidget(true) def changePluginColor(self, pluginId, color, colorStr): if pluginId > self->fPluginCount: return pitem = self->fPluginList[pluginId] if pitem is None: return self->host.set_custom_data(pluginId, CUSTOM_DATA_TYPE_PROPERTY, "CarlaColor", colorStr) pitem.recreateWidget(newColor = color) def changePluginSkin(self, pluginId, skin): if pluginId > self->fPluginCount: return pitem = self->fPluginList[pluginId] if pitem is None: return self->host.set_custom_data(pluginId, CUSTOM_DATA_TYPE_PROPERTY, "CarlaSkin", skin) if skin not in ("default","rncbc","presets","mpresets"): pitem.recreateWidget(newSkin = skin, newColor = (255,255,255)) else: pitem.recreateWidget(newSkin = skin) def switchPlugins(self, pluginIdA, pluginIdB): if pluginIdA == pluginIdB: return if pluginIdA < 0 or pluginIdB < 0: return if pluginIdA >= self->fPluginCount or pluginIdB >= self->fPluginCount: return self->host.switch_plugins(pluginIdA, pluginIdB) itemA = self->fPluginList[pluginIdA] compactA = itemA.isCompacted() guiShownA = itemA.isGuiShown() itemB = self->fPluginList[pluginIdB] compactB = itemB.isCompacted() guiShownB = itemB.isGuiShown() itemA.setPluginId(pluginIdA) itemA.recreateWidget2(compactB, guiShownB) itemB.setPluginId(pluginIdB) itemB.recreateWidget2(compactA, guiShownA) if self->fWithCanvas: self->slot_canvasRefresh() #endif void CarlaHostWindow::setLoadRDFsNeeded() noexcept { self->fLadspaRdfNeedsUpdate = true; } void CarlaHostWindow::setProperWindowTitle() { QString title(self->fClientName); /* if (self->fProjectFilename.isNotEmpty() && ! host.nsmOK) title += QString(" - %s").arg(os.path.basename(self->fProjectFilename)); */ if (self->fSessionManagerName.isNotEmpty()) title += QString(" (%s)").arg(self->fSessionManagerName); setWindowTitle(title); } void CarlaHostWindow::updateBufferSize(const uint newBufferSize) { if (self->fBufferSize == newBufferSize) return; self->fBufferSize = newBufferSize; self->ui.cb_buffer_size->clear(); self->ui.cb_buffer_size->addItem(QString("%1").arg(newBufferSize)); self->ui.cb_buffer_size->setCurrentIndex(0); } void CarlaHostWindow::updateSampleRate(const double newSampleRate) { if (carla_isEqual(self->fSampleRate, newSampleRate)) return; self->fSampleRate = newSampleRate; self->ui.cb_sample_rate->clear(); self->ui.cb_sample_rate->addItem(QString("%1").arg(newSampleRate)); self->ui.cb_sample_rate->setCurrentIndex(0); refreshTransport(true); } //--------------------------------------------------------------------------------------------------------------------- // Engine (menu actions) void CarlaHostWindow::slot_engineStart() { /* audioDriver = setEngineSettings(self->host) */ const char* const audioDriver = "JACK"; const bool firstInit = self->fFirstEngineInit; self->fFirstEngineInit = false; self->ui.text_logs->appendPlainText("======= Starting engine ======="); if (carla_engine_init(audioDriver, self->fClientName.toUtf8())) { if (firstInit && ! (host.isControl or host.isPlugin)) { QSafeSettings settings; const double lastBpm = settings.valueDouble("LastBPM", 120.0); if (lastBpm >= 20.0) carla_transport_bpm(lastBpm); } return; } else if (firstInit) { self->ui.text_logs->appendPlainText("Failed to start engine on first try, ignored"); return; } const QCarlaString audioError(carla_get_last_error()); if (audioError.isNotEmpty()) { QMessageBox::critical(this, tr("Error"), tr("Could not connect to Audio backend '%1', possible reasons:\n%2").arg(audioDriver).arg(audioError)); } else { QMessageBox::critical(this, tr("Error"), tr("Could not connect to Audio backend '%1'").arg(audioDriver)); } } bool CarlaHostWindow::slot_engineStop(const bool forced) { self->ui.text_logs->appendPlainText("======= Stopping engine ======="); if (self->fPluginCount == 0) { engineStopFinal(); return true; } if (! forced) { const QMessageBox::StandardButton ask = QMessageBox::question(this, tr("Warning"), tr("There are still some plugins loaded, you need to remove them to stop the engine.\n" "Do you want to do this now?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (ask != QMessageBox::Yes) return false; } return slot_engineStopTryAgain(); } void CarlaHostWindow::slot_engineConfig() { /* dialog = RuntimeDriverSettingsW(self->fParentOrSelf, self->host) if not dialog.exec_(): return audioDevice, bufferSize, sampleRate = dialog.getValues() if self->host.is_engine_running(): self->host.set_engine_buffer_size_and_sample_rate(bufferSize, sampleRate) else: self->host.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice) self->host.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, bufferSize, "") self->host.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, sampleRate, "") */ } bool CarlaHostWindow::slot_engineStopTryAgain() { if (carla_is_engine_running() && ! carla_set_engine_about_to_close()) { QTimer::singleShot(0, this, SLOT(slot_engineStopTryAgain())); return false; } engineStopFinal(); return true; } void CarlaHostWindow::engineStopFinal() { killTimers(); if (carla_is_engine_running()) { if (self->fCustomStopAction == CUSTOM_ACTION_PROJECT_LOAD) { /* removeAllPlugins(); */ } else if (self->fPluginCount != 0) { self->fCurrentlyRemovingAllPlugins = true; /* projectLoadingStarted(); */ } if (! carla_remove_all_plugins()) { self->ui.text_logs->appendPlainText("Failed to remove all plugins, error was:"); self->ui.text_logs->appendPlainText(carla_get_last_error()); } if (! carla_engine_close()) { self->ui.text_logs->appendPlainText("Failed to stop engine, error was:"); self->ui.text_logs->appendPlainText(carla_get_last_error()); } } if (self->fCustomStopAction == CUSTOM_ACTION_APP_CLOSE) { close(); } else if (self->fCustomStopAction == CUSTOM_ACTION_PROJECT_LOAD) { slot_engineStart(); /* loadProjectNow(); */ carla_nsm_ready(NSM_CALLBACK_OPEN); } self->fCustomStopAction = CUSTOM_ACTION_NONE; } //--------------------------------------------------------------------------------------------------------------------- // Engine (host callbacks) void CarlaHostWindow::slot_handleEngineStartedCallback(uint pluginCount, int processMode, int transportMode, int bufferSize, float sampleRate, QString driverName) { self->ui.menu_PluginMacros->setEnabled(true); self->ui.menu_Canvas->setEnabled(true); self->ui.w_transport->setEnabled(true); self->ui.act_canvas_show_internal->blockSignals(true); self->ui.act_canvas_show_external->blockSignals(true); if (processMode == ENGINE_PROCESS_MODE_PATCHBAY) // and not self->host.isPlugin: { self->ui.act_canvas_show_internal->setChecked(true); self->ui.act_canvas_show_internal->setVisible(true); self->ui.act_canvas_show_external->setChecked(false); self->ui.act_canvas_show_external->setVisible(true); self->fExternalPatchbay = false; } else { self->ui.act_canvas_show_internal->setChecked(false); self->ui.act_canvas_show_internal->setVisible(false); self->ui.act_canvas_show_external->setChecked(true); self->ui.act_canvas_show_external->setVisible(false); self->fExternalPatchbay = true; } self->ui.act_canvas_show_internal->blockSignals(false); self->ui.act_canvas_show_external->blockSignals(false); if (! (host.isControl or host.isPlugin)) { /* const bool canSave = (self->fProjectFilename.isNotEmpty() and os.path.exists(self->fProjectFilename)) or not self->fSessionManagerName; self->ui.act_file_save->setEnabled(canSave); */ self->ui.act_engine_start->setEnabled(false); self->ui.act_engine_stop->setEnabled(true); } /* if (! host.isPlugin) enableTransport(transportMode != ENGINE_TRANSPORT_MODE_DISABLED); */ if (host.isPlugin || self->fSessionManagerName.isEmpty()) { self->ui.act_file_open->setEnabled(true); self->ui.act_file_save_as->setEnabled(true); } self->ui.cb_transport_jack->setChecked(transportMode == ENGINE_TRANSPORT_MODE_JACK); self->ui.cb_transport_jack->setEnabled(driverName == "JACK" and processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS); if (self->ui.cb_transport_link->isEnabled()) self->ui.cb_transport_link->setChecked(host.transportExtra.contains(":link:")); updateBufferSize(bufferSize); updateSampleRate(int(sampleRate)); /* refreshRuntimeInfo(0.0, 0); */ startTimers(); self->ui.text_logs->appendPlainText("======= Engine started ========"); self->ui.text_logs->appendPlainText("Carla engine started, details:"); self->ui.text_logs->appendPlainText(QString(" Driver name: %1").arg(driverName)); self->ui.text_logs->appendPlainText(QString(" Sample rate: %1").arg(int(sampleRate))); self->ui.text_logs->appendPlainText(QString(" Process mode: %1").arg(EngineProcessMode2Str((EngineProcessMode)processMode))); } void CarlaHostWindow::slot_handleEngineStoppedCallback() { self->ui.text_logs->appendPlainText("======= Engine stopped ========"); /* patchcanvas.clear(); */ killTimers(); // just in case /* removeAllPlugins(); refreshRuntimeInfo(0.0, 0); */ self->ui.menu_PluginMacros->setEnabled(false); self->ui.menu_Canvas->setEnabled(false); self->ui.w_transport->setEnabled(false); if (! (host.isControl || host.isPlugin)) { self->ui.act_file_save->setEnabled(false); self->ui.act_engine_start->setEnabled(true); self->ui.act_engine_stop->setEnabled(false); } if (host.isPlugin || self->fSessionManagerName.isEmpty()) { self->ui.act_file_open->setEnabled(false); self->ui.act_file_save_as->setEnabled(false); } } //--------------------------------------------------------------------------------------------------------------------- // Settings void CarlaHostWindow::saveSettings() { QSafeSettings settings; settings.setValue("Geometry", saveGeometry()); settings.setValue("ShowToolbar", self->ui.toolBar->isEnabled()); if (! host.isControl) settings.setValue("ShowSidePanel", self->ui.dockWidget->isEnabled()); QStringList diskFolders; /* for i in range(self->ui.cb_disk.count()): diskFolders.append(self->ui.cb_disk->itemData(i)) */ settings.setValue("DiskFolders", diskFolders); settings.setValue("LastBPM", self->fLastTransportBPM); settings.setValue("ShowMeters", self->ui.act_settings_show_meters->isChecked()); settings.setValue("ShowKeyboard", self->ui.act_settings_show_keyboard->isChecked()); settings.setValue("HorizontalScrollBarValue", self->ui.graphicsView->horizontalScrollBar()->value()); settings.setValue("VerticalScrollBarValue", self->ui.graphicsView->verticalScrollBar()->value()); settings.setValue(CARLA_KEY_ENGINE_TRANSPORT_MODE, host.transportMode); settings.setValue(CARLA_KEY_ENGINE_TRANSPORT_EXTRA, host.transportExtra); } void CarlaHostWindow::loadSettings(bool firstTime) { const QSafeSettings settings; if (firstTime) { const QByteArray geometry(settings.valueByteArray("Geometry")); if (! geometry.isNull()) restoreGeometry(geometry); const bool showToolbar = settings.valueBool("ShowToolbar", true); self->ui.act_settings_show_toolbar->setChecked(showToolbar); self->ui.toolBar->setEnabled(showToolbar); self->ui.toolBar->setVisible(showToolbar); // if settings.contains("SplitterState"): //self->ui.splitter.restoreState(settings.value("SplitterState", b"")) //else: //self->ui.splitter.setSizes([210, 99999]) const bool showSidePanel = settings.valueBool("ShowSidePanel", true) && ! host.isControl; self->ui.act_settings_show_side_panel->setChecked(showSidePanel); slot_showSidePanel(showSidePanel); QStringList diskFolders; diskFolders.append(QDir::homePath()); diskFolders = settings.valueStringList("DiskFolders", diskFolders); self->ui.cb_disk->setItemData(0, QDir::homePath()); for (const auto& folder : diskFolders) { /* if i == 0: continue; folder = diskFolders[i]; self->ui.cb_disk->addItem(os.path.basename(folder), folder); */ } //if MACOS and not settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, true, bool): // self->setUnifiedTitleAndToolBarOnMac(true) const bool showMeters = settings.valueBool("ShowMeters", true); self->ui.act_settings_show_meters->setChecked(showMeters); self->ui.peak_in->setVisible(showMeters); self->ui.peak_out->setVisible(showMeters); const bool showKeyboard = settings.valueBool("ShowKeyboard", true); self->ui.act_settings_show_keyboard->setChecked(showKeyboard); /* self->ui.scrollArea->setVisible(showKeyboard); */ const QSafeSettings settingsDBf("falkTX", "CarlaDatabase2"); self->fFavoritePlugins = settingsDBf.valueStringList("PluginDatabase/Favorites"); /* QTimer::singleShot(100, slot_restoreCanvasScrollbarValues); */ } // TODO - complete this self->fSavedSettings._CARLA_KEY_MAIN_CONFIRM_EXIT = settings.valueBool(CARLA_KEY_MAIN_CONFIRM_EXIT, CARLA_DEFAULT_MAIN_CONFIRM_EXIT); self->fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL = settings.valueUInt(CARLA_KEY_MAIN_REFRESH_INTERVAL, CARLA_DEFAULT_MAIN_REFRESH_INTERVAL); self->fSavedSettings._CARLA_KEY_CANVAS_FANCY_EYE_CANDY = settings.valueBool(CARLA_KEY_CANVAS_FANCY_EYE_CANDY, CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY); /* { CARLA_KEY_MAIN_PROJECT_FOLDER: settings.value(CARLA_KEY_MAIN_PROJECT_FOLDER, CARLA_DEFAULT_MAIN_PROJECT_FOLDER, str), CARLA_KEY_MAIN_EXPERIMENTAL: settings.value(CARLA_KEY_MAIN_EXPERIMENTAL, CARLA_DEFAULT_MAIN_EXPERIMENTAL, bool), CARLA_KEY_CANVAS_THEME: settings.value(CARLA_KEY_CANVAS_THEME, CARLA_DEFAULT_CANVAS_THEME, str), CARLA_KEY_CANVAS_SIZE: settings.value(CARLA_KEY_CANVAS_SIZE, CARLA_DEFAULT_CANVAS_SIZE, str), CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS: settings.value(CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS, CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS, bool), CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS: settings.value(CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS, CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS, bool), CARLA_KEY_CANVAS_USE_BEZIER_LINES: settings.value(CARLA_KEY_CANVAS_USE_BEZIER_LINES, CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES, bool), CARLA_KEY_CANVAS_EYE_CANDY: settings.value(CARLA_KEY_CANVAS_EYE_CANDY, CARLA_DEFAULT_CANVAS_EYE_CANDY, bool), CARLA_KEY_CANVAS_USE_OPENGL: settings.value(CARLA_KEY_CANVAS_USE_OPENGL, CARLA_DEFAULT_CANVAS_USE_OPENGL, bool), CARLA_KEY_CANVAS_ANTIALIASING: settings.value(CARLA_KEY_CANVAS_ANTIALIASING, CARLA_DEFAULT_CANVAS_ANTIALIASING, int), CARLA_KEY_CANVAS_HQ_ANTIALIASING: settings.value(CARLA_KEY_CANVAS_HQ_ANTIALIASING, CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING, bool), CARLA_KEY_CANVAS_FULL_REPAINTS: settings.value(CARLA_KEY_CANVAS_FULL_REPAINTS, CARLA_DEFAULT_CANVAS_FULL_REPAINTS, bool), CARLA_KEY_CANVAS_INLINE_DISPLAYS: settings.value(CARLA_KEY_CANVAS_INLINE_DISPLAYS, CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS, bool), CARLA_KEY_CUSTOM_PAINTING: (settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, true, bool) and settings.value(CARLA_KEY_MAIN_PRO_THEME_COLOR, "Black", str).lower() == "black"), } */ const QSafeSettings settings2("falkTX", "Carla2"); if (host.experimental) { const bool visible = settings2.valueBool(CARLA_KEY_EXPERIMENTAL_JACK_APPS, CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS); self->ui.act_plugin_add_jack->setVisible(visible); } else { self->ui.act_plugin_add_jack->setVisible(false); } self->fMiniCanvasUpdateTimeout = self->fSavedSettings._CARLA_KEY_CANVAS_FANCY_EYE_CANDY ? 1000 : 0; /* setEngineSettings(host); */ restartTimersIfNeeded(); } //--------------------------------------------------------------------------------------------------------------------- // Settings (menu actions) void CarlaHostWindow::slot_showSidePanel(const bool yesNo) { self->ui.dockWidget->setEnabled(yesNo); self->ui.dockWidget->setVisible(yesNo); } void CarlaHostWindow::slot_showToolbar(const bool yesNo) { self->ui.toolBar->setEnabled(yesNo); self->ui.toolBar->setVisible(yesNo); } void CarlaHostWindow::slot_showCanvasMeters(const bool yesNo) { self->ui.peak_in->setVisible(yesNo); self->ui.peak_out->setVisible(yesNo); /* QTimer::singleShot(0, slot_miniCanvasCheckAll); */ } void CarlaHostWindow::slot_showCanvasKeyboard(const bool yesNo) { /* self->ui.scrollArea->setVisible(yesNo); QTimer::singleShot(0, slot_miniCanvasCheckAll); */ } void CarlaHostWindow::slot_configureCarla() { /* CarlaSettingsW dialog(self->fParentOrSelf, self->host, true, hasGL); if not dialog.exec_(): return */ loadSettings(false); /* patchcanvas.clear() setupCanvas(); slot_miniCanvasCheckAll(); */ if (host.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK and host.isPlugin) pass(); else if (carla_is_engine_running()) carla_patchbay_refresh(self->fExternalPatchbay); } //--------------------------------------------------------------------------------------------------------------------- // Transport void CarlaHostWindow::refreshTransport(const bool forced) { if (not self->ui.l_transport_time->isVisible()) return; if (carla_isZero(self->fSampleRate) or ! carla_is_engine_running()) return; const CarlaTransportInfo* const timeInfo = carla_get_transport_info(); const bool playing = timeInfo->playing; const uint64_t frame = timeInfo->frame; const double bpm = timeInfo->bpm; if (playing != self->fLastTransportState || forced) { if (playing) { const QIcon icon(":/16x16/media-playback-pause.svgz"); self->ui.b_transport_play->setChecked(true); self->ui.b_transport_play->setIcon(icon); // self->ui.b_transport_play->setText(tr("&Pause")); } else { const QIcon icon(":/16x16/media-playback-start.svgz"); self->ui.b_transport_play->setChecked(false); self->ui.b_transport_play->setIcon(icon); // self->ui.b_play->setText(tr("&Play")); } self->fLastTransportState = playing; } if (frame != self->fLastTransportFrame || forced) { self->fLastTransportFrame = frame; const uint32_t time = frame / self->fSampleRate; const uint32_t secs = time % 60; const uint32_t mins = (time / 60) % 60; const uint32_t hrs = (time / 3600) % 60; self->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'))); const uint32_t frame1 = frame % 1000; const uint32_t frame2 = (frame / 1000) % 1000; const uint32_t frame3 = (frame / 1000000) % 1000; self->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'))); const int32_t bar = timeInfo->bar; const int32_t beat = timeInfo->beat; const int32_t tick = timeInfo->tick; self->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'))); } if (carla_isNotEqual(bpm, self->fLastTransportBPM) || forced) { self->fLastTransportBPM = bpm; if (bpm > 0.0) { self->ui.dsb_transport_bpm->blockSignals(true); self->ui.dsb_transport_bpm->setValue(bpm); self->ui.dsb_transport_bpm->blockSignals(false); self->ui.dsb_transport_bpm->setStyleSheet(""); } else { self->ui.dsb_transport_bpm->setStyleSheet("QDoubleSpinBox { color: palette(mid); }"); } } } //--------------------------------------------------------------------------------------------------------------------- // Transport (menu actions) void CarlaHostWindow::slot_transportPlayPause(const bool toggled) { if (host.isPlugin || ! carla_is_engine_running()) return; if (toggled) carla_transport_play(); else carla_transport_pause(); refreshTransport(); } void CarlaHostWindow::slot_transportStop() { if (host.isPlugin || ! carla_is_engine_running()) return; carla_transport_pause(); carla_transport_relocate(0); refreshTransport(); } void CarlaHostWindow::slot_transportBackwards() { if (host.isPlugin || ! carla_is_engine_running()) return; int64_t newFrame = carla_get_current_transport_frame() - 100000; if (newFrame < 0) newFrame = 0; carla_transport_relocate(newFrame); } void CarlaHostWindow::slot_transportBpmChanged(const qreal newValue) { carla_transport_bpm(newValue); } void CarlaHostWindow::slot_transportForwards() { if (carla_isZero(self->fSampleRate) || host.isPlugin || ! carla_is_engine_running()) return; const int64_t newFrame = carla_get_current_transport_frame() + int(self->fSampleRate*2.5); carla_transport_relocate(newFrame); } void CarlaHostWindow::slot_transportJackEnabled(const bool clicked) { if (! carla_is_engine_running()) return; host.transportMode = clicked ? ENGINE_TRANSPORT_MODE_JACK : ENGINE_TRANSPORT_MODE_INTERNAL; carla_set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, host.transportMode, host.transportExtra.toUtf8()); } void CarlaHostWindow::slot_transportLinkEnabled(const bool clicked) { if (! carla_is_engine_running()) return; const char* const extra = clicked ? ":link:" : ""; host.transportExtra = extra; carla_set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, host.transportMode, host.transportExtra.toUtf8()); } //--------------------------------------------------------------------------------------------------------------------- // Other void CarlaHostWindow::slot_xrunClear() { carla_clear_engine_xruns(); } //--------------------------------------------------------------------------------------------------------------------- // Timers void CarlaHostWindow::startTimers() { if (self->fIdleTimerFast == 0) self->fIdleTimerFast = startTimer(self->fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL); if (self->fIdleTimerSlow == 0) self->fIdleTimerSlow = startTimer(self->fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL*4); } void CarlaHostWindow::restartTimersIfNeeded() { if (self->fIdleTimerFast != 0) { killTimer(self->fIdleTimerFast); self->fIdleTimerFast = startTimer(self->fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL); } if (self->fIdleTimerSlow != 0) { killTimer(self->fIdleTimerSlow); self->fIdleTimerSlow = startTimer(self->fSavedSettings._CARLA_KEY_MAIN_REFRESH_INTERVAL*4);; } } void CarlaHostWindow::killTimers() { if (self->fIdleTimerFast != 0) { killTimer(self->fIdleTimerFast); self->fIdleTimerFast = 0; } if (self->fIdleTimerSlow != 0) { killTimer(self->fIdleTimerSlow); self->fIdleTimerSlow = 0; } } //--------------------------------------------------------------------------------------------------------------------- // timer event void CarlaHostWindow::refreshRuntimeInfo(const float load, const int xruns) { const QString txt1(xruns >= 0 ? QString("%1").arg(xruns) : QString("--")); const QString txt2(xruns == 1 ? "" : "s"); self->ui.b_xruns->setText(QString("%1 Xrun%2").arg(txt1).arg(txt2)); self->ui.pb_dsp_load->setValue(int(load)); } void CarlaHostWindow::getAndRefreshRuntimeInfo() { if (! self->ui.pb_dsp_load->isVisible()) return; if (! carla_is_engine_running()) return; const CarlaRuntimeEngineInfo* const info = carla_get_runtime_engine_info(); refreshRuntimeInfo(info->load, info->xruns); } void CarlaHostWindow::idleFast() { carla_engine_idle(); refreshTransport(); if (self->fPluginCount == 0 || self->fCurrentlyRemovingAllPlugins) return; for (auto& pitem : self->fPluginList) { if (pitem == nullptr) break; /* pitem->getWidget().idleFast(); */ } for (uint pluginId : self->fSelectedPlugins) { self->fPeaksCleared = false; if (self->ui.peak_in->isVisible()) { /* self->ui.peak_in->displayMeter(1, carla_get_input_peak_value(pluginId, true)) self->ui.peak_in->displayMeter(2, carla_get_input_peak_value(pluginId, false)) */ } if (self->ui.peak_out->isVisible()) { /* self->ui.peak_out->displayMeter(1, carla_get_output_peak_value(pluginId, true)) self->ui.peak_out->displayMeter(2, carla_get_output_peak_value(pluginId, false)) */ } return; } if (self->fPeaksCleared) return; self->fPeaksCleared = true; /* self->ui.peak_in->displayMeter(1, 0.0, true); self->ui.peak_in->displayMeter(2, 0.0, true); self->ui.peak_out->displayMeter(1, 0.0, true); self->ui.peak_out->displayMeter(2, 0.0, true); */ } void CarlaHostWindow::idleSlow() { getAndRefreshRuntimeInfo(); if (self->fPluginCount == 0 || self->fCurrentlyRemovingAllPlugins) return; for (auto& pitem : self->fPluginList) { if (pitem == nullptr) break; /* pitem->getWidget().idleSlow(); */ } } void CarlaHostWindow::timerEvent(QTimerEvent* const event) { if (event->timerId() == self->fIdleTimerFast) idleFast(); else if (event->timerId() == self->fIdleTimerSlow) idleSlow(); QMainWindow::timerEvent(event); } //--------------------------------------------------------------------------------------------------------------------- // color/style change event void CarlaHostWindow::changeEvent(QEvent* const event) { switch (event->type()) { case QEvent::PaletteChange: case QEvent::StyleChange: updateStyle(); break; default: break; } QWidget::changeEvent(event); } void CarlaHostWindow::updateStyle() { // Rack padding images setup QImage rack_imgL(":/bitmaps/rack_padding_left.png"); QImage rack_imgR(":/bitmaps/rack_padding_right.png"); const qreal min_value = 0.07; #if QT_VERSION >= 0x50600 const qreal value_fix = 1.0/(1.0-rack_imgL.scaled(1, 1, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).pixelColor(0,0).blackF()); #else const qreal value_fix = 1.5; #endif const QColor bg_color = self->ui.rack->palette().window().color(); const qreal bg_value = 1.0 - bg_color.blackF(); QColor pad_color; if (carla_isNotZero(bg_value) && bg_value < min_value) pad_color = bg_color.lighter(100*min_value/bg_value*value_fix); else pad_color = QColor::fromHsvF(0.0, 0.0, min_value*value_fix); QPainter painter; QRect fillRect(rack_imgL.rect().adjusted(-1,-1,1,1)); painter.begin(&rack_imgL); painter.setCompositionMode(QPainter::CompositionMode_Multiply); painter.setBrush(pad_color); painter.drawRect(fillRect); painter.end(); const QPixmap rack_pixmapL(QPixmap::fromImage(rack_imgL)); QPalette imgL_palette; //(self->ui.pad_left->palette()); imgL_palette.setBrush(QPalette::Window, QBrush(rack_pixmapL)); self->ui.pad_left->setPalette(imgL_palette); self->ui.pad_left->setAutoFillBackground(true); painter.begin(&rack_imgR); painter.setCompositionMode(QPainter::CompositionMode_Multiply); painter.setBrush(pad_color); painter.drawRect(fillRect); painter.end(); const QPixmap rack_pixmapR(QPixmap::fromImage(rack_imgR)); QPalette imgR_palette; //(self->ui.pad_right->palette()); imgR_palette.setBrush(QPalette::Window, QBrush(rack_pixmapR)); self->ui.pad_right->setPalette(imgR_palette); self->ui.pad_right->setAutoFillBackground(true); } //--------------------------------------------------------------------------------------------------------------------- // close event bool CarlaHostWindow::shouldIgnoreClose() { if (host.isControl || host.isPlugin) return false; if (self->fCustomStopAction == CUSTOM_ACTION_APP_CLOSE) return false; if (self->fSavedSettings._CARLA_KEY_MAIN_CONFIRM_EXIT) return QMessageBox::question(this, tr("Quit"), tr("Are you sure you want to quit Carla?"), QMessageBox::Yes|QMessageBox::No) == QMessageBox::No; return false; } void CarlaHostWindow::closeEvent(QCloseEvent* const event) { if (shouldIgnoreClose()) { event->ignore(); return; } #ifdef CARLA_OS_MAC if (self->fMacClosingHelper && ! (host.isControl || host.isPlugin)) { self->fCustomStopAction = CUSTOM_ACTION_APP_CLOSE; self->fMacClosingHelper = false; event->ignore(); for i in reversed(range(self->fPluginCount)): carla_show_custom_ui(i, false); QTimer::singleShot(100, SIGNAL(close())); return; } #endif killTimers(); saveSettings(); if (carla_is_engine_running() && ! (host.isControl or host.isPlugin)) { if (! slot_engineStop(true)) { self->fCustomStopAction = CUSTOM_ACTION_APP_CLOSE; event->ignore(); return; } } QMainWindow::closeEvent(event); } //--------------------------------------------------------------------------------------------------------------------- // Engine callback void _engineCallback(void* const ptr, EngineCallbackOpcode action, uint pluginId, int value1, int value2, int value3, float valuef, const char* const valueStr) { /* carla_stdout("_engineCallback(%p, %i:%s, %u, %i, %i, %i, %f, %s)", ptr, action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valuef, valueStr); */ Host* const host = (Host*)(ptr); CARLA_SAFE_ASSERT_RETURN(host != nullptr,); switch (action) { case ENGINE_CALLBACK_ENGINE_STARTED: host->processMode = static_cast(value1); host->transportMode = static_cast(value2); break; case ENGINE_CALLBACK_PROCESS_MODE_CHANGED: host->processMode = static_cast(value1); break; case ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED: host->transportMode = static_cast(value1); host->transportExtra = valueStr; break; default: break; } // TODO switch (action) { case ENGINE_CALLBACK_ENGINE_STARTED: emit host->EngineStartedCallback(pluginId, value1, value2, value3, valuef, valueStr); break; case ENGINE_CALLBACK_ENGINE_STOPPED: emit host->EngineStoppedCallback(); break; // FIXME default: break; } } //--------------------------------------------------------------------------------------------------------------------- // File callback static const char* _fileCallback(void*, const FileCallbackOpcode action, const bool isDir, const char* const title, const char* const filter) { QString ret; const QFileDialog::Options options = QFileDialog::Options(isDir ? QFileDialog::ShowDirsOnly : 0x0); switch (action) { case FILE_CALLBACK_DEBUG: break; case FILE_CALLBACK_OPEN: ret = QFileDialog::getOpenFileName(gCarla.gui, title, "", filter, nullptr, options); break; case FILE_CALLBACK_SAVE: ret = QFileDialog::getSaveFileName(gCarla.gui, title, "", filter, nullptr, options); break; } if (ret.isEmpty()) return nullptr; static const char* fileRet = nullptr; if (fileRet != nullptr) delete[] fileRet; fileRet = carla_strdup_safe(ret.toUtf8()); return fileRet; } //--------------------------------------------------------------------------------------------------------------------- // Init host Host& initHost(const QString /*initName*/, const bool isControl, const bool isPlugin, const bool failError) { CarlaString pathBinaries, pathResources; // = getPaths(libPrefix) //----------------------------------------------------------------------------------------------------------------- // Print info // ---------------------------------------------------------------------------------------------------------------- // Init host if (failError) { // # no try // host = HostClass() if HostClass is not None else CarlaHostQtDLL(libname, loadGlobal) } else { // try: // host = HostClass() if HostClass is not None else CarlaHostQtDLL(libname, loadGlobal) // except: // host = CarlaHostQtNull() } static Host host; host.isControl = isControl; host.isPlugin = isPlugin; carla_set_engine_callback(_engineCallback, &host); carla_set_file_callback(_fileCallback, nullptr); // If it's a plugin the paths are already set if (! isPlugin) { host.pathBinaries = pathBinaries; host.pathResources = pathResources; carla_set_engine_option(ENGINE_OPTION_PATH_BINARIES, 0, pathBinaries); carla_set_engine_option(ENGINE_OPTION_PATH_RESOURCES, 0, pathResources); /* if (! isControl) host.nsmOK = carla_nsm_init(getpid(), initName); */ } // ---------------------------------------------------------------------------------------------------------------- // Done return host; } //--------------------------------------------------------------------------------------------------------------------- // Load host settings void loadHostSettings(Host& /*host*/) { } //---------------------------------------------------------------------------------------------------------------------