Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

753 lines
26KB

  1. #!/usr/bin/env python3
  2. # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
  3. # SPDX-License-Identifier: GPL-2.0-or-later
  4. # ----------------------------------------------------------------------------------------------------------------------
  5. # Imports (Global)
  6. from qt_compat import qt_config
  7. if qt_config == 5:
  8. from PyQt5.QtCore import QEventLoop
  9. elif qt_config == 6:
  10. from PyQt6.QtCore import QEventLoop
  11. # ------------------------------------------------------------------------------------------------------------
  12. # Imports (Custom)
  13. import ui_carla_osc_connect
  14. from carla_backend_qt import CarlaHostQtPlugin
  15. from carla_host import *
  16. # ------------------------------------------------------------------------------------------------------------
  17. # Imports (liblo)
  18. try:
  19. from pyliblo3 import (
  20. Address,
  21. AddressError,
  22. ServerError,
  23. Server,
  24. make_method,
  25. send as lo_send,
  26. TCP as LO_TCP,
  27. UDP as LO_UDP,
  28. )
  29. except ModuleNotFoundError:
  30. from liblo import (
  31. Address,
  32. AddressError,
  33. ServerError,
  34. Server,
  35. make_method,
  36. send as lo_send,
  37. TCP as LO_TCP,
  38. UDP as LO_UDP,
  39. )
  40. from random import random
  41. # ------------------------------------------------------------------------------------------------------------
  42. DEBUG = False
  43. # ----------------------------------------------------------------------------------------------------------------------
  44. # OSC connect Dialog
  45. class ConnectDialog(QDialog):
  46. def __init__(self, parent):
  47. QDialog.__init__(self, parent)
  48. self.ui = ui_carla_osc_connect.Ui_Dialog()
  49. self.ui.setupUi(self)
  50. self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
  51. # -------------------------------------------------------------------------------------------------------------
  52. # Load settings
  53. self.loadSettings()
  54. # -------------------------------------------------------------------------------------------------------------
  55. # Set-up connections
  56. self.finished.connect(self.slot_saveSettings)
  57. self.ui.le_host.textChanged.connect(self.slot_hostChanged)
  58. # -----------------------------------------------------------------------------------------------------------------
  59. def getResult(self):
  60. return (self.ui.le_host.text(),
  61. self.ui.sb_tcp_port.value(),
  62. self.ui.sb_udp_port.value())
  63. def checkIfButtonBoxShouldBeEnabled(self, host):
  64. enabled = len(host) > 0
  65. self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled)
  66. def loadSettings(self):
  67. settings = QSafeSettings("falkTX", "CarlaOSCConnect")
  68. self.ui.le_host.setText(settings.value("Host", "127.0.0.1", str))
  69. self.ui.sb_tcp_port.setValue(settings.value("TCPPort", CARLA_DEFAULT_OSC_TCP_PORT_NUMBER, int))
  70. self.ui.sb_udp_port.setValue(settings.value("UDPPort", CARLA_DEFAULT_OSC_UDP_PORT_NUMBER, int))
  71. self.checkIfButtonBoxShouldBeEnabled(self.ui.le_host.text())
  72. # ------------------------------------------------------------------------------------------------------------------
  73. @pyqtSlot(str)
  74. def slot_hostChanged(self, text):
  75. self.checkIfButtonBoxShouldBeEnabled(text)
  76. @pyqtSlot()
  77. def slot_saveSettings(self):
  78. settings = QSafeSettings("falkTX", "CarlaOSCConnect")
  79. settings.setValue("Host", self.ui.le_host.text())
  80. settings.setValue("TCPPort", self.ui.sb_tcp_port.value())
  81. settings.setValue("UDPPort", self.ui.sb_udp_port.value())
  82. # ------------------------------------------------------------------------------------------------------------------
  83. def done(self, r):
  84. QDialog.done(self, r)
  85. self.close()
  86. # ------------------------------------------------------------------------------------------------------------
  87. # Host OSC object
  88. class CarlaHostOSC(CarlaHostQtPlugin):
  89. def __init__(self):
  90. CarlaHostQtPlugin.__init__(self)
  91. self.lo_server_tcp = None
  92. self.lo_server_udp = None
  93. self.lo_target_tcp = None
  94. self.lo_target_udp = None
  95. self.lo_target_tcp_name = ""
  96. self.lo_target_udp_name = ""
  97. self.resetPendingMessages()
  98. # -------------------------------------------------------------------
  99. def resetPendingMessages(self):
  100. self.lastMessageId = 1
  101. self.pendingMessages = []
  102. self.responses = {}
  103. def printAndReturnError(self, error):
  104. print(error)
  105. self.fLastError = error
  106. return False
  107. def sendMsg(self, lines):
  108. if len(lines) < 1:
  109. return self.printAndReturnError("not enough arguments")
  110. method = lines.pop(0)
  111. if method == "set_engine_option":
  112. return True
  113. if self.lo_target_tcp is None:
  114. return self.printAndReturnError("lo_target_tcp is None")
  115. if self.lo_target_tcp_name is None:
  116. return self.printAndReturnError("lo_target_tcp_name is None")
  117. if method in ("clear_engine_xruns",
  118. "cancel_engine_action",
  119. #"load_file",
  120. #"load_project",
  121. #"save_project",
  122. #"clear_project_filename",
  123. "patchbay_connect",
  124. "patchbay_disconnect",
  125. "patchbay_set_group_pos",
  126. "patchbay_refresh",
  127. "transport_play",
  128. "transport_pause",
  129. "transport_bpm",
  130. "transport_relocate",
  131. "add_plugin",
  132. "remove_plugin",
  133. "remove_all_plugins",
  134. "rename_plugin",
  135. "clone_plugin",
  136. "replace_plugin",
  137. "switch_plugins",
  138. #"load_plugin_state",
  139. #"save_plugin_state",
  140. ):
  141. path = "/ctrl/" + method
  142. needResp = True
  143. elif method in (#"set_option",
  144. "set_active",
  145. "set_drywet",
  146. "set_volume",
  147. "set_balance_left",
  148. "set_balance_right",
  149. "set_panning",
  150. "set_forth",
  151. #"set_ctrl_channel",
  152. "set_parameter_value",
  153. "set_parameter_midi_channel",
  154. "set_parameter_midi_cc",
  155. "set_program",
  156. "set_midi_program",
  157. #"set_custom_data",
  158. #"set_chunk_data",
  159. #"prepare_for_save",
  160. #"reset_parameters",
  161. #"randomize_parameters",
  162. ):
  163. pluginId = lines.pop(0)
  164. needResp = False
  165. path = "/%s/%i/%s" % (self.lo_target_tcp_name, pluginId, method)
  166. elif method == "send_midi_note":
  167. pluginId = lines.pop(0)
  168. needResp = False
  169. channel, note, velocity = lines
  170. if velocity:
  171. path = "/%s/%i/note_on" % (self.lo_target_tcp_name, pluginId)
  172. else:
  173. path = "/%s/%i/note_off" % (self.lo_target_tcp_name, pluginId)
  174. lines.pop(2)
  175. else:
  176. return self.printAndReturnError("invalid method '%s'" % method)
  177. if len(self.pendingMessages) != 0:
  178. return self.printAndReturnError("A previous operation is still pending, please wait")
  179. args = [int(line) if isinstance(line, bool) else line for line in lines]
  180. #print(path, args)
  181. if not needResp:
  182. lo_send(self.lo_target_tcp, path, *args)
  183. return True
  184. messageId = self.lastMessageId
  185. self.lastMessageId += 1
  186. self.pendingMessages.append(messageId)
  187. lo_send(self.lo_target_tcp, path, messageId, *args)
  188. while messageId in self.pendingMessages:
  189. QApplication.processEvents(QEventLoop.AllEvents, 100)
  190. error = self.responses.pop(messageId)
  191. if not error:
  192. return True
  193. self.fLastError = error
  194. return False
  195. def sendMsgAndSetError(self, lines):
  196. return self.sendMsg(lines)
  197. # -------------------------------------------------------------------
  198. def engine_init(self, driverName, clientName):
  199. return self.lo_target_tcp is not None
  200. def engine_close(self):
  201. return True
  202. def engine_idle(self):
  203. return
  204. def is_engine_running(self):
  205. return self.lo_target_tcp is not None
  206. def set_engine_about_to_close(self):
  207. return
  208. # ---------------------------------------------------------------------------------------------------------------------
  209. # OSC Control server
  210. class CarlaControlServerTCP(Server):
  211. def __init__(self, host):
  212. Server.__init__(self, proto=LO_TCP)
  213. if False:
  214. host = CarlaHostOSC()
  215. self.host = host
  216. def idle(self):
  217. self.fReceivedMsgs = False
  218. while self.recv(0) and self.fReceivedMsgs:
  219. pass
  220. def getFullURL(self):
  221. return "%sctrl" % self.get_url()
  222. @make_method('/ctrl/cb', 'iiiiifs')
  223. def carla_cb(self, path, args):
  224. if DEBUG: print(path, args)
  225. self.fReceivedMsgs = True
  226. action, pluginId, value1, value2, value3, valuef, valueStr = args
  227. self.host._setViaCallback(action, pluginId, value1, value2, value3, valuef, valueStr)
  228. engineCallback(self.host, action, pluginId, value1, value2, value3, valuef, valueStr)
  229. @make_method('/ctrl/info', 'iiiihiisssssss')
  230. def carla_info(self, path, args):
  231. if DEBUG: print(path, args)
  232. self.fReceivedMsgs = True
  233. (
  234. pluginId, type_, category, hints, uniqueId, optsAvail, optsEnabled,
  235. name, filename, iconName, realName, label, maker, copyright,
  236. ) = args
  237. hints &= ~PLUGIN_HAS_CUSTOM_UI
  238. pinfo = {
  239. 'type': type_,
  240. 'category': category,
  241. 'hints': hints,
  242. 'optionsAvailable': optsAvail,
  243. 'optionsEnabled': optsEnabled,
  244. 'uniqueId': uniqueId,
  245. 'filename': filename,
  246. 'name': name,
  247. 'label': label,
  248. 'maker': maker,
  249. 'copyright': copyright,
  250. 'iconName': iconName
  251. }
  252. self.host._set_pluginInfoUpdate(pluginId, pinfo)
  253. self.host._set_pluginRealName(pluginId, realName)
  254. @make_method('/ctrl/ports', 'iiiiiiii')
  255. def carla_ports(self, path, args):
  256. if DEBUG: print(path, args)
  257. self.fReceivedMsgs = True
  258. pluginId, audioIns, audioOuts, midiIns, midiOuts, paramIns, paramOuts, paramTotal = args
  259. self.host._set_audioCountInfo(pluginId, {'ins': audioIns, 'outs': audioOuts})
  260. self.host._set_midiCountInfo(pluginId, {'ins': midiOuts, 'outs': midiOuts})
  261. self.host._set_parameterCountInfo(pluginId, paramTotal, {'ins': paramIns, 'outs': paramOuts})
  262. @make_method('/ctrl/paramInfo', 'iissss')
  263. def carla_paramInfo(self, path, args):
  264. if DEBUG: print(path, args)
  265. self.fReceivedMsgs = True
  266. pluginId, paramId, name, unit, comment, groupName = args
  267. paramInfo = {
  268. 'name': name,
  269. 'symbol': "",
  270. 'unit': unit,
  271. 'comment': comment,
  272. 'groupName': groupName,
  273. 'scalePointCount': 0,
  274. 'scalePoints': [],
  275. }
  276. self.host._set_parameterInfo(pluginId, paramId, paramInfo)
  277. @make_method('/ctrl/paramData', 'iiiiiifff')
  278. def carla_paramData(self, path, args):
  279. if DEBUG: print(path, args)
  280. self.fReceivedMsgs = True
  281. pluginId, paramId, type_, hints, midiChan, mappedCtrl, mappedMin, mappedMax, value = args
  282. hints &= ~(PARAMETER_USES_SCALEPOINTS | PARAMETER_USES_CUSTOM_TEXT)
  283. paramData = {
  284. 'type': type_,
  285. 'hints': hints,
  286. 'index': paramId,
  287. 'rindex': -1,
  288. 'midiChannel': midiChan,
  289. 'mappedControlIndex': mappedCtrl,
  290. 'mappedMinimum': mappedMin,
  291. 'mappedMaximum': mappedMax,
  292. }
  293. self.host._set_parameterData(pluginId, paramId, paramData)
  294. self.host._set_parameterValue(pluginId, paramId, value)
  295. @make_method('/ctrl/paramRanges', 'iiffffff')
  296. def carla_paramRanges(self, path, args):
  297. if DEBUG: print(path, args)
  298. self.fReceivedMsgs = True
  299. pluginId, paramId, def_, min_, max_, step, stepSmall, stepLarge = args
  300. paramRanges = {
  301. 'def': def_,
  302. 'min': min_,
  303. 'max': max_,
  304. 'step': step,
  305. 'stepSmall': stepSmall,
  306. 'stepLarge': stepLarge,
  307. }
  308. self.host._set_parameterRanges(pluginId, paramId, paramRanges)
  309. @make_method('/ctrl/count', 'iiiiii')
  310. def carla_count(self, path, args):
  311. if DEBUG: print(path, args)
  312. self.fReceivedMsgs = True
  313. pluginId, pcount, mpcount, cdcount, cp, cmp = args
  314. self.host._set_programCount(pluginId, pcount)
  315. self.host._set_midiProgramCount(pluginId, mpcount)
  316. self.host._set_customDataCount(pluginId, cdcount)
  317. self.host._set_pluginInfoUpdate(pluginId, { 'programCurrent': cp, 'midiProgramCurrent': cmp })
  318. @make_method('/ctrl/pcount', 'iii')
  319. def carla_pcount(self, path, args):
  320. if DEBUG: print(path, args)
  321. self.fReceivedMsgs = True
  322. pluginId, pcount, mpcount = args
  323. self.host._set_programCount(pluginId, pcount)
  324. self.host._set_midiProgramCount(pluginId, mpcount)
  325. @make_method('/ctrl/prog', 'iis')
  326. def carla_prog(self, path, args):
  327. if DEBUG: print(path, args)
  328. self.fReceivedMsgs = True
  329. pluginId, progId, progName = args
  330. self.host._set_programName(pluginId, progId, progName)
  331. @make_method('/ctrl/mprog', 'iiiis')
  332. def carla_mprog(self, path, args):
  333. if DEBUG: print(path, args)
  334. self.fReceivedMsgs = True
  335. pluginId, midiProgId, bank, program, name = args
  336. self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name})
  337. @make_method('/ctrl/cdata', 'iisss')
  338. def carla_cdata(self, path, args):
  339. if DEBUG: print(path, args)
  340. self.fReceivedMsgs = True
  341. pluginId, index, type_, key, value = args
  342. self.host._set_customData(pluginId, index, { 'type': type_, 'key': key, 'value': value })
  343. @make_method('/ctrl/iparams', 'iffffffff')
  344. def carla_iparams(self, path, args):
  345. if DEBUG: print(path, args)
  346. self.fReceivedMsgs = True
  347. pluginId, active, drywet, volume, balLeft, balRight, pan, ctrlChan, forth = args
  348. self.host._set_internalValue(pluginId, PARAMETER_ACTIVE, active)
  349. self.host._set_internalValue(pluginId, PARAMETER_DRYWET, drywet)
  350. self.host._set_internalValue(pluginId, PARAMETER_VOLUME, volume)
  351. self.host._set_internalValue(pluginId, PARAMETER_BALANCE_LEFT, balLeft)
  352. self.host._set_internalValue(pluginId, PARAMETER_BALANCE_RIGHT, balRight)
  353. self.host._set_internalValue(pluginId, PARAMETER_PANNING, pan)
  354. self.host._set_internalValue(pluginId, PARAMETER_FORTH, forth)
  355. self.host._set_internalValue(pluginId, PARAMETER_CTRL_CHANNEL, ctrlChan)
  356. @make_method('/ctrl/resp', 'is')
  357. def carla_resp(self, path, args):
  358. if DEBUG: print(path, args)
  359. self.fReceivedMsgs = True
  360. messageId, error = args
  361. self.host.responses[messageId] = error
  362. self.host.pendingMessages.remove(messageId)
  363. @make_method('/ctrl/exit', '')
  364. def carla_exit(self, path, args):
  365. if DEBUG: print(path, args)
  366. self.fReceivedMsgs = True
  367. #self.host.lo_target_tcp = None
  368. self.host.QuitCallback.emit()
  369. @make_method('/ctrl/exit-error', 's')
  370. def carla_exit_error(self, path, args):
  371. if DEBUG: print(path, args)
  372. self.fReceivedMsgs = True
  373. error, = args
  374. self.host.lo_target_tcp = None
  375. self.host.QuitCallback.emit()
  376. self.host.ErrorCallback.emit(error)
  377. @make_method(None, None)
  378. def fallback(self, path, args):
  379. print("ControlServerTCP::fallback(\"%s\") - unknown message, args =" % path, args)
  380. self.fReceivedMsgs = True
  381. # ---------------------------------------------------------------------------------------------------------------------
  382. class CarlaControlServerUDP(Server):
  383. def __init__(self, host):
  384. Server.__init__(self, proto=LO_UDP)
  385. if False:
  386. host = CarlaHostOSC()
  387. self.host = host
  388. def idle(self):
  389. self.fReceivedMsgs = False
  390. while self.recv(0) and self.fReceivedMsgs:
  391. pass
  392. def getFullURL(self):
  393. return "%sctrl" % self.get_url()
  394. @make_method('/ctrl/runtime', 'fiihiiif')
  395. def carla_runtime(self, path, args):
  396. self.fReceivedMsgs = True
  397. load, xruns, playing, frame, bar, beat, tick, bpm = args
  398. self.host._set_runtime_info(load, xruns)
  399. self.host._set_transport(bool(playing), frame, bar, beat, tick, bpm)
  400. @make_method('/ctrl/param', 'iif')
  401. def carla_param_fixme(self, path, args):
  402. self.fReceivedMsgs = True
  403. pluginId, paramId, paramValue = args
  404. self.host._set_parameterValue(pluginId, paramId, paramValue)
  405. @make_method('/ctrl/peaks', 'iffff')
  406. def carla_peaks(self, path, args):
  407. self.fReceivedMsgs = True
  408. pluginId, in1, in2, out1, out2 = args
  409. self.host._set_peaks(pluginId, in1, in2, out1, out2)
  410. @make_method(None, None)
  411. def fallback(self, path, args):
  412. print("ControlServerUDP::fallback(\"%s\") - unknown message, args =" % path, args)
  413. self.fReceivedMsgs = True
  414. # ---------------------------------------------------------------------------------------------------------------------
  415. # Main Window
  416. class HostWindowOSC(HostWindow):
  417. def __init__(self, host, oscAddr = None):
  418. self.fCustomOscAddress = oscAddr
  419. HostWindow.__init__(self, host, True)
  420. self.host = host
  421. if False:
  422. # kdevelop likes this :)
  423. host = CarlaHostOSC()
  424. self.host = host
  425. # ----------------------------------------------------------------------------------------------------
  426. # Connect actions to functions
  427. self.ui.act_file_connect.triggered.connect(self.slot_fileConnect)
  428. self.ui.act_file_refresh.triggered.connect(self.slot_fileRefresh)
  429. # ----------------------------------------------------------------------------------------------------
  430. # Final setup
  431. if oscAddr:
  432. QTimer.singleShot(0, self.connectOsc)
  433. def connectOsc(self, addrTCP = None, addrUDP = None):
  434. if self.fCustomOscAddress is not None:
  435. addrTCP = self.fCustomOscAddress.replace("osc.udp://","osc.tcp://")
  436. addrUDP = self.fCustomOscAddress.replace("osc.tcp://","osc.udp://")
  437. else:
  438. if addrTCP is not None:
  439. self.fOscAddressTCP = addrTCP
  440. if addrUDP is not None:
  441. self.fOscAddressUDP = addrUDP
  442. lo_target_tcp_name = addrTCP.rsplit("/", 1)[-1]
  443. lo_target_udp_name = addrUDP.rsplit("/", 1)[-1]
  444. err = None
  445. try:
  446. lo_target_tcp = Address(addrTCP)
  447. lo_server_tcp = CarlaControlServerTCP(self.host)
  448. lo_send(lo_target_tcp, "/register", lo_server_tcp.getFullURL())
  449. lo_target_udp = Address(addrUDP)
  450. lo_server_udp = CarlaControlServerUDP(self.host)
  451. lo_send(lo_target_udp, "/register", lo_server_udp.getFullURL())
  452. except AddressError as e:
  453. err = e
  454. except OSError as e:
  455. err = e
  456. except:
  457. err = Exception()
  458. if err is not None:
  459. fullError = self.tr("Failed to connect to the Carla instance.")
  460. if len(err.args) > 0:
  461. fullError += " %s\n%s\n" % (self.tr("Error was:"), err.args[0])
  462. fullError += "\n"
  463. fullError += self.tr("Make sure the remote Carla is running and the URL and Port are correct.") + "\n"
  464. fullError += self.tr("If it still does not work, check your current device and the remote's firewall.")
  465. CustomMessageBox(self,
  466. QMessageBox.Warning,
  467. self.tr("Error"),
  468. self.tr("Connection failed"),
  469. fullError,
  470. QMessageBox.Ok,
  471. QMessageBox.Ok)
  472. return
  473. self.host.lo_server_tcp = lo_server_tcp
  474. self.host.lo_target_tcp = lo_target_tcp
  475. self.host.lo_target_tcp_name = lo_target_tcp_name
  476. self.host.lo_server_udp = lo_server_udp
  477. self.host.lo_target_udp = lo_target_udp
  478. self.host.lo_target_udp_name = lo_target_udp_name
  479. self.ui.act_file_refresh.setEnabled(True)
  480. self.startTimers()
  481. def disconnectOsc(self):
  482. self.killTimers()
  483. self.unregister()
  484. self.removeAllPlugins()
  485. patchcanvas.clear()
  486. self.ui.act_file_refresh.setEnabled(False)
  487. # --------------------------------------------------------------------------------------------------------
  488. def unregister(self):
  489. if self.host.lo_server_tcp is not None:
  490. if self.host.lo_target_tcp is not None:
  491. try:
  492. lo_send(self.host.lo_target_tcp, "/unregister", self.host.lo_server_tcp.getFullURL())
  493. except:
  494. pass
  495. self.host.lo_target_tcp = None
  496. while self.host.lo_server_tcp.recv(0):
  497. pass
  498. #self.host.lo_server_tcp.free()
  499. self.host.lo_server_tcp = None
  500. if self.host.lo_server_udp is not None:
  501. if self.host.lo_target_udp is not None:
  502. try:
  503. lo_send(self.host.lo_target_udp, "/unregister", self.host.lo_server_udp.getFullURL())
  504. except:
  505. pass
  506. self.host.lo_target_udp = None
  507. while self.host.lo_server_udp.recv(0):
  508. pass
  509. #self.host.lo_server_udp.free()
  510. self.host.lo_server_udp = None
  511. self.host.lo_target_tcp_name = ""
  512. self.host.lo_target_udp_name = ""
  513. # --------------------------------------------------------------------------------------------------------
  514. # Timers
  515. def idleFast(self):
  516. HostWindow.idleFast(self)
  517. if self.host.lo_server_tcp is not None:
  518. self.host.lo_server_tcp.idle()
  519. else:
  520. self.disconnectOsc()
  521. if self.host.lo_server_udp is not None:
  522. self.host.lo_server_udp.idle()
  523. else:
  524. self.disconnectOsc()
  525. # --------------------------------------------------------------------------------------------------------
  526. def removeAllPlugins(self):
  527. self.host.fPluginsInfo = {}
  528. HostWindow.removeAllPlugins(self)
  529. # --------------------------------------------------------------------------------------------------------
  530. def loadSettings(self, firstTime):
  531. settings = HostWindow.loadSettings(self, firstTime)
  532. if self.fCustomOscAddress is not None:
  533. self.fOscAddressTCP = settings.value("RemoteAddressTCP", "osc.tcp://127.0.0.1:22752/Carla", str)
  534. self.fOscAddressUDP = settings.value("RemoteAddressUDP", "osc.udp://127.0.0.1:22752/Carla", str)
  535. def saveSettings(self):
  536. settings = HostWindow.saveSettings(self)
  537. if self.fOscAddressTCP:
  538. settings.setValue("RemoteAddressTCP", self.fOscAddressTCP)
  539. if self.fOscAddressUDP:
  540. settings.setValue("RemoteAddressUDP", self.fOscAddressUDP)
  541. # --------------------------------------------------------------------------------------------------------
  542. @pyqtSlot()
  543. def slot_fileConnect(self):
  544. dialog = ConnectDialog(self)
  545. if not dialog.exec_():
  546. return
  547. host, tcpPort, udpPort = dialog.getResult()
  548. self.disconnectOsc()
  549. self.connectOsc("osc.tcp://%s:%i/Carla" % (host, tcpPort),
  550. "osc.udp://%s:%i/Carla" % (host, udpPort))
  551. @pyqtSlot()
  552. def slot_fileRefresh(self):
  553. if None in (self.host.lo_server_tcp, self.host.lo_server_udp, self.host.lo_target_tcp, self.host.lo_target_udp):
  554. return
  555. lo_send(self.host.lo_target_udp, "/unregister", self.host.lo_server_udp.getFullURL())
  556. while self.host.lo_server_udp.recv(0):
  557. pass
  558. #self.host.lo_server_udp.free()
  559. lo_send(self.host.lo_target_tcp, "/unregister", self.host.lo_server_tcp.getFullURL())
  560. while self.host.lo_server_tcp.recv(0):
  561. pass
  562. #self.host.lo_server_tcp.free()
  563. self.removeAllPlugins()
  564. patchcanvas.clear()
  565. self.host.lo_server_tcp = CarlaControlServerTCP(self.host)
  566. self.host.lo_server_udp = CarlaControlServerUDP(self.host)
  567. try:
  568. lo_send(self.host.lo_target_tcp, "/register", self.host.lo_server_tcp.getFullURL())
  569. except:
  570. self.disconnectOsc()
  571. return
  572. try:
  573. lo_send(self.host.lo_target_udp, "/register", self.host.lo_server_udp.getFullURL())
  574. except:
  575. self.disconnectOsc()
  576. return
  577. # --------------------------------------------------------------------------------------------------------
  578. @pyqtSlot()
  579. def slot_handleSIGTERM(self):
  580. print("Got SIGTERM -> Closing now")
  581. self.host.pendingMessages = []
  582. self.close()
  583. @pyqtSlot()
  584. def slot_handleQuitCallback(self):
  585. self.disconnectOsc()
  586. HostWindow.slot_handleQuitCallback(self)
  587. # --------------------------------------------------------------------------------------------------------
  588. def closeEvent(self, event):
  589. self.killTimers()
  590. self.unregister()
  591. HostWindow.closeEvent(self, event)
  592. # ------------------------------------------------------------------------------------------------------------