diff --git a/resources/ui/carla_osc_connect.ui b/resources/ui/carla_osc_connect.ui new file mode 100644 index 000000000..4608f66c5 --- /dev/null +++ b/resources/ui/carla_osc_connect.ui @@ -0,0 +1,298 @@ + + + Dialog + + + + 0 + 0 + 443 + 281 + + + + Carla Control - Connect + + + + + + Remote setup + + + + + + UDP Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Remote host: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 1024 + + + 32767 + + + + + + + 1024 + + + 32767 + + + + + + + TCP Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 60 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 60 + + + + + + + + + + + Reported host + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 92 + 38 + + + + + + + + + 0 + 0 + + + + Automatic + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 92 + 38 + + + + + + + + + 0 + 0 + + + + Custom: + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 1 + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + 1 + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + In some networks (like USB connections), the remote system cannot reach the local network. You can specify here which hostname or IP to make the remote Carla connect to. +If you are unsure, leave it as 'Automatic'. + + + Qt::NoTextInteraction + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 1 + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/source/frontend/Makefile b/source/frontend/Makefile index 3499c8006..5f7208a64 100644 --- a/source/frontend/Makefile +++ b/source/frontend/Makefile @@ -30,6 +30,7 @@ UIs = \ ui_carla_database.py \ ui_carla_edit.py \ ui_carla_host.py \ + ui_carla_osc_connect.py \ ui_carla_parameter.py \ ui_carla_plugin_calf.py \ ui_carla_plugin_classic.py \ @@ -68,6 +69,7 @@ RES = \ $(BINDIR)/resources/ui_carla_database.py \ $(BINDIR)/resources/ui_carla_edit.py \ $(BINDIR)/resources/ui_carla_host.py \ + $(BINDIR)/resources/ui_carla_osc_connect.py \ $(BINDIR)/resources/ui_carla_parameter.py \ $(BINDIR)/resources/ui_carla_plugin_calf.py \ $(BINDIR)/resources/ui_carla_plugin_classic.py \ diff --git a/source/frontend/carla_backend.py b/source/frontend/carla_backend.py index aea9451dd..9d4b11f45 100644 --- a/source/frontend/carla_backend.py +++ b/source/frontend/carla_backend.py @@ -2948,7 +2948,7 @@ class CarlaHostPlugin(CarlaHostMeta): # plugin info self.fPluginsInfo = {} - self.fFallbackPluginInfo = PyCarlaPluginInfo.copy() + self.fFallbackPluginInfo = PluginStoreInfo() # runtime engine info self.fRuntimeEngineInfo = { diff --git a/source/frontend/carla_control.py b/source/frontend/carla_control.py index a5280c641..bf4b8d3b0 100755 --- a/source/frontend/carla_control.py +++ b/source/frontend/carla_control.py @@ -24,6 +24,8 @@ from PyQt5.QtCore import QEventLoop # ------------------------------------------------------------------------------------------------------------ # Imports (Custom) +import ui_carla_osc_connect + from carla_host import * # ------------------------------------------------------------------------------------------------------------ @@ -46,6 +48,112 @@ from random import random DEBUG = False +# ---------------------------------------------------------------------------------------------------------------------- +# OSC connect Dialog + +class ConnectDialog(QDialog): + def __init__(self, parent): + QDialog.__init__(self, parent) + self.ui = ui_carla_osc_connect.Ui_Dialog() + self.ui.setupUi(self) + + self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) + + # Mke PlainTextEdit background the same color as the window background + palette = self.ui.te_reported_hint.palette() + palette.setColor(QPalette.Base, palette.color(QPalette.Background)) + self.ui.te_reported_hint.setPalette(palette) + + # ------------------------------------------------------------------------------------------------------------- + # Load settings + + self.loadSettings() + + # ------------------------------------------------------------------------------------------------------------- + # Set-up connections + + self.finished.connect(self.slot_saveSettings) + self.ui.rb_reported_auto.clicked.connect(self.slot_reportedAutoClicked) + self.ui.rb_reported_custom.clicked.connect(self.slot_reportedCustomClicked) + self.ui.le_host.textChanged.connect(self.slot_hostChanged) + self.ui.le_reported_host.textChanged.connect(self.slot_reportedHostChanged) + + # ----------------------------------------------------------------------------------------------------------------- + + def getResult(self): + return (self.ui.le_host.text(), + self.ui.le_reported_host.text() if self.ui.rb_reported_custom.isChecked() else "", + self.ui.sb_tcp_port.value(), + self.ui.sb_udp_port.value()) + + def checkIfButtonBoxShouldBeEnabled(self, host, reportedHostAutomatic, reportedHost): + enabled = len(host) > 0 + + if enabled and not reportedHostAutomatic: + enabled = len(reportedHost) > 0 + + self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled) + + def loadSettings(self): + settings = QSettings("falkTX", "CarlaOSCConnect") + + if settings.value("ReportedHostAutomatic", True, type=bool): + self.ui.rb_reported_custom.setChecked(False) + self.ui.rb_reported_auto.setChecked(True) + else: + self.ui.rb_reported_auto.setChecked(False) + self.ui.rb_reported_custom.setChecked(True) + + self.ui.le_host.setText(settings.value("Host", "127.0.0.1", type=str)) + self.ui.le_reported_host.setText(settings.value("ReportedHost", "", type=str)) + self.ui.sb_tcp_port.setValue(settings.value("TCPPort", CARLA_DEFAULT_OSC_TCP_PORT_NUMBER, type=int)) + self.ui.sb_udp_port.setValue(settings.value("UDPPort", CARLA_DEFAULT_OSC_UDP_PORT_NUMBER, type=int)) + + self.checkIfButtonBoxShouldBeEnabled(self.ui.le_host.text(), + self.ui.rb_reported_auto.isChecked(), + self.ui.le_reported_host.text()) + + # ------------------------------------------------------------------------------------------------------------------ + + @pyqtSlot(bool) + def slot_reportedAutoClicked(self, clicked): + self.checkIfButtonBoxShouldBeEnabled(self.ui.le_host.text(), + clicked, + self.ui.le_reported_host.text()) + + @pyqtSlot(bool) + def slot_reportedCustomClicked(self, clicked): + self.checkIfButtonBoxShouldBeEnabled(self.ui.le_host.text(), + not clicked, + self.ui.le_reported_host.text()) + + @pyqtSlot(str) + def slot_hostChanged(self, text): + self.checkIfButtonBoxShouldBeEnabled(text, + self.ui.rb_reported_auto.isChecked(), + self.ui.le_reported_host.text()) + + @pyqtSlot(str) + def slot_reportedHostChanged(self, text): + self.checkIfButtonBoxShouldBeEnabled(self.ui.le_host.text(), + self.ui.rb_reported_auto.isChecked(), + text) + + @pyqtSlot() + def slot_saveSettings(self): + settings = QSettings("falkTX", "CarlaOSCConnect") + settings.setValue("Host", self.ui.le_host.text()) + settings.setValue("ReportedHost", self.ui.le_reported_host.text()) + settings.setValue("TCPPort", self.ui.sb_tcp_port.value()) + settings.setValue("UDPPort", self.ui.sb_udp_port.value()) + settings.setValue("ReportedHostAutomatic", self.ui.rb_reported_auto.isChecked()) + + # ------------------------------------------------------------------------------------------------------------------ + + def done(self, r): + QDialog.done(self, r) + self.close() + # ------------------------------------------------------------------------------------------------------------ # Host OSC object @@ -60,12 +168,15 @@ class CarlaHostOSC(CarlaHostQtPlugin): self.lo_target_tcp_name = "" self.lo_target_udp_name = "" + self.resetPendingMessages() + + # ------------------------------------------------------------------- + + def resetPendingMessages(self): self.lastMessageId = 1 self.pendingMessages = [] self.responses = {} - # ------------------------------------------------------------------- - def printAndReturnError(self, error): print(error) self.fLastError = error @@ -78,7 +189,6 @@ class CarlaHostOSC(CarlaHostQtPlugin): method = lines.pop(0) if method == "set_engine_option": - print(method, lines) return True if self.lo_target_tcp is None: @@ -182,11 +292,9 @@ class CarlaHostOSC(CarlaHostQtPlugin): # ------------------------------------------------------------------- def engine_init(self, driverName, clientName): - print("engine_init", self.lo_target_tcp is not None) return self.lo_target_tcp is not None def engine_close(self): - print("engine_close") return True def engine_idle(self): @@ -202,13 +310,14 @@ class CarlaHostOSC(CarlaHostQtPlugin): # OSC Control server class CarlaControlServerTCP(Server): - def __init__(self, host): + def __init__(self, host, rhost): Server.__init__(self, proto=LO_TCP) if False: host = CarlaHostOSC() self.host = host + self.rhost = rhost def idle(self): self.fReceivedMsgs = False @@ -217,6 +326,8 @@ class CarlaControlServerTCP(Server): pass def getFullURL(self): + if self.rhost: + return "osc.tcp://%s:%i/ctrl" % (self.rhost, self.get_port()) return "%sctrl" % self.get_url() @make_method('/ctrl/cb', 'iiiiifs') @@ -390,13 +501,14 @@ class CarlaControlServerTCP(Server): # --------------------------------------------------------------------------------------------------------------------- class CarlaControlServerUDP(Server): - def __init__(self, host): + def __init__(self, host, rhost): Server.__init__(self, proto=LO_UDP) if False: - host = CarlaHostPlugin() + host = CarlaHostOSC() self.host = host + self.rhost = rhost def idle(self): self.fReceivedMsgs = False @@ -405,6 +517,8 @@ class CarlaControlServerUDP(Server): pass def getFullURL(self): + if self.rhost: + return "osc.udp://%s:%i/ctrl" % (self.rhost, self.get_port()) return "%sctrl" % self.get_url() @make_method('/ctrl/runtime', 'fiihiiif') @@ -441,7 +555,7 @@ class HostWindowOSC(HostWindow): if False: # kdevelop likes this :) - host = CarlaHostPlugin() + host = CarlaHostOSC() self.host = host # ---------------------------------------------------------------------------------------------------- @@ -456,11 +570,13 @@ class HostWindowOSC(HostWindow): if oscAddr: QTimer.singleShot(0, self.connectOsc) - def connectOsc(self, addrTCP = None, addrUDP = None): + def connectOsc(self, addrTCP = None, addrUDP = None, rhost = None): if addrTCP is not None: self.fOscAddressTCP = addrTCP if addrUDP is not None: self.fOscAddressUDP = addrUDP + if rhost is not None: + self.fOscReportedHost = rhost lo_target_tcp_name = self.fOscAddressTCP.rsplit("/", 1)[-1] lo_target_udp_name = self.fOscAddressUDP.rsplit("/", 1)[-1] @@ -469,11 +585,11 @@ class HostWindowOSC(HostWindow): try: lo_target_tcp = Address(self.fOscAddressTCP) - lo_server_tcp = CarlaControlServerTCP(self.host) + lo_server_tcp = CarlaControlServerTCP(self.host, self.fOscReportedHost) lo_send(lo_target_tcp, "/register", lo_server_tcp.getFullURL()) lo_target_udp = Address(self.fOscAddressUDP) - lo_server_udp = CarlaControlServerUDP(self.host) + lo_server_udp = CarlaControlServerUDP(self.host, self.fOscReportedHost) lo_send(lo_target_udp, "/register", lo_server_udp.getFullURL()) except AddressError as e: @@ -582,6 +698,7 @@ class HostWindowOSC(HostWindow): settings = HostWindow.loadSettings(self, firstTime) self.fOscAddressTCP = settings.value("RemoteAddressTCP", "osc.tcp://127.0.0.1:22752/Carla", type=str) self.fOscAddressUDP = settings.value("RemoteAddressUDP", "osc.udp://127.0.0.1:22752/Carla", type=str) + self.fOscReportedHost = settings.value("RemoteReportedHost", "", type=str) def saveSettings(self): settings = HostWindow.saveSettings(self) @@ -589,31 +706,24 @@ class HostWindowOSC(HostWindow): settings.setValue("RemoteAddressTCP", self.fOscAddressTCP) if self.fOscAddressUDP: settings.setValue("RemoteAddressUDP", self.fOscAddressUDP) + if self.fOscReportedHost: + settings.setValue("RemoteReportedHost", self.fOscReportedHost) # -------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_fileConnect(self): - dialog = QInputDialog(self) - dialog.setInputMode(QInputDialog.TextInput) - dialog.setLabelText(self.tr("Address:")) - dialog.setTextValue(self.fOscAddressTCP or "osc.tcp://127.0.0.1:22752/Carla") - dialog.setWindowTitle(self.tr("Carla Control - Connect")) - dialog.resize(400,1) - - ok = dialog.exec_() - addr = dialog.textValue().strip() - del dialog - - if not ok: - return - if not addr: + dialog = ConnectDialog(self) + + if not dialog.exec_(): return - self.disconnectOsc() + host, rhost, tcpPort, udpPort = dialog.getResult() - if addr: - self.connectOsc(addr.replace("osc.udp:", "osc.tcp:"), addr.replace("osc.tcp:", "osc.udp:")) + self.disconnectOsc() + self.connectOsc("osc.tcp://%s:%i/Carla" % (host, tcpPort), + "osc.udp://%s:%i/Carla" % (host, udpPort), + rhost) @pyqtSlot() def slot_fileRefresh(self): @@ -633,8 +743,8 @@ class HostWindowOSC(HostWindow): self.removeAllPlugins() patchcanvas.clear() - self.host.lo_server_tcp = CarlaControlServerTCP(self.host) - self.host.lo_server_udp = CarlaControlServerUDP(self.host) + self.host.lo_server_tcp = CarlaControlServerTCP(self.host, self.fOscReportedHost) + self.host.lo_server_udp = CarlaControlServerUDP(self.host, self.fOscReportedHost) try: lo_send(self.host.lo_target_tcp, "/register", self.host.lo_server_tcp.getFullURL()) @@ -653,6 +763,7 @@ class HostWindowOSC(HostWindow): @pyqtSlot() def slot_handleSIGTERM(self): print("Got SIGTERM -> Closing now") + self.host.pendingMessages = [] self.close() @pyqtSlot() diff --git a/source/frontend/carla_database.py b/source/frontend/carla_database.py index b83cecb96..39990a0ab 100755 --- a/source/frontend/carla_database.py +++ b/source/frontend/carla_database.py @@ -16,7 +16,7 @@ # # For a full copy of the GNU General Public License see the doc/GPL.txt file. -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Imports (Global) from copy import deepcopy @@ -25,7 +25,7 @@ from subprocess import Popen, PIPE from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QEventLoop, QThread, QSettings from PyQt5.QtWidgets import QApplication, QDialog, QDialogButtonBox, QTableWidgetItem -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Imports (Custom) import ui_carla_add_jack @@ -34,7 +34,7 @@ import ui_carla_refresh from carla_shared import * -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Try Import LADSPA-RDF if WINDOWS: @@ -52,7 +52,7 @@ else: qWarning("LRDF Support disabled for static build (LADSPA-RDF will be disabled)") haveLRDF = False -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Set LADSPA-RDF Path if haveLRDF and readEnvVars: @@ -64,7 +64,7 @@ if haveLRDF and readEnvVars: pass del LADSPA_RDF_PATH_env -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Plugin Query (helper functions) def findBinaries(binPath, OS): @@ -127,7 +127,7 @@ def findFilenames(filePath, stype): return filenames -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Plugin Query PLUGIN_QUERY_API_VERSION = 8 @@ -363,7 +363,7 @@ def checkFileSFZ(filename, tool): def checkAllPluginsAU(tool): return runCarlaDiscovery(PLUGIN_AU, "AU", ":all", tool) -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Separate Thread for Plugin Search class SearchPluginsThread(QThread): @@ -1246,7 +1246,7 @@ class PluginRefreshW(QDialog): self.ui.ch_do_checks.setChecked(settings.value("PluginDatabase/DoChecks", False, type=bool)) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_saveSettings(self): @@ -1266,7 +1266,7 @@ class PluginRefreshW(QDialog): settings.setValue("PluginDatabase/SearchWin64", self.ui.ch_win64.isChecked()) settings.setValue("PluginDatabase/DoChecks", self.ui.ch_do_checks.isChecked()) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_start(self): @@ -1297,13 +1297,13 @@ class PluginRefreshW(QDialog): self.fThread.setSearchPluginTypes(ladspa, dssi, lv2, vst, vst3, au, sf2, sfz) self.fThread.start() - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_skip(self): killDiscovery() - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_checkTools(self): @@ -1318,14 +1318,14 @@ class PluginRefreshW(QDialog): self.ui.b_start.setEnabled(enabled1 and enabled2) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot(int, str) def slot_handlePluginLook(self, percent, plugin): self.ui.progressBar.setFormat("%s" % plugin) self.ui.progressBar.setValue(percent) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot() def slot_handlePluginThreadFinished(self): @@ -1339,7 +1339,7 @@ class PluginRefreshW(QDialog): self.ui.group_types.setEnabled(True) self.ui.group_options.setEnabled(True) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- def closeEvent(self, event): if self.fThread.isRunning(): @@ -1355,13 +1355,13 @@ class PluginRefreshW(QDialog): QDialog.closeEvent(self, event) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- def done(self, r): QDialog.done(self, r) self.close() -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Plugin Database Dialog class PluginDatabaseW(QDialog): @@ -1924,7 +1924,7 @@ class PluginDatabaseW(QDialog): QDialog.done(self, r) self.close() -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Jack Application Dialog class JackApplicationW(QDialog): @@ -1966,7 +1966,7 @@ class JackApplicationW(QDialog): self.ui.cb_session_mgr.currentIndexChanged.connect(self.slot_sessionManagerChanged) self.ui.le_command.textChanged.connect(self.slot_commandChanged) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- def getCommandAndFlags(self): name = self.ui.le_name.text() @@ -2032,7 +2032,7 @@ class JackApplicationW(QDialog): self.checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), self.ui.le_command.text()) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- @pyqtSlot(str) def slot_commandChanged(self, text): @@ -2054,13 +2054,13 @@ class JackApplicationW(QDialog): settings.setValue("NumMidiOuts", self.ui.sb_midi_outs.value()) settings.setValue("ManageWindow", self.ui.cb_manage_window.isChecked()) - # ------------------------------------------------------------------------------------------------------------------ + # ----------------------------------------------------------------------------------------------------------------- def done(self, r): QDialog.done(self, r) self.close() -# ---------------------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------------------------------------------- # Main if __name__ == '__main__': diff --git a/source/frontend/carla_host.py b/source/frontend/carla_host.py index 181343ed8..a684b50e4 100644 --- a/source/frontend/carla_host.py +++ b/source/frontend/carla_host.py @@ -148,6 +148,7 @@ class HostWindow(QMainWindow): self.fSampleRate = 0.0 self.fOscAddressTCP = "" self.fOscAddressUDP = "" + self.fOscReportedHost = "" if MACOS: self.fMacClosingHelper = True