| @@ -35,9 +35,9 @@ NON_STATIC_LINK_FLAGS = $(LINK_FLAGS) | |||
| endif | |||
| ifeq ($(WINDOWS),true) | |||
| QT_LINK_FLAGS += -L$(BINDIR) $(BINDIR)/libcarla_utils.dll | |||
| QT_LINK_FLAGS += -L$(BINDIR) $(BINDIR)/libcarla_standalone2.dll $(BINDIR)/libcarla_utils.dll | |||
| else | |||
| QT_LINK_FLAGS += -L$(BINDIR) -lcarla_utils | |||
| QT_LINK_FLAGS += -L$(BINDIR) -lcarla_standalone2 -lcarla_utils | |||
| endif | |||
| ifeq ($(MACOS),true) | |||
| @@ -58,6 +58,7 @@ QMs = $(patsubst %,translations/carla_%.qm,$(I18N_LANGUAGES)) | |||
| CPP_FILES = \ | |||
| carla_frontend.cpp \ | |||
| dialogs/aboutdialog.cpp \ | |||
| dialogs/jackappdialog.cpp \ | |||
| pluginlist/pluginlistdialog.cpp | |||
| @@ -89,7 +90,6 @@ RES = \ | |||
| $(BINDIR)/resources/notes-ui \ | |||
| $(BINDIR)/resources/xycontroller-ui \ | |||
| $(BINDIR)/resources/resources_rc.py \ | |||
| $(BINDIR)/resources/ui_carla_about.py \ | |||
| $(BINDIR)/resources/ui_carla_edit.py \ | |||
| $(BINDIR)/resources/ui_carla_host.py \ | |||
| $(BINDIR)/resources/ui_carla_osc_connect.py \ | |||
| @@ -122,11 +122,8 @@ PLUGINLIST_UI_FILES = $(wildcard pluginlist/*.ui) | |||
| UIs = $(DIALOG_UI_FILES:dialogs/%.ui=dialogs/ui_%.h) | |||
| UIs += $(PLUGINLIST_UI_FILES:pluginlist/%.ui=pluginlist/ui_%.h) | |||
| UIs += $(DIALOG_UI_FILES:%.ui=%_ui.py) | |||
| # old stuff, not yet converted | |||
| UIs += \ | |||
| ui_carla_about.py \ | |||
| ui_carla_edit.py \ | |||
| ui_carla_host.py \ | |||
| ui_carla_osc_connect.py \ | |||
| @@ -1531,6 +1531,7 @@ class CarlaHostMeta(): | |||
| self.isPlugin = False | |||
| self.isRemote = False | |||
| self.nsmOK = False | |||
| self.handle = None | |||
| # settings | |||
| self.processMode = ENGINE_PROCESS_MODE_PATCHBAY | |||
| @@ -1,23 +1,136 @@ | |||
| /* | |||
| * Carla Plugin Host | |||
| * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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. | |||
| */ | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #include "carla_frontend.h" | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // common files | |||
| #include "utils/qsafesettings.cpp" | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // aboutdialog | |||
| #include "dialogs/aboutdialog.hpp" | |||
| void carla_frontend_createAndExecAboutDialog(QWidget* const parent, | |||
| const CarlaHostHandle hostHandle, | |||
| const bool isControl, | |||
| const bool isPlugin) | |||
| { | |||
| AboutDialog(parent, hostHandle, isControl, isPlugin).exec(); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // jackappdialog | |||
| #include "dialogs/jackappdialog.hpp" | |||
| #include "distrho/extra/String.hpp" | |||
| const JackAppDialogResults* | |||
| carla_frontend_createAndExecJackAppDialog(QWidget* const parent, const char* const projectFilename) | |||
| { | |||
| JackAppDialog gui(parent, projectFilename); | |||
| if (gui.exec()) | |||
| { | |||
| static JackAppDialogResults ret = {}; | |||
| static String retCommand; | |||
| static String retName; | |||
| static String retLabelSetup; | |||
| const JackAppDialog::CommandAndFlags cafs = gui.getCommandAndFlags(); | |||
| retCommand = cafs.command.toUtf8().constData(); | |||
| retName = cafs.name.toUtf8().constData(); | |||
| retLabelSetup = cafs.labelSetup.toUtf8().constData(); | |||
| ret.command = retCommand; | |||
| ret.name = retName; | |||
| ret.labelSetup = retLabelSetup; | |||
| return &ret; | |||
| } | |||
| return nullptr; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // pluginlistdialog | |||
| #include "pluginlist/pluginlistdialog.hpp" | |||
| #include "CarlaUtils.h" | |||
| PluginListDialog* | |||
| carla_frontend_createPluginListDialog(QWidget* const parent, const HostSettings* const hostSettings) | |||
| { | |||
| return new PluginListDialog(parent, hostSettings); | |||
| } | |||
| void | |||
| carla_frontend_destroyPluginListDialog(PluginListDialog* const dialog) | |||
| { | |||
| dialog->close(); | |||
| delete dialog; | |||
| } | |||
| void | |||
| carla_frontend_setPluginListDialogPath(PluginListDialog* const dialog, const int ptype, const char* const path) | |||
| { | |||
| dialog->setPluginPath(static_cast<PluginType>(ptype), path); | |||
| } | |||
| const PluginListDialogResults* | |||
| carla_frontend_execPluginListDialog(PluginListDialog* const dialog) | |||
| { | |||
| if (dialog->exec()) | |||
| { | |||
| static PluginListDialogResults ret; | |||
| static String category; | |||
| static String filename; | |||
| static String name; | |||
| static String label; | |||
| static String maker; | |||
| const PluginInfo& plugin(dialog->getSelectedPluginInfo()); | |||
| category = plugin.category.toUtf8(); | |||
| filename = plugin.filename.toUtf8(); | |||
| name = plugin.name.toUtf8(); | |||
| label = plugin.label.toUtf8(); | |||
| maker = plugin.maker.toUtf8(); | |||
| ret.build = plugin.build; | |||
| ret.type = plugin.type; | |||
| ret.hints = plugin.hints; | |||
| ret.category = category; | |||
| ret.filename = filename; | |||
| ret.name = name; | |||
| ret.label = label; | |||
| ret.maker = maker; | |||
| ret.uniqueId = plugin.uniqueId; | |||
| ret.audioIns = plugin.audioIns; | |||
| ret.audioOuts = plugin.audioOuts; | |||
| ret.cvIns = plugin.cvIns; | |||
| ret.cvOuts = plugin.cvOuts; | |||
| ret.midiIns = plugin.midiIns; | |||
| ret.midiOuts = plugin.midiOuts; | |||
| ret.parameterIns = plugin.parameterIns; | |||
| ret.parameterOuts = plugin.parameterOuts; | |||
| return &ret; | |||
| } | |||
| return nullptr; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // const PluginListDialogResults* | |||
| // carla_frontend_createAndExecPluginListDialog(void* const parent, const HostSettings* const hostSettings) | |||
| // { | |||
| // PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings); | |||
| // | |||
| // return carla_frontend_execPluginListDialog(&gui); | |||
| // } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,4 +1,4 @@ | |||
| // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #pragma once | |||
| @@ -10,6 +10,8 @@ using CARLA_BACKEND_NAMESPACE::PluginType; | |||
| extern "C" { | |||
| #endif | |||
| typedef struct _CarlaHostHandle* CarlaHostHandle; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| typedef struct { | |||
| @@ -49,17 +51,26 @@ typedef struct { | |||
| #ifdef __cplusplus | |||
| class PluginListDialog; | |||
| class QWidget; | |||
| #else | |||
| struct PluginListDialog; | |||
| struct QWidget; | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_PLUGIN_EXPORT void | |||
| carla_frontend_createAndExecAboutDialog(QWidget* parent, CarlaHostHandle hostHandle, bool isControl, bool isPlugin); | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_PLUGIN_EXPORT const JackAppDialogResults* | |||
| carla_frontend_createAndExecJackAppDialog(void* parent, const char* projectFilename); | |||
| carla_frontend_createAndExecJackAppDialog(QWidget* parent, const char* projectFilename); | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_PLUGIN_EXPORT PluginListDialog* | |||
| carla_frontend_createPluginListDialog(void* parent, const HostSettings* hostSettings); | |||
| carla_frontend_createPluginListDialog(QWidget* parent, const HostSettings* hostSettings); | |||
| CARLA_PLUGIN_EXPORT void | |||
| carla_frontend_destroyPluginListDialog(PluginListDialog* dialog); | |||
| @@ -81,6 +81,9 @@ class CarlaFrontendLib(): | |||
| def __init__(self, filename): | |||
| self.lib = cdll.LoadLibrary(filename) | |||
| self.lib.carla_frontend_createAndExecAboutDialog.argtypes = (c_void_p, c_void_p, c_bool, c_bool) | |||
| self.lib.carla_frontend_createAndExecAboutDialog.restype = None | |||
| self.lib.carla_frontend_createAndExecJackAppDialog.argtypes = (c_void_p, c_char_p) | |||
| self.lib.carla_frontend_createAndExecJackAppDialog.restype = POINTER(JackApplicationDialogResults) | |||
| @@ -98,9 +101,16 @@ class CarlaFrontendLib(): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def createAndExecAboutDialog(self, parent, hostHandle, isControl, isPlugin): | |||
| return structToDictOrNull(self.lib.carla_frontend_createAndExecAboutDialog(unwrapinstance(parent), | |||
| hostHandle, | |||
| isControl, | |||
| isPlugin)) | |||
| def createAndExecJackAppDialog(self, parent, projectFilename): | |||
| return structToDictOrNull(self.lib.carla_frontend_createAndExecJackAppDialog(unwrapinstance(parent), | |||
| projectFilename.encode("utf-8"))) | |||
| return structToDictOrNull( | |||
| self.lib.carla_frontend_createAndExecJackAppDialog(unwrapinstance(parent), | |||
| projectFilename.encode("utf-8"))) | |||
| def createPluginListDialog(self, parent, hostSettings): | |||
| hostSettingsC = HostSettings() | |||
| @@ -2215,7 +2215,10 @@ class HostWindow(QMainWindow): | |||
| @pyqtSlot() | |||
| def slot_aboutCarla(self): | |||
| CarlaAboutW(self.fParentOrSelf, self.host).exec_() | |||
| gCarla.felib.createAndExecAboutDialog(self.fParentOrSelf, | |||
| self.host.handle, | |||
| self.host.isControl, | |||
| self.host.isPlugin) | |||
| @pyqtSlot() | |||
| def slot_aboutQt(self): | |||
| @@ -42,7 +42,6 @@ elif qt_config == 6: | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Imports (Custom) | |||
| import ui_carla_about | |||
| import ui_carla_edit | |||
| import ui_carla_parameter | |||
| @@ -113,135 +112,6 @@ ICON_STATE_WAIT = 2 # nothing, sets as off | |||
| ICON_STATE_OFF = 1 # turns off, sets as null | |||
| ICON_STATE_NULL = 0 # nothing | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Carla About dialog | |||
| class CarlaAboutW(QDialog): | |||
| def __init__(self, parent, host): | |||
| QDialog.__init__(self, parent) | |||
| self.ui = ui_carla_about.Ui_CarlaAboutW() | |||
| self.ui.setupUi(self) | |||
| if host.isControl: | |||
| extraInfo = " - <b>%s</b>" % self.tr("OSC Bridge Version") | |||
| elif host.isPlugin: | |||
| extraInfo = " - <b>%s</b>" % self.tr("Plugin Version") | |||
| else: | |||
| extraInfo = "" | |||
| self.ui.l_about.setText(self.tr("" | |||
| "<br>Version %s" | |||
| "<br>Carla is a fully-featured audio plugin host%s.<br>" | |||
| "<br>Copyright (C) 2011-2025 falkTX<br>" | |||
| "" % (CARLA_VERSION_STRING, extraInfo))) | |||
| if self.ui.about.palette().color(QPalette.Background).blackF() < 0.5: | |||
| self.ui.l_icons.setPixmap(QPixmap(":/bitmaps/carla_about_black.png")) | |||
| self.ui.ico_example_edit.setPixmap(QPixmap(":/bitmaps/button_file-black.png")) | |||
| self.ui.ico_example_file.setPixmap(QPixmap(":/scalable/button_edit-black.svg")) | |||
| self.ui.ico_example_gui.setPixmap(QPixmap(":/bitmaps/button_gui-black.png")) | |||
| if host.isControl: | |||
| self.ui.l_extended.hide() | |||
| self.ui.tabWidget.removeTab(3) | |||
| self.ui.tabWidget.removeTab(2) | |||
| self.ui.l_extended.setText(gCarla.utils.get_complete_license_text()) | |||
| if host.is_engine_running() and not host.isControl: | |||
| self.ui.le_osc_url_tcp.setText(host.get_host_osc_url_tcp()) | |||
| self.ui.le_osc_url_udp.setText(host.get_host_osc_url_udp()) | |||
| else: | |||
| self.ui.le_osc_url_tcp.setText(self.tr("(Engine not running)")) | |||
| self.ui.le_osc_url_udp.setText(self.tr("(Engine not running)")) | |||
| # pylint: disable=line-too-long | |||
| self.ui.l_osc_cmds.setText("<table>" | |||
| "<tr><td>" "/set_active" " </td><td><i-value></td></tr>" | |||
| "<tr><td>" "/set_drywet" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_volume" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_balance_left" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_balance_right" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_panning" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_parameter_value" " </td><td><i-index> <f-value></td></tr>" | |||
| "<tr><td>" "/set_parameter_midi_cc" " </td><td><i-index> <i-cc></td></tr>" | |||
| "<tr><td>" "/set_parameter_midi_channel" " </td><td><i-index> <i-channel></td></tr>" | |||
| "<tr><td>" "/set_program" " </td><td><i-index></td></tr>" | |||
| "<tr><td>" "/set_midi_program" " </td><td><i-index></td></tr>" | |||
| "<tr><td>" "/note_on" " </td><td><i-channel> <i-note> <i-velo></td></tr>" | |||
| "<tr><td>" "/note_off" " </td><td><i-channel> <i-note</td></tr>" | |||
| "</table>" | |||
| ) | |||
| self.ui.l_example.setText("/Carla/2/set_parameter_value 5 1.0") | |||
| self.ui.l_example_help.setText("<i>(as in this example, \"2\" is the plugin number and \"5\" the parameter)</i>") | |||
| # pylint: enable=line-too-long | |||
| self.ui.l_ladspa.setText(self.tr("Everything! (Including LRDF)")) | |||
| self.ui.l_dssi.setText(self.tr("Everything! (Including CustomData/Chunks)")) | |||
| self.ui.l_lv2.setText(self.tr("About 110% complete (using custom extensions)<br/>" | |||
| "Implemented Feature/Extensions:" | |||
| "<ul>" | |||
| "<li>http://lv2plug.in/ns/ext/atom</li>" | |||
| "<li>http://lv2plug.in/ns/ext/buf-size</li>" | |||
| "<li>http://lv2plug.in/ns/ext/data-access</li>" | |||
| #"<li>http://lv2plug.in/ns/ext/dynmanifest</li>" | |||
| "<li>http://lv2plug.in/ns/ext/event</li>" | |||
| "<li>http://lv2plug.in/ns/ext/instance-access</li>" | |||
| "<li>http://lv2plug.in/ns/ext/log</li>" | |||
| "<li>http://lv2plug.in/ns/ext/midi</li>" | |||
| #"<li>http://lv2plug.in/ns/ext/morph</li>" | |||
| "<li>http://lv2plug.in/ns/ext/options</li>" | |||
| "<li>http://lv2plug.in/ns/ext/parameters</li>" | |||
| #"<li>http://lv2plug.in/ns/ext/patch</li>" | |||
| "<li>http://lv2plug.in/ns/ext/port-props</li>" | |||
| "<li>http://lv2plug.in/ns/ext/presets</li>" | |||
| "<li>http://lv2plug.in/ns/ext/resize-port</li>" | |||
| "<li>http://lv2plug.in/ns/ext/state</li>" | |||
| "<li>http://lv2plug.in/ns/ext/time</li>" | |||
| "<li>http://lv2plug.in/ns/ext/uri-map</li>" | |||
| "<li>http://lv2plug.in/ns/ext/urid</li>" | |||
| "<li>http://lv2plug.in/ns/ext/worker</li>" | |||
| "<li>http://lv2plug.in/ns/extensions/ui</li>" | |||
| "<li>http://lv2plug.in/ns/extensions/units</li>" | |||
| "<li>http://home.gna.org/lv2dynparam/rtmempool/v1</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/external-ui</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/programs</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/props</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/rtmempool</li>" | |||
| "<li>http://ll-plugins.nongnu.org/lv2/ext/midimap</li>" | |||
| "<li>http://ll-plugins.nongnu.org/lv2/ext/miditype</li>" | |||
| "</ul>")) | |||
| self.ui.l_vst2.setText(self.tr("About 85% complete (missing vst bank/presets and some minor stuff)")) | |||
| self.ui.l_vst3.setText(self.tr("About 66% complete")) | |||
| if CARLA_OS_MAC: | |||
| self.ui.l_au.setText(self.tr("About 20% complete")) | |||
| else: | |||
| self.ui.line_vst3.hide() | |||
| self.ui.l_au.hide() | |||
| self.ui.lid_au.hide() | |||
| # 3rd tab is usually longer than the 1st | |||
| # adjust appropriately | |||
| self.ui.tabWidget.setCurrentIndex(2) | |||
| self.adjustSize() | |||
| self.ui.tabWidget.setCurrentIndex(0) | |||
| self.setFixedSize(self.size()) | |||
| flags = self.windowFlags() | |||
| flags &= ~Qt.WindowContextHelpButtonHint | |||
| if CARLA_OS_WIN: | |||
| flags |= Qt.MSWindowsFixedSizeDialogHint | |||
| self.setWindowFlags(flags) | |||
| if CARLA_OS_MAC: | |||
| self.setWindowModality(Qt.WindowModal) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Plugin Parameter | |||
| @@ -1852,9 +1722,6 @@ if __name__ == '__main__': | |||
| _host.add_plugin(BINARY_NATIVE, PLUGIN_DSSI, "/usr/lib/dssi/karplong.so", "karplong", "karplong", 0, None, 0x0) | |||
| _host.set_active(0, True) | |||
| gui1 = CarlaAboutW(None, _host) | |||
| gui1.show() | |||
| gui2 = PluginEdit(None, _host, 0) | |||
| gui2.testTimer() | |||
| gui2.show() | |||
| @@ -1,19 +0,0 @@ | |||
| #!/usr/bin/env python3 | |||
| # -*- coding: utf-8 -*- | |||
| # Carla plugin host | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # 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. | |||
| from .jackappdialog import JackAppDialog | |||
| @@ -0,0 +1,165 @@ | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #include "aboutdialog.hpp" | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic push | |||
| # pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy" | |||
| # pragma clang diagnostic ignored "-Wdeprecated-register" | |||
| #elif defined(__GNUC__) && __GNUC__ >= 8 | |||
| # pragma GCC diagnostic push | |||
| # pragma GCC diagnostic ignored "-Wclass-memaccess" | |||
| # pragma GCC diagnostic ignored "-Wdeprecated-copy" | |||
| #endif | |||
| // #include <QtCore/QFileInfo> | |||
| // #include <QtCore/QVector> | |||
| // #include <QtWidgets/QPushButton> | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic pop | |||
| #elif defined(__GNUC__) && __GNUC__ >= 8 | |||
| # pragma GCC diagnostic pop | |||
| #endif | |||
| #include "CarlaHost.h" | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // About Dialog | |||
| AboutDialog::AboutDialog(QWidget* const parent, | |||
| const CarlaHostHandle hostHandle, | |||
| const bool isControl, | |||
| const bool isPlugin) | |||
| : QDialog(parent) | |||
| { | |||
| ui.setupUi(this); | |||
| QString extraInfo; | |||
| if (isControl) | |||
| extraInfo = QString(" - <b>%1</b>").arg(tr("OSC Bridge Version")); | |||
| else if (isPlugin) | |||
| extraInfo = QString(" - <b>%1</b>").arg(tr("Plugin Version")); | |||
| ui.l_about->setText(tr("" | |||
| "<br>Version %1" | |||
| "<br>Carla is a fully-featured audio plugin host%2.<br>" | |||
| "<br>Copyright (C) 2011-2025 falkTX<br>" | |||
| "").arg(CARLA_VERSION_STRING).arg(extraInfo)); | |||
| if (ui.about->palette().color(QPalette::Background).blackF() < 0.5) | |||
| { | |||
| ui.l_icons->setPixmap(QPixmap(":/bitmaps/carla_about_black.png")); | |||
| ui.ico_example_edit->setPixmap(QPixmap(":/bitmaps/button_file-black.png")); | |||
| ui.ico_example_file->setPixmap(QPixmap(":/scalable/button_edit-black.svg")); | |||
| ui.ico_example_gui->setPixmap(QPixmap(":/bitmaps/button_gui-black.png")); | |||
| } | |||
| if (isControl || isPlugin) | |||
| { | |||
| ui.l_extended->hide(); | |||
| ui.tabWidget->removeTab(3); | |||
| ui.tabWidget->removeTab(2); | |||
| } | |||
| else if (carla_is_engine_running(hostHandle)) | |||
| { | |||
| ui.le_osc_url_tcp->setText(carla_get_host_osc_url_tcp(hostHandle)); | |||
| ui.le_osc_url_udp->setText(carla_get_host_osc_url_udp(hostHandle)); | |||
| } | |||
| else | |||
| { | |||
| ui.le_osc_url_tcp->setText(tr("(Engine not running)")); | |||
| ui.le_osc_url_udp->setText(tr("(Engine not running)")); | |||
| } | |||
| ui.l_extended->setText(carla_get_complete_license_text()); | |||
| ui.l_osc_cmds->setText("<table>" | |||
| "<tr><td>" "/set_active" " </td><td><i-value></td></tr>" | |||
| "<tr><td>" "/set_drywet" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_volume" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_balance_left" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_balance_right" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_panning" " </td><td><f-value></td></tr>" | |||
| "<tr><td>" "/set_parameter_value" " </td><td><i-index> <f-value></td></tr>" | |||
| "<tr><td>" "/set_parameter_midi_cc" " </td><td><i-index> <i-cc></td></tr>" | |||
| "<tr><td>" "/set_parameter_midi_channel" " </td><td><i-index> <i-channel></td></tr>" | |||
| "<tr><td>" "/set_program" " </td><td><i-index></td></tr>" | |||
| "<tr><td>" "/set_midi_program" " </td><td><i-index></td></tr>" | |||
| "<tr><td>" "/note_on" " </td><td><i-channel> <i-note> <i-velo></td></tr>" | |||
| "<tr><td>" "/note_off" " </td><td><i-channel> <i-note</td></tr>" | |||
| "</table>"); | |||
| ui.l_example->setText("/Carla/2/set_parameter_value 5 1.0"); | |||
| ui.l_example_help->setText("<i>(as in this example, \"2\" is the plugin number and \"5\" the parameter)</i>"); | |||
| ui.l_ladspa->setText(tr("Everything! (Including LRDF)")); | |||
| ui.l_dssi->setText(tr("Everything! (Including CustomData/Chunks)")); | |||
| ui.l_lv2->setText(tr("About 110% complete (using custom extensions)<br/>" | |||
| "Implemented Feature/Extensions:" | |||
| "<ul>" | |||
| "<li>http://lv2plug.in/ns/ext/atom</li>" | |||
| "<li>http://lv2plug.in/ns/ext/buf-size</li>" | |||
| "<li>http://lv2plug.in/ns/ext/data-access</li>" | |||
| // "<li>http://lv2plug.in/ns/ext/dynmanifest</li>" | |||
| "<li>http://lv2plug.in/ns/ext/event</li>" | |||
| "<li>http://lv2plug.in/ns/ext/instance-access</li>" | |||
| "<li>http://lv2plug.in/ns/ext/log</li>" | |||
| "<li>http://lv2plug.in/ns/ext/midi</li>" | |||
| // "<li>http://lv2plug.in/ns/ext/morph</li>" | |||
| "<li>http://lv2plug.in/ns/ext/options</li>" | |||
| "<li>http://lv2plug.in/ns/ext/parameters</li>" | |||
| // "<li>http://lv2plug.in/ns/ext/patch</li>" | |||
| // "<li>http://lv2plug.in/ns/ext/port-groups</li>" | |||
| "<li>http://lv2plug.in/ns/ext/port-props</li>" | |||
| "<li>http://lv2plug.in/ns/ext/presets</li>" | |||
| "<li>http://lv2plug.in/ns/ext/resize-port</li>" | |||
| "<li>http://lv2plug.in/ns/ext/state</li>" | |||
| "<li>http://lv2plug.in/ns/ext/time</li>" | |||
| "<li>http://lv2plug.in/ns/ext/uri-map</li>" | |||
| "<li>http://lv2plug.in/ns/ext/urid</li>" | |||
| "<li>http://lv2plug.in/ns/ext/worker</li>" | |||
| "<li>http://lv2plug.in/ns/extensions/ui</li>" | |||
| "<li>http://lv2plug.in/ns/extensions/units</li>" | |||
| "<li>http://home.gna.org/lv2dynparam/rtmempool/v1</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/external-ui</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/programs</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/props</li>" | |||
| "<li>http://kxstudio.sf.net/ns/lv2ext/rtmempool</li>" | |||
| "<li>http://ll-plugins.nongnu.org/lv2/ext/midimap</li>" | |||
| "<li>http://ll-plugins.nongnu.org/lv2/ext/miditype</li>" | |||
| "</ul>")); | |||
| ui.l_vst2->setText(tr("About 85% complete (missing vst bank/presets and some minor stuff)")); | |||
| ui.l_vst3->setText(tr("About 66% complete")); | |||
| #ifdef CARLA_OS_MAC | |||
| ui.l_au->setText(tr("About 20% complete")); | |||
| #else | |||
| ui.line_vst3->hide(); | |||
| ui.l_au->hide(); | |||
| ui.lid_au->hide(); | |||
| #endif | |||
| // 3rd tab is usually longer than the 1st, adjust appropriately | |||
| ui.tabWidget->setCurrentIndex(2); | |||
| adjustSize(); | |||
| ui.tabWidget->setCurrentIndex(0); | |||
| setFixedSize(size()); | |||
| Qt::WindowFlags flags = windowFlags(); | |||
| flags &= ~Qt::WindowContextHelpButtonHint; | |||
| #ifdef CARLA_OS_WIN | |||
| flags |= ~Qt::MSWindowsFixedSizeDialogHint; | |||
| #endif | |||
| setWindowFlags(flags); | |||
| #ifdef CARLA_OS_MAC | |||
| if (parent != nullptr) | |||
| setWindowModality(Qt::WindowModal); | |||
| #endif | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -0,0 +1,39 @@ | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #pragma once | |||
| #include "carla_frontend.h" | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic push | |||
| # pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy" | |||
| # pragma clang diagnostic ignored "-Wdeprecated-register" | |||
| #elif defined(__GNUC__) && __GNUC__ >= 8 | |||
| # pragma GCC diagnostic push | |||
| # pragma GCC diagnostic ignored "-Wclass-memaccess" | |||
| # pragma GCC diagnostic ignored "-Wdeprecated-copy" | |||
| #endif | |||
| #include "ui_aboutdialog.h" | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic pop | |||
| #elif defined(__GNUC__) && __GNUC__ >= 8 | |||
| # pragma GCC diagnostic pop | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // About Dialog | |||
| class AboutDialog : public QDialog | |||
| { | |||
| Ui_AboutDialog ui; | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| public: | |||
| explicit AboutDialog(QWidget* parent, CarlaHostHandle hostHandle, bool isControl, bool isPlugin); | |||
| }; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,7 +1,7 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <ui version="4.0"> | |||
| <class>CarlaAboutW</class> | |||
| <widget class="QDialog" name="CarlaAboutW"> | |||
| <class>AboutDialog</class> | |||
| <widget class="QDialog" name="AboutDialog"> | |||
| <property name="geometry"> | |||
| <rect> | |||
| <x>0</x> | |||
| @@ -1425,7 +1425,7 @@ POSSIBILITY OF SUCH DAMAGES. | |||
| <connection> | |||
| <sender>buttonBox</sender> | |||
| <signal>accepted()</signal> | |||
| <receiver>CarlaAboutW</receiver> | |||
| <receiver>AboutDialog</receiver> | |||
| <slot>accept()</slot> | |||
| <hints> | |||
| <hint type="sourcelabel"> | |||
| @@ -1441,7 +1441,7 @@ POSSIBILITY OF SUCH DAMAGES. | |||
| <connection> | |||
| <sender>buttonBox</sender> | |||
| <signal>rejected()</signal> | |||
| <receiver>CarlaAboutW</receiver> | |||
| <receiver>AboutDialog</receiver> | |||
| <slot>reject()</slot> | |||
| <hints> | |||
| <hint type="sourcelabel"> | |||
| @@ -1,19 +1,5 @@ | |||
| /* | |||
| * Carla plugin host | |||
| * Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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. | |||
| */ | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #include "jackappdialog.hpp" | |||
| @@ -27,9 +13,7 @@ | |||
| # pragma GCC diagnostic ignored "-Wdeprecated-copy" | |||
| #endif | |||
| #include "ui_jackappdialog.h" | |||
| #include <QtCore/QFileInfo> | |||
| #include <QtCore/QVector> | |||
| #include <QtWidgets/QPushButton> | |||
| #ifdef __clang__ | |||
| @@ -40,43 +24,29 @@ | |||
| #include "qsafesettings.hpp" | |||
| #include "CarlaFrontend.h" | |||
| #include "CarlaLibJackHints.h" | |||
| #include "CarlaString.hpp" | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Jack Application Dialog | |||
| enum { | |||
| UI_SESSION_NONE = 0, | |||
| UI_SESSION_LADISH = 1, | |||
| UI_SESSION_NSM = 2, | |||
| }; | |||
| struct JackAppDialog::Self { | |||
| Ui_JackAppDialog ui; | |||
| struct JackAppDialog::PrivateData { | |||
| const QString fProjectFilename; | |||
| Self(const char* const projectFilename) | |||
| PrivateData(const char* const projectFilename) | |||
| : fProjectFilename(projectFilename) {} | |||
| static Self& create(const char* const projectFilename) | |||
| { | |||
| Self* const self = new Self(projectFilename); | |||
| return *self; | |||
| } | |||
| }; | |||
| JackAppDialog::JackAppDialog(QWidget* const parent, const char* const projectFilename) | |||
| : QDialog(parent), | |||
| self(Self::create(projectFilename)) | |||
| p(new PrivateData(projectFilename)) | |||
| { | |||
| self.ui.setupUi(this); | |||
| ui.setupUi(this); | |||
| // ------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // UI setup | |||
| self.ui.group_error->setVisible(false); | |||
| ui.group_error->setVisible(false); | |||
| adjustSize(); | |||
| setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); | |||
| @@ -86,34 +56,34 @@ JackAppDialog::JackAppDialog(QWidget* const parent, const char* const projectFil | |||
| setWindowModality(Qt::WindowModal); | |||
| #endif | |||
| // ------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // Load settings | |||
| loadSettings(); | |||
| // ------------------------------------------------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // Set-up connections | |||
| connect(this, &QDialog::finished, | |||
| this, &JackAppDialog::slot_saveSettings); | |||
| connect(self.ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), | |||
| connect(ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), | |||
| this, &JackAppDialog::slot_sessionManagerChanged); | |||
| connect(self.ui.le_command, &QLineEdit::textChanged, | |||
| connect(ui.le_command, &QLineEdit::textChanged, | |||
| this, &JackAppDialog::slot_commandChanged); | |||
| } | |||
| JackAppDialog::~JackAppDialog() | |||
| { | |||
| delete &self; | |||
| delete p; | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // public methods | |||
| JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const | |||
| { | |||
| const QString command = self.ui.le_command->text(); | |||
| QString name = self.ui.le_name->text(); | |||
| const QString command = ui.le_command->text(); | |||
| QString name = ui.le_name->text(); | |||
| if (name.isEmpty()) | |||
| { | |||
| @@ -122,7 +92,7 @@ JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const | |||
| } | |||
| SessionManager smgr; | |||
| switch (self.ui.cb_session_mgr->currentIndex()) | |||
| switch (ui.cb_session_mgr->currentIndex()) | |||
| { | |||
| case UI_SESSION_LADISH: | |||
| smgr = LIBJACK_SESSION_MANAGER_LADISH; | |||
| @@ -136,28 +106,28 @@ JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const | |||
| } | |||
| uint flags = 0x0; | |||
| if (self.ui.cb_manage_window->isChecked()) | |||
| if (ui.cb_manage_window->isChecked()) | |||
| flags |= LIBJACK_FLAG_CONTROL_WINDOW; | |||
| if (self.ui.cb_capture_first_window->isChecked()) | |||
| if (ui.cb_capture_first_window->isChecked()) | |||
| flags |= LIBJACK_FLAG_CAPTURE_FIRST_WINDOW; | |||
| if (self.ui.cb_buffers_addition_mode->isChecked()) | |||
| if (ui.cb_buffers_addition_mode->isChecked()) | |||
| flags |= LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION; | |||
| if (self.ui.cb_out_midi_mixdown->isChecked()) | |||
| if (ui.cb_out_midi_mixdown->isChecked()) | |||
| flags |= LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN; | |||
| if (self.ui.cb_external_start->isChecked()) | |||
| if (ui.cb_external_start->isChecked()) | |||
| flags |= LIBJACK_FLAG_EXTERNAL_START; | |||
| const QString labelSetup(QString("%1%2%3%4%5%6").arg(QChar('0' + self.ui.sb_audio_ins->value())) | |||
| .arg(QChar('0' + self.ui.sb_audio_outs->value())) | |||
| .arg(QChar('0' + self.ui.sb_midi_ins->value())) | |||
| .arg(QChar('0' + self.ui.sb_midi_outs->value())) | |||
| const QString labelSetup(QString("%1%2%3%4%5%6").arg(QChar('0' + ui.sb_audio_ins->value())) | |||
| .arg(QChar('0' + ui.sb_audio_outs->value())) | |||
| .arg(QChar('0' + ui.sb_midi_ins->value())) | |||
| .arg(QChar('0' + ui.sb_midi_outs->value())) | |||
| .arg(QChar('0' + smgr)) | |||
| .arg(QChar('0' + flags))); | |||
| return {command, name, labelSetup}; | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // private methods | |||
| void JackAppDialog::checkIfButtonBoxShouldBeEnabled(const int index, const QCarlaString& command) | |||
| @@ -166,28 +136,28 @@ void JackAppDialog::checkIfButtonBoxShouldBeEnabled(const int index, const QCarl | |||
| QCarlaString showErr; | |||
| // NSM applications must not be abstract or absolute paths, and must not contain arguments | |||
| if (enabled and index == UI_SESSION_NSM) | |||
| if (enabled && index == UI_SESSION_NSM) | |||
| { | |||
| if (QVector<QChar>{'.', '/'}.contains(command[0])) | |||
| if (command[0] == '.' || command[0] == '/') | |||
| showErr = tr("NSM applications cannot use abstract or absolute paths"); | |||
| else if (command.contains(' ') or command.contains(';') or command.contains('&')) | |||
| showErr = tr("NSM applications cannot use CLI arguments"); | |||
| else if (self.fProjectFilename.isEmpty()) | |||
| else if (p->fProjectFilename.isEmpty()) | |||
| showErr = tr("You need to save the current Carla project before NSM can be used"); | |||
| } | |||
| if (showErr.isNotEmpty()) | |||
| { | |||
| enabled = false; | |||
| self.ui.l_error->setText(showErr); | |||
| self.ui.group_error->setVisible(true); | |||
| ui.l_error->setText(showErr); | |||
| ui.group_error->setVisible(true); | |||
| } | |||
| else | |||
| { | |||
| self.ui.group_error->setVisible(false); | |||
| ui.group_error->setVisible(false); | |||
| } | |||
| if (QPushButton* const button = self.ui.buttonBox->button(QDialogButtonBox::Ok)) | |||
| if (QPushButton* const button = ui.buttonBox->button(QDialogButtonBox::Ok)) | |||
| button->setEnabled(enabled); | |||
| } | |||
| @@ -198,104 +168,53 @@ void JackAppDialog::loadSettings() | |||
| const QString smName = settings.valueString("SessionManager", ""); | |||
| if (smName == "LADISH (SIGUSR1)") | |||
| self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH); | |||
| ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH); | |||
| else if (smName == "NSM") | |||
| self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM); | |||
| ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM); | |||
| else | |||
| self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE); | |||
| self.ui.le_command->setText(settings.valueString("Command", "")); | |||
| self.ui.le_name->setText(settings.valueString("Name", "")); | |||
| self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
| self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
| self.ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2)); | |||
| self.ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0)); | |||
| self.ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0)); | |||
| self.ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true)); | |||
| self.ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false)); | |||
| self.ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false)); | |||
| checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(), | |||
| self.ui.le_command->text()); | |||
| ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE); | |||
| ui.le_command->setText(settings.valueString("Command", "")); | |||
| ui.le_name->setText(settings.valueString("Name", "")); | |||
| ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
| ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2)); | |||
| ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2)); | |||
| ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0)); | |||
| ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0)); | |||
| ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true)); | |||
| ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false)); | |||
| ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false)); | |||
| checkIfButtonBoxShouldBeEnabled(ui.cb_session_mgr->currentIndex(), | |||
| ui.le_command->text()); | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // private slots | |||
| void JackAppDialog::slot_commandChanged(const QString& command) | |||
| { | |||
| checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(), command); | |||
| checkIfButtonBoxShouldBeEnabled(ui.cb_session_mgr->currentIndex(), command); | |||
| } | |||
| void JackAppDialog::slot_sessionManagerChanged(const int index) | |||
| { | |||
| checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command->text()); | |||
| checkIfButtonBoxShouldBeEnabled(index, ui.le_command->text()); | |||
| } | |||
| void JackAppDialog::slot_saveSettings() | |||
| { | |||
| QSafeSettings settings("falkTX", "CarlaAddJackApp"); | |||
| settings.setValue("Command", self.ui.le_command->text()); | |||
| settings.setValue("Name", self.ui.le_name->text()); | |||
| settings.setValue("SessionManager", self.ui.cb_session_mgr->currentText()); | |||
| settings.setValue("NumAudioIns", self.ui.sb_audio_ins->value()); | |||
| settings.setValue("NumAudioOuts", self.ui.sb_audio_outs->value()); | |||
| settings.setValue("NumMidiIns", self.ui.sb_midi_ins->value()); | |||
| settings.setValue("NumMidiOuts", self.ui.sb_midi_outs->value()); | |||
| settings.setValue("ManageWindow", self.ui.cb_manage_window->isChecked()); | |||
| settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window->isChecked()); | |||
| settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown->isChecked()); | |||
| settings.setValue("Command", ui.le_command->text()); | |||
| settings.setValue("Name", ui.le_name->text()); | |||
| settings.setValue("SessionManager", ui.cb_session_mgr->currentText()); | |||
| settings.setValue("NumAudioIns", ui.sb_audio_ins->value()); | |||
| settings.setValue("NumAudioOuts", ui.sb_audio_outs->value()); | |||
| settings.setValue("NumMidiIns", ui.sb_midi_ins->value()); | |||
| settings.setValue("NumMidiOuts", ui.sb_midi_outs->value()); | |||
| settings.setValue("ManageWindow", ui.cb_manage_window->isChecked()); | |||
| settings.setValue("CaptureFirstWindow", ui.cb_capture_first_window->isChecked()); | |||
| settings.setValue("MidiOutMixdown", ui.cb_out_midi_mixdown->isChecked()); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| const JackAppDialogResults* | |||
| carla_frontend_createAndExecJackAppDialog(void* const parent, const char* const projectFilename) | |||
| { | |||
| JackAppDialog gui(reinterpret_cast<QWidget*>(parent), projectFilename); | |||
| if (gui.exec()) | |||
| { | |||
| static JackAppDialogResults ret = {}; | |||
| static CarlaString retCommand; | |||
| static CarlaString retName; | |||
| static CarlaString retLabelSetup; | |||
| const JackAppDialog::CommandAndFlags cafs = gui.getCommandAndFlags(); | |||
| retCommand = cafs.command.toUtf8().constData(); | |||
| retName = cafs.name.toUtf8().constData(); | |||
| retLabelSetup = cafs.labelSetup.toUtf8().constData(); | |||
| ret.command = retCommand; | |||
| ret.name = retName; | |||
| ret.labelSetup = retLabelSetup; | |||
| return &ret; | |||
| } | |||
| return nullptr; | |||
| } | |||
| #if 0 | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Testing | |||
| #include "../utils/qsafesettings.cpp" | |||
| int main(int argc, char* argv[]) | |||
| { | |||
| QApplication app(argc, argv); | |||
| if (JackAppDialogResults* const res = carla_frontend_createAndExecJackAppDialog(nullptr, "")) | |||
| { | |||
| printf("Results:\n"); | |||
| printf("\tCommand: %s\n", res->command); | |||
| printf("\tName: %s\n", res->name); | |||
| printf("\tLabelSetup: %s\n", res->labelSetup); | |||
| } | |||
| return 0; | |||
| } | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,22 +1,10 @@ | |||
| /* | |||
| * Carla plugin host | |||
| * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * 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. | |||
| */ | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #pragma once | |||
| #include "carla_frontend.h" | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic push | |||
| # pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy" | |||
| @@ -27,7 +15,7 @@ | |||
| # pragma GCC diagnostic ignored "-Wdeprecated-copy" | |||
| #endif | |||
| #include <QtWidgets/QDialog> | |||
| #include "ui_jackappdialog.h" | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic pop | |||
| @@ -42,8 +30,16 @@ | |||
| class JackAppDialog : public QDialog | |||
| { | |||
| struct Self; | |||
| Self& self; | |||
| enum { | |||
| UI_SESSION_NONE, | |||
| UI_SESSION_LADISH, | |||
| UI_SESSION_NSM, | |||
| }; | |||
| struct PrivateData; | |||
| PrivateData* const p; | |||
| Ui_JackAppDialog ui; | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,221 +0,0 @@ | |||
| #!/usr/bin/env python3 | |||
| # -*- coding: utf-8 -*- | |||
| # Carla plugin host | |||
| # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # 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) | |||
| import os | |||
| from PyQt5.QtCore import pyqtSlot, Qt | |||
| from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QWidget | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Carla) | |||
| from utils import QSafeSettings | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (Local) | |||
| from jackappdialog_ui import Ui_JackAppDialog | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Imports (API) | |||
| SESSION_MGR_NONE = 0 | |||
| SESSION_MGR_AUTO = 1 | |||
| SESSION_MGR_JACK = 2 | |||
| SESSION_MGR_LADISH = 3 | |||
| SESSION_MGR_NSM = 4 | |||
| FLAG_CONTROL_WINDOW = 0x01 | |||
| FLAG_CAPTURE_FIRST_WINDOW = 0x02 | |||
| FLAG_BUFFERS_ADDITION_MODE = 0x10 | |||
| FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN = 0x20 | |||
| FLAG_EXTERNAL_START = 0x40 | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Jack Application Dialog | |||
| UI_SESSION_NONE = 0 | |||
| UI_SESSION_LADISH = 1 | |||
| UI_SESSION_NSM = 2 | |||
| class JackAppDialog(QDialog): | |||
| def __init__(self, parent: QWidget, projectFilename: str): | |||
| QDialog.__init__(self, parent) | |||
| self.ui = Ui_JackAppDialog() | |||
| self.ui.setupUi(self) | |||
| self.fProjectFilename = projectFilename | |||
| # -------------------------------------------------------------------------------------------------------------- | |||
| # UI setup | |||
| self.ui.group_error.setVisible(False) | |||
| self.adjustSize() | |||
| self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) | |||
| # -------------------------------------------------------------------------------------------------------------- | |||
| # Load settings | |||
| self._loadSettings() | |||
| # -------------------------------------------------------------------------------------------------------------- | |||
| # Set-up connections | |||
| self.finished.connect(self._slot_saveSettings) | |||
| self.ui.cb_session_mgr.currentIndexChanged.connect(self._slot_sessionManagerChanged) | |||
| self.ui.le_command.textChanged.connect(self._slot_commandChanged) | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| # public methods | |||
| def getCommandAndFlags(self): | |||
| name = self.ui.le_name.text() | |||
| command = self.ui.le_command.text() | |||
| smgr = SESSION_MGR_NONE | |||
| flags = 0x0 | |||
| if not name: | |||
| name = os.path.basename(command.split(" ",1)[0]).title() | |||
| uiSessionMgrIndex = self.ui.cb_session_mgr.currentIndex() | |||
| if uiSessionMgrIndex == UI_SESSION_LADISH: | |||
| smgr = SESSION_MGR_LADISH | |||
| elif uiSessionMgrIndex == UI_SESSION_NSM: | |||
| smgr = SESSION_MGR_NSM | |||
| if self.ui.cb_manage_window.isChecked(): | |||
| flags |= FLAG_CONTROL_WINDOW | |||
| if self.ui.cb_capture_first_window.isChecked(): | |||
| flags |= FLAG_CAPTURE_FIRST_WINDOW | |||
| if self.ui.cb_buffers_addition_mode.isChecked(): | |||
| flags |= FLAG_BUFFERS_ADDITION_MODE | |||
| if self.ui.cb_out_midi_mixdown.isChecked(): | |||
| flags |= FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN | |||
| if self.ui.cb_external_start.isChecked(): | |||
| flags |= FLAG_EXTERNAL_START | |||
| bv = ord('0') | |||
| v1 = chr(bv + self.ui.sb_audio_ins.value()) | |||
| v2 = chr(bv + self.ui.sb_audio_outs.value()) | |||
| v3 = chr(bv + self.ui.sb_midi_ins.value()) | |||
| v4 = chr(bv + self.ui.sb_midi_outs.value()) | |||
| v5 = chr(bv + smgr) | |||
| v6 = chr(bv + flags) | |||
| labelSetup = f"{v1}{v2}{v3}{v4}{v5}{v6}" | |||
| return (command, name, labelSetup) | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| # private methods | |||
| def _checkIfButtonBoxShouldBeEnabled(self, index: int, command: str): | |||
| enabled = len(command) > 0 | |||
| showErr = "" | |||
| # NSM applications must not be abstract or absolute paths, and must not contain arguments | |||
| if enabled and index == UI_SESSION_NSM: | |||
| if command[0] in (".", "/"): | |||
| showErr = self.tr("NSM applications cannot use abstract or absolute paths") | |||
| elif " " in command or ";" in command or "&" in command: | |||
| showErr = self.tr("NSM applications cannot use CLI arguments") | |||
| elif not self.fProjectFilename: | |||
| showErr = self.tr("You need to save the current Carla project before NSM can be used") | |||
| if showErr: | |||
| enabled = False | |||
| self.ui.l_error.setText(showErr) | |||
| self.ui.group_error.setVisible(True) | |||
| else: | |||
| self.ui.group_error.setVisible(False) | |||
| self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled) | |||
| def _loadSettings(self): | |||
| settings = QSafeSettings("falkTX", "CarlaAddJackApp") | |||
| smName = settings.value("SessionManager", "", str) | |||
| if smName == "LADISH (SIGUSR1)": | |||
| self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_LADISH) | |||
| elif smName == "NSM": | |||
| self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NSM) | |||
| else: | |||
| self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NONE) | |||
| self.ui.le_command.setText(settings.value("Command", "", str)) | |||
| self.ui.le_name.setText(settings.value("Name", "", str)) | |||
| self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int)) | |||
| self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int)) | |||
| self.ui.sb_audio_outs.setValue(settings.value("NumAudioOuts", 2, int)) | |||
| self.ui.sb_midi_ins.setValue(settings.value("NumMidiIns", 0, int)) | |||
| self.ui.sb_midi_outs.setValue(settings.value("NumMidiOuts", 0, int)) | |||
| self.ui.cb_manage_window.setChecked(settings.value("ManageWindow", True, bool)) | |||
| self.ui.cb_capture_first_window.setChecked(settings.value("CaptureFirstWindow", False, bool)) | |||
| self.ui.cb_out_midi_mixdown.setChecked(settings.value("MidiOutMixdown", False, bool)) | |||
| self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), | |||
| self.ui.le_command.text()) | |||
| # ----------------------------------------------------------------------------------------------------------------- | |||
| # private slots | |||
| @pyqtSlot(str) | |||
| def _slot_commandChanged(self, command: str): | |||
| self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), command) | |||
| @pyqtSlot(int) | |||
| def _slot_sessionManagerChanged(self, index: int): | |||
| self._checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command.text()) | |||
| @pyqtSlot() | |||
| def _slot_saveSettings(self): | |||
| settings = QSafeSettings("falkTX", "CarlaAddJackApp") | |||
| settings.setValue("Command", self.ui.le_command.text()) | |||
| settings.setValue("Name", self.ui.le_name.text()) | |||
| settings.setValue("SessionManager", self.ui.cb_session_mgr.currentText()) | |||
| settings.setValue("NumAudioIns", self.ui.sb_audio_ins.value()) | |||
| settings.setValue("NumAudioOuts", self.ui.sb_audio_outs.value()) | |||
| settings.setValue("NumMidiIns", self.ui.sb_midi_ins.value()) | |||
| settings.setValue("NumMidiOuts", self.ui.sb_midi_outs.value()) | |||
| settings.setValue("ManageWindow", self.ui.cb_manage_window.isChecked()) | |||
| settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window.isChecked()) | |||
| settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown.isChecked()) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Testing | |||
| if __name__ == '__main__': | |||
| import sys | |||
| # pylint: disable=ungrouped-imports | |||
| from PyQt5.QtWidgets import QApplication | |||
| # pylint: enable=ungrouped-imports | |||
| _app = QApplication(sys.argv) | |||
| _gui = JackAppDialog(None, "") | |||
| if _gui.exec_(): | |||
| _command, _name, _labelSetup = _gui.getCommandAndFlags() | |||
| print("Results:") | |||
| print(f"\tCommand: {_command}") | |||
| print(f"\tName: {_name}") | |||
| print(f"\tLabelSetup: {_labelSetup}") | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -382,31 +382,6 @@ int fontMetricsHorizontalAdvance(const QFontMetrics& fontMetrics, const QString& | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Qt-compatible plugin info | |||
| // base details, nicely packed and POD-only so we can directly use as binary | |||
| struct PluginInfoHeader { | |||
| uint16_t build; | |||
| uint16_t type; | |||
| uint32_t hints; | |||
| uint64_t uniqueId; | |||
| uint16_t audioIns; | |||
| uint16_t audioOuts; | |||
| uint16_t cvIns; | |||
| uint16_t cvOuts; | |||
| uint16_t midiIns; | |||
| uint16_t midiOuts; | |||
| uint16_t parameterIns; | |||
| uint16_t parameterOuts; | |||
| }; | |||
| // full details, now with non-POD types | |||
| struct PluginInfo : PluginInfoHeader { | |||
| QString category; | |||
| QString filename; | |||
| QString name; | |||
| QString label; | |||
| QString maker; | |||
| }; | |||
| // convert PluginInfo to Qt types | |||
| static QVariant asByteArray(const PluginInfo& info) | |||
| { | |||
| @@ -2090,78 +2065,3 @@ void PluginListDialog::saveSettings() | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| PluginListDialog* | |||
| carla_frontend_createPluginListDialog(void* const parent, const HostSettings* const hostSettings) | |||
| { | |||
| return new PluginListDialog(reinterpret_cast<QWidget*>(parent), hostSettings); | |||
| } | |||
| void | |||
| carla_frontend_destroyPluginListDialog(PluginListDialog* const dialog) | |||
| { | |||
| dialog->close(); | |||
| delete dialog; | |||
| } | |||
| void | |||
| carla_frontend_setPluginListDialogPath(PluginListDialog* const dialog, const int ptype, const char* const path) | |||
| { | |||
| dialog->setPluginPath(static_cast<PluginType>(ptype), path); | |||
| } | |||
| const PluginListDialogResults* | |||
| carla_frontend_execPluginListDialog(PluginListDialog* const dialog) | |||
| { | |||
| if (dialog->exec()) | |||
| { | |||
| static PluginListDialogResults ret; | |||
| static CarlaString category; | |||
| static CarlaString filename; | |||
| static CarlaString name; | |||
| static CarlaString label; | |||
| static CarlaString maker; | |||
| const PluginInfo& plugin(dialog->getSelectedPluginInfo()); | |||
| category = plugin.category.toUtf8(); | |||
| filename = plugin.filename.toUtf8(); | |||
| name = plugin.name.toUtf8(); | |||
| label = plugin.label.toUtf8(); | |||
| maker = plugin.maker.toUtf8(); | |||
| ret.build = plugin.build; | |||
| ret.type = plugin.type; | |||
| ret.hints = plugin.hints; | |||
| ret.category = category; | |||
| ret.filename = filename; | |||
| ret.name = name; | |||
| ret.label = label; | |||
| ret.maker = maker; | |||
| ret.uniqueId = plugin.uniqueId; | |||
| ret.audioIns = plugin.audioIns; | |||
| ret.audioOuts = plugin.audioOuts; | |||
| ret.cvIns = plugin.cvIns; | |||
| ret.cvOuts = plugin.cvOuts; | |||
| ret.midiIns = plugin.midiIns; | |||
| ret.midiOuts = plugin.midiOuts; | |||
| ret.parameterIns = plugin.parameterIns; | |||
| ret.parameterOuts = plugin.parameterOuts; | |||
| return &ret; | |||
| } | |||
| return nullptr; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // const PluginListDialogResults* | |||
| // carla_frontend_createAndExecPluginListDialog(void* const parent, const HostSettings* const hostSettings) | |||
| // { | |||
| // PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings); | |||
| // | |||
| // return carla_frontend_execPluginListDialog(&gui); | |||
| // } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,9 +1,9 @@ | |||
| // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: GPL-2.0-or-later | |||
| #pragma once | |||
| #include "CarlaFrontend.h" | |||
| #include "carla_frontend.h" | |||
| #ifdef __clang__ | |||
| # pragma clang diagnostic push | |||
| @@ -15,7 +15,6 @@ | |||
| # pragma GCC diagnostic ignored "-Wdeprecated-copy" | |||
| #endif | |||
| #include <QtWidgets/QDialog> | |||
| #include "ui_pluginlistdialog.h" | |||
| #ifdef __clang__ | |||
| @@ -24,10 +23,35 @@ | |||
| # pragma GCC diagnostic pop | |||
| #endif | |||
| class QSafeSettings; | |||
| typedef struct _CarlaPluginDiscoveryInfo CarlaPluginDiscoveryInfo; | |||
| typedef struct _HostSettings HostSettings; | |||
| struct PluginInfo; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // base details, nicely packed and POD-only so we can directly use as binary | |||
| struct PluginInfoHeader { | |||
| uint16_t build; | |||
| uint16_t type; | |||
| uint32_t hints; | |||
| uint64_t uniqueId; | |||
| uint16_t audioIns; | |||
| uint16_t audioOuts; | |||
| uint16_t cvIns; | |||
| uint16_t cvOuts; | |||
| uint16_t midiIns; | |||
| uint16_t midiOuts; | |||
| uint16_t parameterIns; | |||
| uint16_t parameterOuts; | |||
| }; | |||
| // full details, now with non-POD types | |||
| struct PluginInfo : PluginInfoHeader { | |||
| QString category; | |||
| QString filename; | |||
| QString name; | |||
| QString label; | |||
| QString maker; | |||
| }; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Plugin List Dialog | |||