Collection of tools useful for audio production
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.

1349 lines
51KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # JACK Patchbay
  4. # Copyright (C) 2010-2012 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # Imports (Global)
  18. from PyQt4.QtCore import QSettings
  19. from PyQt4.QtGui import QApplication, QMainWindow
  20. # Imports (Custom Stuff)
  21. import ui_catia
  22. from shared_jack import *
  23. from shared_canvas import *
  24. from shared_settings import *
  25. try:
  26. from PyQt4.QtOpenGL import QGLWidget
  27. hasGL = True
  28. except:
  29. hasGL = False
  30. try:
  31. import dbus
  32. from dbus.mainloop.qt import DBusQtMainLoop
  33. haveDBus = True
  34. except:
  35. haveDBus = False
  36. # Disabled for Beta
  37. if LINUX and False:
  38. for iPATH in PATH:
  39. if os.path.exists(os.path.join(iPATH, "aconnect")):
  40. from subprocess import getoutput
  41. haveALSA = True
  42. print("Using experimental ALSA-MIDI support")
  43. break
  44. else:
  45. haveALSA = False
  46. else:
  47. haveALSA = False
  48. global a2j_client_name
  49. a2j_client_name = None
  50. GROUP_TYPE_NULL = 0
  51. GROUP_TYPE_ALSA = 1
  52. GROUP_TYPE_JACK = 2
  53. iGroupId = 0
  54. iGroupName = 1
  55. iGroupType = 2
  56. iPortId = 0
  57. iPortName = 1
  58. iPortNameR = 2
  59. iPortGroupName = 3
  60. iConnId = 0
  61. iConnOutput = 1
  62. iConnInput = 2
  63. # Main Window
  64. class CatiaMainW(QMainWindow, ui_catia.Ui_CatiaMainW):
  65. def __init__(self, parent=None):
  66. QMainWindow.__init__(self, parent)
  67. self.setupUi(self)
  68. self.settings = QSettings("Cadence", "Catia")
  69. self.loadSettings(True)
  70. setIcons(self, ["canvas", "jack", "transport", "misc"])
  71. self.act_quit.setIcon(getIcon("application-exit"))
  72. self.act_configure.setIcon(getIcon("configure"))
  73. self.m_group_list = []
  74. self.m_group_split_list = []
  75. self.m_port_list = []
  76. self.m_connection_list = []
  77. self.m_last_group_id = 1
  78. self.m_last_port_id = 1
  79. self.m_last_connection_id = 1
  80. self.m_xruns = 0
  81. self.m_buffer_size = 0
  82. self.m_sample_rate = 0
  83. self.m_next_sample_rate = 0
  84. self.m_last_bpm = None
  85. self.m_last_transport_state = None
  86. self.cb_buffer_size.clear()
  87. self.cb_sample_rate.clear()
  88. for buffer_size in buffer_sizes:
  89. self.cb_buffer_size.addItem(str(buffer_size))
  90. for sample_rate in sample_rates:
  91. self.cb_sample_rate.addItem(str(sample_rate))
  92. self.act_jack_bf_list = (self.act_jack_bf_16, self.act_jack_bf_32, self.act_jack_bf_64, self.act_jack_bf_128,
  93. self.act_jack_bf_256, self.act_jack_bf_512, self.act_jack_bf_1024, self.act_jack_bf_2048,
  94. self.act_jack_bf_4096, self.act_jack_bf_8192)
  95. self.scene = patchcanvas.PatchScene(self, self.graphicsView)
  96. self.graphicsView.setScene(self.scene)
  97. self.graphicsView.setRenderHint(QPainter.Antialiasing, bool(self.m_savedSettings["Canvas/Antialiasing"] == patchcanvas.ANTIALIASING_FULL))
  98. self.graphicsView.setRenderHint(QPainter.TextAntialiasing, self.m_savedSettings["Canvas/TextAntialiasing"])
  99. if self.m_savedSettings["Canvas/UseOpenGL"] and hasGL:
  100. self.graphicsView.setViewport(QGLWidget(self.graphicsView))
  101. self.graphicsView.setRenderHint(QPainter.HighQualityAntialiasing, self.m_savedSettings["Canvas/HighQualityAntialiasing"])
  102. p_options = patchcanvas.options_t()
  103. p_options.theme_name = self.m_savedSettings["Canvas/Theme"]
  104. p_options.auto_hide_groups = self.m_savedSettings["Canvas/AutoHideGroups"]
  105. p_options.use_bezier_lines = self.m_savedSettings["Canvas/UseBezierLines"]
  106. p_options.antialiasing = self.m_savedSettings["Canvas/Antialiasing"]
  107. p_options.eyecandy = self.m_savedSettings["Canvas/EyeCandy"]
  108. p_features = patchcanvas.features_t()
  109. p_features.group_info = False
  110. p_features.group_rename = False
  111. p_features.port_info = True
  112. p_features.port_rename = bool(self.m_savedSettings["Main/JackPortAlias"] > 0)
  113. p_features.handle_group_pos = True
  114. patchcanvas.setOptions(p_options)
  115. patchcanvas.setFeatures(p_features)
  116. patchcanvas.init("Catia", self.scene, self.canvasCallback, DEBUG)
  117. # Try to connect to jack
  118. if self.jackStarted():
  119. self.init_alsa_ports()
  120. # DBus checks
  121. if haveDBus:
  122. if DBus.jack:
  123. pass
  124. else:
  125. self.act_tools_jack_start.setEnabled(False)
  126. self.act_tools_jack_stop.setEnabled(False)
  127. self.act_jack_configure.setEnabled(False)
  128. self.b_jack_configure.setEnabled(False)
  129. if DBus.a2j:
  130. if DBus.a2j.is_started():
  131. self.a2jStarted()
  132. else:
  133. self.a2jStopped()
  134. else:
  135. self.act_tools_a2j_start.setEnabled(False)
  136. self.act_tools_a2j_stop.setEnabled(False)
  137. self.act_tools_a2j_export_hw.setEnabled(False)
  138. self.menu_A2J_Bridge.setEnabled(False)
  139. else:
  140. # No DBus
  141. self.act_tools_jack_start.setEnabled(False)
  142. self.act_tools_jack_stop.setEnabled(False)
  143. self.act_jack_configure.setEnabled(False)
  144. self.b_jack_configure.setEnabled(False)
  145. self.act_tools_a2j_start.setEnabled(False)
  146. self.act_tools_a2j_stop.setEnabled(False)
  147. self.act_tools_a2j_export_hw.setEnabled(False)
  148. self.menu_A2J_Bridge.setEnabled(False)
  149. self.m_timer120 = self.startTimer(self.m_savedSettings["Main/RefreshInterval"])
  150. self.m_timer600 = self.startTimer(self.m_savedSettings["Main/RefreshInterval"] * 5)
  151. setCanvasConnections(self)
  152. setJackConnections(self, ["jack", "buffer-size", "transport", "misc"])
  153. self.connect(self.act_tools_jack_start, SIGNAL("triggered()"), SLOT("slot_JackServerStart()"))
  154. self.connect(self.act_tools_jack_stop, SIGNAL("triggered()"), SLOT("slot_JackServerStop()"))
  155. self.connect(self.act_tools_a2j_start, SIGNAL("triggered()"), SLOT("slot_A2JBridgeStart()"))
  156. self.connect(self.act_tools_a2j_stop, SIGNAL("triggered()"), SLOT("slot_A2JBridgeStop()"))
  157. self.connect(self.act_tools_a2j_export_hw, SIGNAL("triggered()"), SLOT("slot_A2JBridgeExportHW()"))
  158. self.connect(self.act_configure, SIGNAL("triggered()"), SLOT("slot_configureCatia()"))
  159. self.connect(self.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCatia()"))
  160. self.connect(self.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  161. self.connect(self, SIGNAL("XRunCallback()"), SLOT("slot_XRunCallback()"))
  162. self.connect(self, SIGNAL("BufferSizeCallback(int)"), SLOT("slot_BufferSizeCallback(int)"))
  163. self.connect(self, SIGNAL("SampleRateCallback(int)"), SLOT("slot_SampleRateCallback(int)"))
  164. self.connect(self, SIGNAL("PortRegistrationCallback(int, bool)"), SLOT("slot_PortRegistrationCallback(int, bool)"))
  165. self.connect(self, SIGNAL("PortConnectCallback(int, int, bool)"), SLOT("slot_PortConnectCallback(int, int, bool)"))
  166. self.connect(self, SIGNAL("PortRenameCallback(int, QString, QString)"), SLOT("slot_PortRenameCallback(int, QString, QString)"))
  167. self.connect(self, SIGNAL("ShutdownCallback()"), SLOT("slot_ShutdownCallback()"))
  168. if DBus.jack or DBus.a2j:
  169. DBus.bus.add_signal_receiver(self.DBusSignalReceiver, destination_keyword='dest', path_keyword='path',
  170. member_keyword='member', interface_keyword='interface', sender_keyword='sender', )
  171. def canvasCallback(self, action, value1, value2, value_str):
  172. if action == patchcanvas.ACTION_GROUP_INFO:
  173. pass
  174. elif action == patchcanvas.ACTION_GROUP_RENAME:
  175. pass
  176. elif action == patchcanvas.ACTION_GROUP_SPLIT:
  177. group_id = value1
  178. patchcanvas.splitGroup(group_id)
  179. elif action == patchcanvas.ACTION_GROUP_JOIN:
  180. group_id = value1
  181. patchcanvas.joinGroup(group_id)
  182. elif action == patchcanvas.ACTION_PORT_INFO:
  183. port_id = value1
  184. for port in self.m_port_list:
  185. if port[iPortId] == port_id:
  186. port_nameR = port[iPortNameR]
  187. port_nameG = port[iPortGroupName]
  188. break
  189. else:
  190. return
  191. if port_nameR.startswith("[ALSA-"):
  192. port_id, port_name = port_nameR.split("] ", 1)[1].split(" ", 1)
  193. flags = []
  194. if port_nameR.startswith("[ALSA-Input] "):
  195. flags.append(self.tr("Input"))
  196. elif port_nameR.startswith("[ALSA-Output] "):
  197. flags.append(self.tr("Output"))
  198. flags_text = " | ".join(flags)
  199. type_text = self.tr("ALSA MIDI")
  200. info = self.tr(""
  201. "<table>"
  202. "<tr><td align='right'><b>Group Name:</b></td><td>&nbsp;%s</td></tr>"
  203. "<tr><td align='right'><b>Port Id:</b></td><td>&nbsp;%s</td></tr>"
  204. "<tr><td align='right'><b>Port Name:</b></td><td>&nbsp;%s</td></tr>"
  205. "<tr><td colspan='2'>&nbsp;</td></tr>"
  206. "<tr><td align='right'><b>Port Flags:</b></td><td>&nbsp;%s</td></tr>"
  207. "<tr><td align='right'><b>Port Type:</b></td><td>&nbsp;%s</td></tr>"
  208. "</table>" % (port_nameG, port_id, port_name, flags_text, type_text))
  209. else:
  210. port_ptr = jacklib.port_by_name(jack.client, port_nameR)
  211. port_flags = jacklib.port_flags(port_ptr)
  212. group_name = port_nameR.split(":", 1)[0]
  213. port_short_name = str(jacklib.port_short_name(port_ptr), encoding="utf-8")
  214. aliases = jacklib.port_get_aliases(port_ptr)
  215. if aliases[0] == 1:
  216. alias1text = aliases[1]
  217. alias2text = "(none)"
  218. elif aliases[0] == 2:
  219. alias1text = aliases[1]
  220. alias2text = aliases[2]
  221. else:
  222. alias1text = "(none)"
  223. alias2text = "(none)"
  224. flags = []
  225. if port_flags & jacklib.JackPortIsInput:
  226. flags.append(self.tr("Input"))
  227. if port_flags & jacklib.JackPortIsOutput:
  228. flags.append(self.tr("Output"))
  229. if port_flags & jacklib.JackPortIsPhysical:
  230. flags.append(self.tr("Physical"))
  231. if port_flags & jacklib.JackPortCanMonitor:
  232. flags.append(self.tr("Can Monitor"))
  233. if port_flags & jacklib.JackPortIsTerminal:
  234. flags.append(self.tr("Terminal"))
  235. flags_text = " | ".join(flags)
  236. port_type_str = str(jacklib.port_type(port_ptr), encoding="utf-8")
  237. if port_type_str == jacklib.JACK_DEFAULT_AUDIO_TYPE:
  238. type_text = self.tr("JACK Audio")
  239. elif port_type_str == jacklib.JACK_DEFAULT_MIDI_TYPE:
  240. type_text = self.tr("JACK MIDI")
  241. else:
  242. type_text = self.tr("Unknown")
  243. port_latency = jacklib.port_get_latency(port_ptr)
  244. port_total_latency = jacklib.port_get_total_latency(jack.client, port_ptr)
  245. latency_text = self.tr("%.1f ms (%i frames)" % (port_latency * 1000 / self.m_sample_rate, port_latency))
  246. latency_total_text = self.tr("%.1f ms (%i frames)" % (port_total_latency * 1000 / self.m_sample_rate, port_total_latency))
  247. info = self.tr(""
  248. "<table>"
  249. "<tr><td align='right'><b>Group Name:</b></td><td>&nbsp;%s</td></tr>"
  250. "<tr><td align='right'><b>Port Name:</b></td><td>&nbsp;%s</td></tr>"
  251. "<tr><td align='right'><b>Full Port Name:</b></td><td>&nbsp;%s</td></tr>"
  252. "<tr><td align='right'><b>Port Alias #1:</b></td><td>&nbsp;%s</td></tr>"
  253. "<tr><td align='right'><b>Port Alias #2:</b></td><td>&nbsp;%s</td></tr>"
  254. "<tr><td colspan='2'>&nbsp;</td></tr>"
  255. "<tr><td align='right'><b>Port Flags:</b></td><td>&nbsp;%s</td></tr>"
  256. "<tr><td align='right'><b>Port Type:</b></td><td>&nbsp;%s</td></tr>"
  257. "<tr><td colspan='2'>&nbsp;</td></tr>"
  258. "<tr><td align='right'><b>Port Latency:</b></td><td>&nbsp;%s</td></tr>"
  259. "<tr><td align='right'><b>Total Port Latency:</b></td><td>&nbsp;%s</td></tr>"
  260. "</table>" % (group_name, port_short_name, port_nameR, alias1text, alias2text, flags_text, type_text, latency_text, latency_total_text))
  261. QMessageBox.information(self, self.tr("Port Information"), info)
  262. elif action == patchcanvas.ACTION_PORT_RENAME:
  263. global a2j_client_name
  264. port_id = value1
  265. port_short_name = asciiString(value_str)
  266. for port in self.m_port_list:
  267. if port[iPortId] == port_id:
  268. port_nameR = port[iPortNameR]
  269. if port_nameR.startswith("[ALSA-"):
  270. QMessageBox.warning(self, self.tr("Cannot continue"), self.tr("Rename functions rely on JACK aliases and cannot be done in ALSA ports"))
  271. return
  272. if port_nameR.split(":", 1)[0] == a2j_client_name:
  273. a2j_split = port_nameR.split(":", 3)
  274. port_name = "%s:%s: %s" % (a2j_split[0], a2j_split[1], port_short_name)
  275. else:
  276. port_name = "%s:%s" % (port[iPortGroupName], port_short_name)
  277. break
  278. else:
  279. return
  280. port_ptr = jacklib.port_by_name(jack.client, port_nameR)
  281. aliases = jacklib.port_get_aliases(port_ptr)
  282. if aliases[0] == 2:
  283. # JACK only allows 2 aliases, remove 2nd
  284. jacklib.port_unset_alias(port_ptr, aliases[2])
  285. # If we're going for 1st alias, unset it too
  286. if self.m_savedSettings["Main/JackPortAlias"] == 1:
  287. jacklib.port_unset_alias(port_ptr, aliases[1])
  288. elif aliases[0] == 1 and self.m_savedSettings["Main/JackPortAlias"] == 1:
  289. jacklib.port_unset_alias(port_ptr, aliases[1])
  290. if aliases[0] == 0 and self.m_savedSettings["Main/JackPortAlias"] == 2:
  291. # If 2nd alias is enabled and port had no previous aliases, set the 1st alias now
  292. jacklib.port_set_alias(port_ptr, port_name)
  293. if jacklib.port_set_alias(port_ptr, port_name) == 0:
  294. patchcanvas.renamePort(port_id, port_short_name)
  295. elif action == patchcanvas.ACTION_PORTS_CONNECT:
  296. port_a_id = value1
  297. port_b_id = value2
  298. port_a_nameR = ""
  299. port_b_nameR = ""
  300. for port in self.m_port_list:
  301. if port[iPortId] == port_a_id:
  302. port_a_nameR = port[iPortNameR]
  303. if port[iPortId] == port_b_id:
  304. port_b_nameR = port[iPortNameR]
  305. if port_a_nameR.startswith("[ALSA-"):
  306. port_a_alsa_id = port_a_nameR.split(" ", 2)[1]
  307. port_b_alsa_id = port_b_nameR.split(" ", 2)[1]
  308. if os.system("aconnect %s %s" % (port_a_alsa_id, port_b_alsa_id)) == 0:
  309. self.canvas_connect_ports(port_a_id, port_b_id)
  310. elif port_a_nameR and port_b_nameR:
  311. jacklib.connect(jack.client, port_a_nameR, port_b_nameR)
  312. elif action == patchcanvas.ACTION_PORTS_DISCONNECT:
  313. connection_id = value1
  314. for connection in self.m_connection_list:
  315. if connection[iConnId] == connection_id:
  316. port_a_id = connection[iConnOutput]
  317. port_b_id = connection[iConnInput]
  318. break
  319. else:
  320. return
  321. port_a_nameR = ""
  322. port_b_nameR = ""
  323. for port in self.m_port_list:
  324. if port[iPortId] == port_a_id:
  325. port_a_nameR = port[iPortNameR]
  326. if port[iPortId] == port_b_id:
  327. port_b_nameR = port[iPortNameR]
  328. if port_a_nameR.startswith("[ALSA-"):
  329. port_a_alsa_id = port_a_nameR.split(" ", 2)[1]
  330. port_b_alsa_id = port_b_nameR.split(" ", 2)[1]
  331. if os.system("aconnect -d %s %s" % (port_a_alsa_id, port_b_alsa_id)) == 0:
  332. self.canvas_disconnect_ports(port_a_id, port_b_id)
  333. elif port_a_nameR and port_b_nameR:
  334. jacklib.disconnect(jack.client, port_a_nameR, port_b_nameR)
  335. def init_ports(self):
  336. self.m_group_list = []
  337. self.m_group_split_list = []
  338. self.m_port_list = []
  339. self.m_connection_list = []
  340. self.m_last_group_id = 1
  341. self.m_last_port_id = 1
  342. self.m_last_connection_id = 1
  343. self.init_jack_ports()
  344. self.init_alsa_ports()
  345. def init_jack(self):
  346. self.m_xruns = 0
  347. self.m_next_sample_rate = 0
  348. self.m_last_bpm = None
  349. self.m_last_transport_state = None
  350. buffer_size = int(jacklib.get_buffer_size(jack.client))
  351. sample_rate = int(jacklib.get_sample_rate(jack.client))
  352. realtime = bool(int(jacklib.is_realtime(jack.client)))
  353. setBufferSize(self, buffer_size)
  354. setSampleRate(self, sample_rate)
  355. setRealTime(self, realtime)
  356. setXruns(self, 0)
  357. refreshDSPLoad(self)
  358. refreshTransport(self)
  359. self.init_jack_callbacks()
  360. self.init_jack_ports()
  361. self.scene.zoom_fit()
  362. self.scene.zoom_reset()
  363. jacklib.activate(jack.client)
  364. def init_jack_callbacks(self):
  365. jacklib.set_buffer_size_callback(jack.client, self.JackBufferSizeCallback, None)
  366. jacklib.set_sample_rate_callback(jack.client, self.JackSampleRateCallback, None)
  367. jacklib.set_xrun_callback(jack.client, self.JackXRunCallback, None)
  368. jacklib.set_port_registration_callback(jack.client, self.JackPortRegistrationCallback, None)
  369. jacklib.set_port_connect_callback(jack.client, self.JackPortConnectCallback, None)
  370. jacklib.set_session_callback(jack.client, self.JackSessionCallback, None)
  371. jacklib.on_shutdown(jack.client, self.JackShutdownCallback, None)
  372. if jacklib.JACK2:
  373. jacklib.set_port_rename_callback(jack.client, self.JackPortRenameCallback, None)
  374. def init_jack_ports(self):
  375. if not jack.client:
  376. return
  377. # Get all jack ports, put a2j ones to the bottom of the list
  378. a2j_name_list = []
  379. port_name_list = c_char_p_p_to_list(jacklib.get_ports(jack.client, "", "", 0))
  380. global a2j_client_name
  381. h = 0
  382. for i in range(len(port_name_list)):
  383. if port_name_list[i - h].split(":")[0] == a2j_client_name:
  384. port_name = port_name_list.pop(i - h)
  385. a2j_name_list.append(port_name)
  386. h += 1
  387. for a2j_name in a2j_name_list:
  388. port_name_list.append(a2j_name)
  389. del a2j_name_list
  390. # Add jack ports
  391. for port_name in port_name_list:
  392. port_ptr = jacklib.port_by_name(jack.client, port_name)
  393. self.canvas_add_jack_port(port_ptr, port_name)
  394. # Add jack connections
  395. for port_name in port_name_list:
  396. port_ptr = jacklib.port_by_name(jack.client, port_name)
  397. # Only make connections from an output port
  398. if jacklib.port_flags(port_ptr) & jacklib.JackPortIsInput:
  399. continue
  400. port_connection_names = c_char_p_p_to_list(jacklib.port_get_all_connections(jack.client, port_ptr))
  401. for port_con_name in port_connection_names:
  402. self.canvas_connect_ports_by_name(port_name, port_con_name)
  403. def init_alsa_ports(self):
  404. if not haveALSA:
  405. return
  406. # Get ALSA MIDI ports (outputs)
  407. output = getoutput("env LANG=C aconnect -i").split("\n")
  408. last_group_id = -1
  409. last_group_name = ""
  410. for line in output:
  411. # Make 'System' match JACK's 'system'
  412. if line == "client 0: 'System' [type=kernel]":
  413. line = "client 0: 'system' [type=kernel]"
  414. if line.startswith("client "):
  415. lineSplit = line.split(": ", 1)
  416. lineSplit2 = lineSplit[1].replace("'", "", 1).split("' [type=", 1)
  417. group_id = int(lineSplit[0].replace("client ", ""))
  418. group_name = lineSplit2[0]
  419. group_type = lineSplit2[1].rsplit("]", 1)[0]
  420. last_group_id = self.get_group_id(group_name)
  421. if last_group_id == -1:
  422. # Group doesn't exist yet
  423. last_group_id = self.canvas_add_alsa_group(group_id, group_name, bool(group_type == "kernel"))
  424. last_group_name = group_name
  425. elif line.startswith(" ") and last_group_id >= 0 and last_group_name:
  426. lineSplit = line.split(" '", 1)
  427. port_id = int(lineSplit[0].strip())
  428. port_name = lineSplit[1].rsplit("'", 1)[0].strip()
  429. self.canvas_add_alsa_port(last_group_id, last_group_name, port_name, "%i:%i %s" % (group_id, port_id, port_name), False)
  430. else:
  431. last_group_id = -1
  432. last_group_name = ""
  433. # Get ALSA MIDI ports (inputs)
  434. output = getoutput("env LANG=C aconnect -o").split("\n")
  435. last_group_id = -1
  436. last_group_name = ""
  437. for line in output:
  438. # Make 'System' match JACK's 'system'
  439. if line == "client 0: 'System' [type=kernel]":
  440. line = "client 0: 'system' [type=kernel]"
  441. if line.startswith("client "):
  442. lineSplit = line.split(": ", 1)
  443. lineSplit2 = lineSplit[1].replace("'", "", 1).split("' [type=", 1)
  444. group_id = int(lineSplit[0].replace("client ", ""))
  445. group_name = lineSplit2[0]
  446. group_type = lineSplit2[1].rsplit("]", 1)[0]
  447. last_group_id = self.get_group_id(group_name)
  448. if last_group_id == -1:
  449. # Group doesn't exist yet
  450. last_group_id = self.canvas_add_alsa_group(group_id, group_name, bool(group_type == "kernel"))
  451. last_group_name = group_name
  452. elif line.startswith(" ") and last_group_id >= 0 and last_group_name:
  453. lineSplit = line.split(" '", 1)
  454. port_id = int(lineSplit[0].strip())
  455. port_name = lineSplit[1].rsplit("'", 1)[0].strip()
  456. self.canvas_add_alsa_port(last_group_id, last_group_name, port_name, "%i:%i %s" % (group_id, port_id, port_name), True)
  457. else:
  458. last_group_id = -1
  459. last_group_name = ""
  460. # Get ALSA MIDI connections
  461. output = getoutput("env LANG=C aconnect -ol").split("\n")
  462. last_group_id = -1
  463. last_port_id = -1
  464. for line in output:
  465. # Make 'System' match JACK's 'system'
  466. if line == "client 0: 'System' [type=kernel]":
  467. line = "client 0: 'system' [type=kernel]"
  468. if line.startswith("client "):
  469. lineSplit = line.split(": ", 1)
  470. lineSplit2 = lineSplit[1].replace("'", "", 1).split("' [type=", 1)
  471. group_id = int(lineSplit[0].replace("client ", ""))
  472. group_name = lineSplit2[0]
  473. last_group_id = self.get_group_id(group_name)
  474. elif line.startswith(" ") and last_group_id >= 0:
  475. lineSplit = line.split(" '", 1)
  476. port_id = int(lineSplit[0].strip())
  477. port_name = lineSplit[1].rsplit("'", 1)[0].strip()
  478. for port in self.m_port_list:
  479. if port[iPortNameR] == "[ALSA-Input] %i:%i %s" % (group_id, port_id, port_name):
  480. last_port_id = port[iPortId]
  481. break
  482. else:
  483. last_port_id = -1
  484. elif line.startswith("\tConnect") and last_group_id >= 0 and last_port_id >= 0:
  485. if line.startswith("\tConnected From"):
  486. lineSplit = line.split(": ", 1)[1]
  487. lineConns = lineSplit.split(", ")
  488. for lineConn in lineConns:
  489. lineConnSplit = lineConn.replace("'","").split(":", 1)
  490. alsa_group_id = int(lineConnSplit[0])
  491. alsa_port_id = int(lineConnSplit[1])
  492. portNameRtest = "[ALSA-Output] %i:%i " % (alsa_group_id, alsa_port_id)
  493. for port in self.m_port_list:
  494. if port[iPortNameR].startswith(portNameRtest):
  495. self.canvas_connect_ports(port[iPortId], last_port_id)
  496. break
  497. else:
  498. last_group_id = -1
  499. last_port_id = -1
  500. def get_group_id(self, group_name):
  501. for group in self.m_group_list:
  502. if group[iGroupName] == group_name:
  503. return group[iGroupId]
  504. return -1
  505. def canvas_add_alsa_group(self, alsa_group_id, group_name, hw_split):
  506. group_id = self.m_last_group_id
  507. if hw_split:
  508. patchcanvas.addGroup(group_id, group_name, patchcanvas.SPLIT_YES, patchcanvas.ICON_HARDWARE)
  509. else:
  510. patchcanvas.addGroup(group_id, group_name)
  511. group_obj = [None, None, None]
  512. group_obj[iGroupId] = group_id
  513. group_obj[iGroupName] = group_name
  514. group_obj[iGroupType] = GROUP_TYPE_ALSA
  515. self.m_group_list.append(group_obj)
  516. self.m_last_group_id += 1
  517. return group_id
  518. def canvas_add_jack_group(self, group_name):
  519. group_id = self.m_last_group_id
  520. patchcanvas.addGroup(group_id, group_name)
  521. group_obj = [None, None, None]
  522. group_obj[iGroupId] = group_id
  523. group_obj[iGroupName] = group_name
  524. group_obj[iGroupType] = GROUP_TYPE_JACK
  525. self.m_group_list.append(group_obj)
  526. self.m_last_group_id += 1
  527. return group_id
  528. def canvas_remove_group(self, group_name):
  529. group_id = -1
  530. for group in self.m_group_list:
  531. if group[iGroupName] == group_name:
  532. group_id = group[iGroupId]
  533. self.m_group_list.remove(group)
  534. break
  535. else:
  536. print("Catia - remove group failed")
  537. return
  538. patchcanvas.removeGroup(group_id)
  539. def canvas_add_alsa_port(self, group_id, group_name, port_name, port_nameR, is_port_input):
  540. port_id = self.m_last_port_id
  541. port_mode = patchcanvas.PORT_MODE_INPUT if is_port_input else patchcanvas.PORT_MODE_OUTPUT
  542. port_type = patchcanvas.PORT_TYPE_MIDI_ALSA
  543. patchcanvas.addPort(group_id, port_id, port_name, port_mode, port_type)
  544. port_obj = [None, None, None, None]
  545. port_obj[iPortId] = port_id
  546. port_obj[iPortName] = port_name
  547. port_obj[iPortNameR] = "[ALSA-%s] %s" % ("Input" if is_port_input else "Output", port_nameR)
  548. port_obj[iPortGroupName] = group_name
  549. self.m_port_list.append(port_obj)
  550. self.m_last_port_id += 1
  551. return port_id
  552. def canvas_add_jack_port(self, port_ptr, port_name):
  553. global a2j_client_name
  554. port_id = self.m_last_port_id
  555. group_id = -1
  556. port_nameR = port_name
  557. alias_n = self.m_savedSettings["Main/JackPortAlias"]
  558. if alias_n in (1, 2):
  559. aliases = jacklib.port_get_aliases(port_ptr)
  560. if aliases[0] == 2 and alias_n == 2:
  561. port_name = aliases[2]
  562. elif aliases[0] >= 1 and alias_n == 1:
  563. port_name = aliases[1]
  564. port_flags = jacklib.port_flags(port_ptr)
  565. group_name = port_name.split(":", 1)[0]
  566. if port_flags & jacklib.JackPortIsInput:
  567. port_mode = patchcanvas.PORT_MODE_INPUT
  568. elif port_flags & jacklib.JackPortIsOutput:
  569. port_mode = patchcanvas.PORT_MODE_OUTPUT
  570. else:
  571. port_mode = patchcanvas.PORT_MODE_NULL
  572. if group_name == a2j_client_name:
  573. port_type = patchcanvas.PORT_TYPE_MIDI_A2J
  574. group_name = port_name.replace("%s:" % a2j_client_name, "", 1).split(" [", 1)[0]
  575. port_short_name = port_name.split("): ", 1)[1]
  576. else:
  577. port_short_name = port_name.replace("%s:" % group_name, "", 1)
  578. port_type_str = str(jacklib.port_type(port_ptr), encoding="utf-8")
  579. if port_type_str == jacklib.JACK_DEFAULT_AUDIO_TYPE:
  580. port_type = patchcanvas.PORT_TYPE_AUDIO_JACK
  581. elif port_type_str == jacklib.JACK_DEFAULT_MIDI_TYPE:
  582. port_type = patchcanvas.PORT_TYPE_MIDI_JACK
  583. else:
  584. port_type = patchcanvas.PORT_TYPE_NULL
  585. for group in self.m_group_list:
  586. if group[iGroupName] == group_name:
  587. group_id = group[iGroupId]
  588. break
  589. else:
  590. # For ports with no group
  591. group_id = self.canvas_add_jack_group(group_name)
  592. patchcanvas.addPort(group_id, port_id, port_short_name, port_mode, port_type)
  593. port_obj = [None, None, None, None]
  594. port_obj[iPortId] = port_id
  595. port_obj[iPortName] = port_name
  596. port_obj[iPortNameR] = port_nameR
  597. port_obj[iPortGroupName] = group_name
  598. self.m_port_list.append(port_obj)
  599. self.m_last_port_id += 1
  600. if group_id not in self.m_group_split_list and (port_flags & jacklib.JackPortIsPhysical) > 0:
  601. patchcanvas.splitGroup(group_id)
  602. patchcanvas.setGroupIcon(group_id, patchcanvas.ICON_HARDWARE)
  603. self.m_group_split_list.append(group_id)
  604. return port_id
  605. def canvas_remove_jack_port(self, port_id):
  606. patchcanvas.removePort(port_id)
  607. for port in self.m_port_list:
  608. if port[iPortId] == port_id:
  609. group_name = port[iPortGroupName]
  610. self.m_port_list.remove(port)
  611. break
  612. else:
  613. return
  614. # Check if group has no more ports; if yes remove it
  615. for port in self.m_port_list:
  616. if port[iPortGroupName] == group_name:
  617. break
  618. else:
  619. self.canvas_remove_group(group_name)
  620. def canvas_rename_port(self, port_id, port_short_name):
  621. patchcanvas.renamePort(port_id, port_short_name)
  622. def canvas_connect_ports(self, port_out_id, port_in_id):
  623. connection_id = self.m_last_connection_id
  624. patchcanvas.connectPorts(connection_id, port_out_id, port_in_id)
  625. conn_obj = [None, None, None]
  626. conn_obj[iConnId] = connection_id
  627. conn_obj[iConnOutput] = port_out_id
  628. conn_obj[iConnInput] = port_in_id
  629. self.m_connection_list.append(conn_obj)
  630. self.m_last_connection_id += 1
  631. return connection_id
  632. def canvas_connect_ports_by_name(self, port_out_name, port_in_name):
  633. port_out_id = -1
  634. port_in_id = -1
  635. for port in self.m_port_list:
  636. if port[iPortNameR] == port_out_name:
  637. port_out_id = port[iPortId]
  638. elif port[iPortNameR] == port_in_name:
  639. port_in_id = port[iPortId]
  640. if port_out_id == -1 or port_in_id == -1:
  641. print("Catia - connect jack ports failed")
  642. return
  643. return self.canvas_connect_ports(port_out_id, port_in_id)
  644. def canvas_disconnect_ports(self, port_out_id, port_in_id):
  645. for connection in self.m_connection_list:
  646. if connection[iConnOutput] == port_out_id and connection[iConnInput] == port_in_id:
  647. patchcanvas.disconnectPorts(connection[iConnId])
  648. self.m_connection_list.remove(connection)
  649. break
  650. def canvas_disconnect_ports_by_name(self, port_out_name, port_in_name):
  651. port_out_id = -1
  652. port_in_id = -1
  653. for port in self.m_port_list:
  654. if port[iPortNameR] == port_out_name:
  655. port_out_id = port[iPortId]
  656. elif port[iPortNameR] == port_in_name:
  657. port_in_id = port[iPortId]
  658. if port_out_id == -1 or port_in_id == -1:
  659. print("Catia - disconnect ports failed")
  660. return
  661. self.canvas_disconnect_ports(port_out_id, port_in_id)
  662. def jackStarted(self):
  663. if not jack.client:
  664. jack.client = jacklib.client_open("catia", jacklib.JackNoStartServer | jacklib.JackSessionID, None)
  665. if not jack.client:
  666. self.jackStopped()
  667. return False
  668. self.act_jack_render.setEnabled(canRender)
  669. self.b_jack_render.setEnabled(canRender)
  670. self.menuJackServer(True)
  671. self.menuJackTransport(True)
  672. self.cb_buffer_size.setEnabled(True)
  673. self.cb_sample_rate.setEnabled(bool(DBus.jack)) # DBus.jack and jacksettings.getSampleRate() != -1
  674. self.menu_Jack_Buffer_Size.setEnabled(True)
  675. self.pb_dsp_load.setMaximum(100)
  676. self.pb_dsp_load.setValue(0)
  677. self.pb_dsp_load.update()
  678. self.init_jack()
  679. return True
  680. def jackStopped(self):
  681. if haveDBus:
  682. self.DBusReconnect()
  683. # client already closed
  684. jack.client = None
  685. # refresh canvas (remove jack ports)
  686. patchcanvas.clear()
  687. self.init_ports()
  688. if self.m_next_sample_rate:
  689. jack_sample_rate(self, self.m_next_sample_rate)
  690. if DBus.jack:
  691. buffer_size = jacksettings.getBufferSize()
  692. sample_rate = jacksettings.getSampleRate()
  693. buffer_size_test = bool(buffer_size != -1)
  694. sample_rate_test = bool(sample_rate != -1)
  695. if buffer_size_test:
  696. setBufferSize(self, buffer_size)
  697. if sample_rate_test:
  698. setSampleRate(self, sample_rate)
  699. setRealTime(self, jacksettings.isRealtime())
  700. self.cb_buffer_size.setEnabled(buffer_size_test)
  701. self.cb_sample_rate.setEnabled(sample_rate_test)
  702. self.menu_Jack_Buffer_Size.setEnabled(buffer_size_test)
  703. else:
  704. self.cb_buffer_size.setEnabled(False)
  705. self.cb_sample_rate.setEnabled(False)
  706. self.menu_Jack_Buffer_Size.setEnabled(False)
  707. self.act_jack_render.setEnabled(False)
  708. self.b_jack_render.setEnabled(False)
  709. self.menuJackServer(False)
  710. self.menuJackTransport(False)
  711. setXruns(self, -1)
  712. if self.m_selected_transport_view == TRANSPORT_VIEW_HMS:
  713. self.label_time.setText("00:00:00")
  714. elif self.m_selected_transport_view == TRANSPORT_VIEW_BBT:
  715. self.label_time.setText("000|0|0000")
  716. elif self.m_selected_transport_view == TRANSPORT_VIEW_FRAMES:
  717. self.label_time.setText("000'000'000")
  718. self.pb_dsp_load.setValue(0)
  719. self.pb_dsp_load.setMaximum(0)
  720. self.pb_dsp_load.update()
  721. def a2jStarted(self):
  722. self.menuA2JBridge(True)
  723. def a2jStopped(self):
  724. self.menuA2JBridge(False)
  725. def menuJackServer(self, started):
  726. if DBus.jack:
  727. self.act_tools_jack_start.setEnabled(not started)
  728. self.act_tools_jack_stop.setEnabled(started)
  729. self.menuA2JBridge(False)
  730. def menuJackTransport(self, enabled):
  731. self.act_transport_play.setEnabled(enabled)
  732. self.act_transport_stop.setEnabled(enabled)
  733. self.act_transport_backwards.setEnabled(enabled)
  734. self.act_transport_forwards.setEnabled(enabled)
  735. self.menu_Transport.setEnabled(enabled)
  736. self.group_transport.setEnabled(enabled)
  737. def menuA2JBridge(self, started):
  738. if DBus.jack and not DBus.jack.IsStarted():
  739. self.act_tools_a2j_start.setEnabled(False)
  740. self.act_tools_a2j_stop.setEnabled(False)
  741. else:
  742. self.act_tools_a2j_start.setEnabled(not started)
  743. self.act_tools_a2j_stop.setEnabled(started)
  744. self.act_tools_a2j_export_hw.setEnabled(not started)
  745. def DBusSignalReceiver(self, *args, **kwds):
  746. if kwds['interface'] == "org.freedesktop.DBus" and kwds['path'] == "/org/freedesktop/DBus" and kwds['member'] == "NameOwnerChanged":
  747. appInterface, appId, newId = args
  748. if not newId:
  749. # Something crashed
  750. if appInterface == "org.gna.home.a2jmidid":
  751. QTimer.singleShot(0, self, SLOT("slot_handleCrash_a2j()"))
  752. elif appInterface == "org.jackaudio.service":
  753. QTimer.singleShot(0, self, SLOT("slot_handleCrash_jack()"))
  754. elif kwds['interface'] == "org.jackaudio.JackControl":
  755. if kwds['member'] == "ServerStarted":
  756. self.jackStarted()
  757. elif kwds['member'] == "ServerStopped":
  758. self.jackStopped()
  759. elif kwds['interface'] == "org.gna.home.a2jmidid.control":
  760. if kwds['member'] == "bridge_started":
  761. self.a2jStarted()
  762. elif kwds['member'] == "bridge_stopped":
  763. self.a2jStopped()
  764. def DBusReconnect(self):
  765. global a2j_client_name
  766. try:
  767. DBus.jack = DBus.bus.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
  768. jacksettings.initBus(DBus.bus)
  769. except:
  770. DBus.jack = None
  771. try:
  772. DBus.a2j = dbus.Interface(DBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
  773. a2j_client_name = str(DBus.a2j.get_jack_client_name())
  774. except:
  775. DBus.a2j = None
  776. a2j_client_name = None
  777. def JackXRunCallback(self, arg):
  778. if DEBUG: print("JackXRunCallback()")
  779. self.emit(SIGNAL("XRunCallback()"))
  780. return 0
  781. def JackBufferSizeCallback(self, buffer_size, arg):
  782. if DEBUG: print("JackBufferSizeCallback(%i)" % buffer_size)
  783. self.emit(SIGNAL("BufferSizeCallback(int)"), buffer_size)
  784. return 0
  785. def JackSampleRateCallback(self, sample_rate, arg):
  786. if DEBUG: print("JackSampleRateCallback(%i)" % sample_rate)
  787. self.emit(SIGNAL("SampleRateCallback(int)"), sample_rate)
  788. return 0
  789. def JackPortRegistrationCallback(self, port_id, register_yesno, arg):
  790. if DEBUG: print("JackPortRegistrationCallback(%i, %i)" % (port_id, register_yesno))
  791. self.emit(SIGNAL("PortRegistrationCallback(int, bool)"), port_id, bool(register_yesno))
  792. return 0
  793. def JackPortConnectCallback(self, port_a, port_b, connect_yesno, arg):
  794. if DEBUG: print("JackPortConnectCallback(%i, %i, %i)" % (port_a, port_b, connect_yesno))
  795. self.emit(SIGNAL("PortConnectCallback(int, int, bool)"), port_a, port_b, bool(connect_yesno))
  796. return 0
  797. def JackPortRenameCallback(self, port_id, old_name, new_name, arg):
  798. if DEBUG: print("JackPortRenameCallback(%i, %s, %s)" % (port_id, old_name, new_name))
  799. self.emit(SIGNAL("PortRenameCallback(int, QString, QString)"), port_id, str(old_name, encoding="utf-8"), str(new_name, encoding="utf-8"))
  800. return 0
  801. def JackSessionCallback(self, event, arg):
  802. if WINDOWS:
  803. filepath = os.path.join(sys.argv[0])
  804. else:
  805. if sys.argv[0].startswith("/"):
  806. filepath = "catia"
  807. else:
  808. filepath = os.path.join(sys.path[0], "catia.py")
  809. event.command_line = str(filepath).encode("utf-8")
  810. jacklib.session_reply(jack.client, event)
  811. if event.type == jacklib.JackSessionSaveAndQuit:
  812. app.quit()
  813. #jacklib.session_event_free(event)
  814. def JackShutdownCallback(self, arg):
  815. if DEBUG: print("JackShutdownCallback()")
  816. self.emit(SIGNAL("ShutdownCallback()"))
  817. return 0
  818. @pyqtSlot()
  819. def slot_JackServerStart(self):
  820. if DBus.jack:
  821. try:
  822. ret = bool(DBus.jack.StartServer())
  823. return ret
  824. except:
  825. QMessageBox.warning(self, self.tr("Warning"), self.tr("Failed to start JACK, please check the logs for more information."))
  826. #self.jackStopped()
  827. return False
  828. @pyqtSlot()
  829. def slot_JackServerStop(self):
  830. if DBus.jack:
  831. return DBus.jack.StopServer()
  832. else:
  833. return False
  834. @pyqtSlot()
  835. def slot_JackClearXruns(self):
  836. if jack.client:
  837. self.m_xruns = 0
  838. setXruns(self, 0)
  839. @pyqtSlot()
  840. def slot_A2JBridgeStart(self):
  841. if DBus.a2j:
  842. return DBus.a2j.start()
  843. else:
  844. return False
  845. @pyqtSlot()
  846. def slot_A2JBridgeStop(self):
  847. if DBus.a2j:
  848. return DBus.a2j.stop()
  849. else:
  850. return False
  851. @pyqtSlot()
  852. def slot_A2JBridgeExportHW(self):
  853. if DBus.a2j:
  854. ask = QMessageBox.question(self, self.tr("A2J Hardware Export"), self.tr("Enable Hardware Export on the A2J Bridge?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, QMessageBox.No)
  855. if ask == QMessageBox.Yes:
  856. DBus.a2j.set_hw_export(True)
  857. elif ask == QMessageBox.No:
  858. DBus.a2j.set_hw_export(False)
  859. @pyqtSlot()
  860. def slot_XRunCallback(self):
  861. self.m_xruns += 1
  862. setXruns(self, self.m_xruns)
  863. @pyqtSlot(int)
  864. def slot_BufferSizeCallback(self, buffer_size):
  865. setBufferSize(self, buffer_size)
  866. @pyqtSlot(int)
  867. def slot_SampleRateCallback(self, sample_rate):
  868. setSampleRate(self, sample_rate)
  869. @pyqtSlot(int, bool)
  870. def slot_PortRegistrationCallback(self, port_id_jack, register_yesno):
  871. port_ptr = jacklib.port_by_id(jack.client, port_id_jack)
  872. port_nameR = str(jacklib.port_name(port_ptr), encoding="utf-8")
  873. if register_yesno:
  874. self.canvas_add_jack_port(port_ptr, port_nameR)
  875. else:
  876. for port in self.m_port_list:
  877. if port[iPortNameR] == port_nameR:
  878. port_id = port[iPortId]
  879. break
  880. else:
  881. return
  882. self.canvas_remove_jack_port(port_id)
  883. @pyqtSlot(int, int, bool)
  884. def slot_PortConnectCallback(self, port_a_jack, port_b_jack, connect_yesno):
  885. port_a_ptr = jacklib.port_by_id(jack.client, port_a_jack)
  886. port_b_ptr = jacklib.port_by_id(jack.client, port_b_jack)
  887. port_a_nameR = str(jacklib.port_name(port_a_ptr), encoding="utf-8")
  888. port_b_nameR = str(jacklib.port_name(port_b_ptr), encoding="utf-8")
  889. if connect_yesno:
  890. self.canvas_connect_ports_by_name(port_a_nameR, port_b_nameR)
  891. else:
  892. self.canvas_disconnect_ports_by_name(port_a_nameR, port_b_nameR)
  893. @pyqtSlot(int, str, str)
  894. def slot_PortRenameCallback(self, port_id_jack, old_name, new_name):
  895. port_ptr = jacklib.port_by_id(jack.client, port_id_jack)
  896. port_short_name = str(jacklib.port_short_name(port_ptr), encoding="utf-8")
  897. for port in self.m_port_list:
  898. if port[iPortNameR] == old_name:
  899. port_id = port[iPortId]
  900. port[iPortNameR] = new_name
  901. break
  902. else:
  903. return
  904. # Only set new name in canvas if no alias is active for this port
  905. aliases = jacklib.port_get_aliases(port_ptr)
  906. if aliases[0] == 1 and self.m_savedSettings["Main/JackPortAlias"] == 1:
  907. pass
  908. elif aliases[0] == 2 and self.m_savedSettings["Main/JackPortAlias"] == 2:
  909. pass
  910. else:
  911. self.canvas_rename_port(port_id, port_short_name)
  912. @pyqtSlot()
  913. def slot_ShutdownCallback(self):
  914. self.jackStopped()
  915. @pyqtSlot()
  916. def slot_handleCrash_a2j(self):
  917. global a2j_client_name
  918. try:
  919. DBus.a2j = dbus.Interface(DBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
  920. a2j_client_name = str(DBus.a2j.get_jack_client_name())
  921. except:
  922. DBus.a2j = None
  923. a2j_client_name = None
  924. if DBus.a2j:
  925. if DBus.a2j.is_started():
  926. self.a2jStarted()
  927. else:
  928. self.a2jStopped()
  929. else:
  930. self.act_tools_a2j_start.setEnabled(False)
  931. self.act_tools_a2j_stop.setEnabled(False)
  932. self.act_tools_a2j_export_hw.setEnabled(False)
  933. self.menu_A2J_Bridge.setEnabled(False)
  934. @pyqtSlot()
  935. def slot_handleCrash_jack(self):
  936. self.DBusReconnect()
  937. if DBus.jack:
  938. self.act_jack_configure.setEnabled(True)
  939. self.b_jack_configure.setEnabled(True)
  940. else:
  941. self.act_tools_jack_start.setEnabled(False)
  942. self.act_tools_jack_stop.setEnabled(False)
  943. self.act_jack_configure.setEnabled(False)
  944. self.b_jack_configure.setEnabled(False)
  945. if DBus.a2j:
  946. if DBus.a2j.is_started():
  947. self.a2jStarted()
  948. else:
  949. self.a2jStopped()
  950. else:
  951. self.act_tools_a2j_start.setEnabled(False)
  952. self.act_tools_a2j_stop.setEnabled(False)
  953. self.act_tools_a2j_export_hw.setEnabled(False)
  954. self.menu_A2J_Bridge.setEnabled(False)
  955. self.jackStopped()
  956. @pyqtSlot()
  957. def slot_configureCatia(self):
  958. dialog = SettingsW(self, "catia", hasGL)
  959. if dialog.exec_():
  960. self.loadSettings(False)
  961. patchcanvas.clear()
  962. p_options = patchcanvas.options_t()
  963. p_options.theme_name = self.m_savedSettings["Canvas/Theme"]
  964. p_options.auto_hide_groups = self.m_savedSettings["Canvas/AutoHideGroups"]
  965. p_options.use_bezier_lines = self.m_savedSettings["Canvas/UseBezierLines"]
  966. p_options.antialiasing = self.m_savedSettings["Canvas/Antialiasing"]
  967. p_options.eyecandy = self.m_savedSettings["Canvas/EyeCandy"]
  968. p_features = patchcanvas.features_t()
  969. p_features.group_info = False
  970. p_features.group_rename = False
  971. p_features.port_info = True
  972. p_features.port_rename = bool(self.m_savedSettings["Main/JackPortAlias"] > 0)
  973. p_features.handle_group_pos = True
  974. patchcanvas.setOptions(p_options)
  975. patchcanvas.setFeatures(p_features)
  976. patchcanvas.init("Catia", self.scene, self.canvasCallback, DEBUG)
  977. self.init_ports()
  978. @pyqtSlot()
  979. def slot_aboutCatia(self):
  980. QMessageBox.about(self, self.tr("About Catia"), self.tr("<h3>Catia</h3>"
  981. "<br>Version %s"
  982. "<br>Catia is a nice JACK Patchbay with A2J Bridge integration.<br>"
  983. "<br>Copyright (C) 2010-2012 falkTX" % VERSION))
  984. def saveSettings(self):
  985. self.settings.setValue("Geometry", self.saveGeometry())
  986. self.settings.setValue("ShowToolbar", self.frame_toolbar.isVisible())
  987. self.settings.setValue("ShowStatusbar", self.frame_statusbar.isVisible())
  988. self.settings.setValue("TransportView", self.m_selected_transport_view)
  989. def loadSettings(self, geometry):
  990. if geometry:
  991. self.restoreGeometry(self.settings.value("Geometry", ""))
  992. show_toolbar = self.settings.value("ShowToolbar", True, type=bool)
  993. self.act_settings_show_toolbar.setChecked(show_toolbar)
  994. self.frame_toolbar.setVisible(show_toolbar)
  995. show_statusbar = self.settings.value("ShowStatusbar", True, type=bool)
  996. self.act_settings_show_statusbar.setChecked(show_statusbar)
  997. self.frame_statusbar.setVisible(show_statusbar)
  998. setTransportView(self, self.settings.value("TransportView", TRANSPORT_VIEW_HMS, type=int))
  999. self.m_savedSettings = {
  1000. "Main/RefreshInterval": self.settings.value("Main/RefreshInterval", 120, type=int),
  1001. "Main/JackPortAlias": self.settings.value("Main/JackPortAlias", 2, type=int),
  1002. "Canvas/Theme": self.settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str),
  1003. "Canvas/AutoHideGroups": self.settings.value("Canvas/AutoHideGroups", False, type=bool),
  1004. "Canvas/UseBezierLines": self.settings.value("Canvas/UseBezierLines", True, type=bool),
  1005. "Canvas/EyeCandy": self.settings.value("Canvas/EyeCandy", patchcanvas.EYECANDY_SMALL, type=int),
  1006. "Canvas/UseOpenGL": self.settings.value("Canvas/UseOpenGL", False, type=bool),
  1007. "Canvas/Antialiasing": self.settings.value("Canvas/Antialiasing", patchcanvas.ANTIALIASING_SMALL, type=int),
  1008. "Canvas/TextAntialiasing": self.settings.value("Canvas/TextAntialiasing", True, type=bool),
  1009. "Canvas/HighQualityAntialiasing": self.settings.value("Canvas/HighQualityAntialiasing", False, type=bool)
  1010. }
  1011. def timerEvent(self, event):
  1012. if event.timerId() == self.m_timer120:
  1013. if jack.client:
  1014. refreshTransport(self)
  1015. elif event.timerId() == self.m_timer600:
  1016. if jack.client:
  1017. refreshDSPLoad(self)
  1018. #else:
  1019. #self.update()
  1020. QMainWindow.timerEvent(self, event)
  1021. def closeEvent(self, event):
  1022. self.saveSettings()
  1023. patchcanvas.clear()
  1024. QMainWindow.closeEvent(self, event)
  1025. #--------------- main ------------------
  1026. if __name__ == '__main__':
  1027. # App initialization
  1028. app = QApplication(sys.argv)
  1029. app.setApplicationName("Catia")
  1030. app.setApplicationVersion(VERSION)
  1031. app.setOrganizationName("Cadence")
  1032. app.setWindowIcon(QIcon(":/scalable/catia.svg"))
  1033. if haveDBus:
  1034. DBus.loop = DBusQtMainLoop(set_as_default=True)
  1035. DBus.bus = dbus.SessionBus(mainloop=DBus.loop)
  1036. try:
  1037. DBus.jack = DBus.bus.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
  1038. jacksettings.initBus(DBus.bus)
  1039. except:
  1040. DBus.jack = None
  1041. try:
  1042. DBus.a2j = dbus.Interface(DBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
  1043. a2j_client_name = str(DBus.a2j.get_jack_client_name())
  1044. except:
  1045. DBus.a2j = None
  1046. a2j_client_name = None
  1047. if DBus.jack or DBus.a2j:
  1048. string = "Using DBus for "
  1049. if DBus.jack:
  1050. string += "JACK"
  1051. if DBus.a2j:
  1052. string += " and a2jmidid"
  1053. elif DBus.a2j:
  1054. string += "a2jmidid"
  1055. print(string)
  1056. else:
  1057. DBus.jack = None
  1058. DBus.a2j = None
  1059. a2j_client_name = None
  1060. print("Not using DBus")
  1061. # Show GUI
  1062. gui = CatiaMainW()
  1063. # Set-up custom signal handling
  1064. setUpSignals(gui)
  1065. gui.show()
  1066. # App-Loop
  1067. ret = app.exec_()
  1068. # Close Jack
  1069. if jack.client:
  1070. jacklib.deactivate(jack.client)
  1071. jacklib.client_close(jack.client)
  1072. # Exit properly
  1073. sys.exit(ret)