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.

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