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.

1075 lines
45KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # JACK Settings Dialog
  4. # Copyright (C) 2010-2018 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. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from sys import platform, version_info
  20. if True:
  21. from PyQt5.QtCore import pyqtSlot, Qt, QSettings, QTimer
  22. from PyQt5.QtGui import QFontMetrics
  23. from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QMessageBox
  24. else:
  25. from PyQt4.QtCore import pyqtSlot, Qt, QSettings, QTimer
  26. from PyQt4.QtGui import QFontMetrics
  27. from PyQt4.QtGui import QDialog, QDialogButtonBox, QMessageBox
  28. from shared_cadence import *
  29. # ------------------------------------------------------------------------------------------------------------
  30. # Imports (Custom Stuff)
  31. import ui_settings_jack
  32. # ------------------------------------------------------------------------------------------------------------
  33. # Try Import DBus
  34. try:
  35. import dbus
  36. except:
  37. dbus = None
  38. # ------------------------------------------------------------------------------------------------------------
  39. # Global object
  40. global gJackctl, gResetNeeded
  41. gJackctl = None
  42. gResetNeeded = False
  43. # ------------------------------------------------------------------------------------------------------------
  44. # enum jack_timer_type_t
  45. JACK_TIMER_SYSTEM_CLOCK = 0
  46. JACK_TIMER_CYCLE_COUNTER = 1
  47. JACK_TIMER_HPET = 2
  48. # ------------------------------------------------------------------------------------------------------------
  49. # Set Platform
  50. if "linux" in platform:
  51. LINUX = True
  52. if version_info >= (3, 0):
  53. from subprocess import getoutput
  54. else:
  55. from commands import getoutput
  56. else:
  57. LINUX = False
  58. # ------------------------------------------------------------------------------------------------------------
  59. # Init DBus
  60. def initBus(bus):
  61. global gJackctl
  62. global jack_control_iface
  63. if not bus:
  64. gJackctl = None
  65. return 1
  66. try:
  67. controller = bus.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
  68. gJackctl = dbus.Interface(controller, "org.jackaudio.Configure")
  69. jack_control_iface = dbus.Interface(
  70. controller, "org.jackaudio.JackControl")
  71. return 0
  72. except:
  73. gJackctl = None
  74. return 1
  75. def needsInit():
  76. global gJackctl
  77. return bool(gJackctl is None)
  78. def setResetNeeded(yesNo):
  79. global gResetNeeded
  80. gResetNeeded = yesNo
  81. # ------------------------------------------------------------------------------------------------------------
  82. # Helper functions
  83. def getBufferSize():
  84. return getDriverParameter("period", -1)
  85. def getSampleRate():
  86. return getDriverParameter("rate", -1)
  87. def isRealtime():
  88. return getEngineParameter("realtime", False)
  89. def setBufferSize(bsize):
  90. return setDriverParameter("period", dbus.UInt32(bsize))
  91. def setSampleRate(srate):
  92. return setDriverParameter("rate", dbus.UInt32(srate))
  93. # ------------------------------------------------------------------------------------------------------------
  94. # Helper functions (engine)
  95. def engineHasFeature(feature):
  96. if gJackctl is None:
  97. return False
  98. try:
  99. featureList = gJackctl.ReadContainer(["engine"])[1]
  100. except:
  101. featureList = ()
  102. return bool(dbus.String(feature) in featureList)
  103. def getEngineParameter(parameter, fallback):
  104. if gJackctl is None or not engineHasFeature(parameter):
  105. return fallback
  106. else:
  107. try:
  108. return gJackctl.GetParameterValue(["engine", parameter])[2]
  109. except:
  110. return fallback
  111. def setEngineParameter(parameter, value, optional=True):
  112. if not engineHasFeature(parameter):
  113. return False
  114. elif optional:
  115. paramValueTry = gJackctl.GetParameterValue(["engine", parameter])
  116. if paramValueTry is None:
  117. return False
  118. paramValue = paramValueTry[2]
  119. if value != paramValue:
  120. return bool(gJackctl.SetParameterValue(["engine", parameter], value))
  121. else:
  122. return False
  123. else:
  124. return bool(gJackctl.SetParameterValue(["engine", parameter], value))
  125. # ------------------------------------------------------------------------------------------------------------
  126. # Helper functions (driver)
  127. def driverHasFeature(feature):
  128. if gJackctl is None:
  129. return False
  130. try:
  131. featureList = gJackctl.ReadContainer(["driver"])[1]
  132. except:
  133. featureList = ()
  134. return bool(dbus.String(feature) in featureList)
  135. def getDriverParameter(parameter, fallback):
  136. if gJackctl is None or not driverHasFeature(parameter):
  137. return fallback
  138. else:
  139. try:
  140. return gJackctl.GetParameterValue(["driver", parameter])[2]
  141. except:
  142. return fallback
  143. def setDriverParameter(parameter, value, optional=True):
  144. if not driverHasFeature(parameter):
  145. return False
  146. elif optional:
  147. if value != gJackctl.GetParameterValue(["driver", parameter])[2]:
  148. return bool(gJackctl.SetParameterValue(["driver", parameter], value))
  149. else:
  150. return False
  151. else:
  152. return bool(gJackctl.SetParameterValue(["driver", parameter], value))
  153. # ------------------------------------------------------------------------------------------------------------
  154. # JACK Settings Dialog
  155. class JackSettingsW(QDialog):
  156. def __init__(self, parent):
  157. QDialog.__init__(self, parent)
  158. self.ui = ui_settings_jack.Ui_JackSettingsW()
  159. self.ui.setupUi(self)
  160. # -------------------------------------------------------------
  161. # Check if we've got valid control interface
  162. global gJackctl
  163. if gJackctl is None:
  164. QTimer.singleShot(0, self, SLOT("slot_closeWithError()"))
  165. return
  166. # -------------------------------------------------------------
  167. # Align driver text and hide non available ones
  168. driverList = gJackctl.ReadContainer(["drivers"])[1]
  169. fontMetris = QFontMetrics(self.ui.obj_server_driver.font())
  170. maxWidth = 75
  171. for i in range(self.ui.obj_server_driver.rowCount()):
  172. item = self.ui.obj_server_driver.item(i, 0)
  173. item.setTextAlignment(Qt.AlignCenter)
  174. itexText = item.text()
  175. itemWidth = fontMetris.width(itexText)+25
  176. if itemWidth > maxWidth:
  177. maxWidth = itemWidth
  178. if dbus.String(itexText.lower()) not in driverList:
  179. self.ui.obj_server_driver.hideRow(i)
  180. self.ui.obj_server_driver.setMinimumWidth(maxWidth)
  181. self.ui.obj_server_driver.setMaximumWidth(maxWidth)
  182. # -------------------------------------------------------------
  183. # Set-up connections
  184. self.accepted.connect(self.slot_saveJackSettings)
  185. self.ui.buttonBox.button(QDialogButtonBox.Reset).clicked.connect(self.slot_resetJackSettings)
  186. self.ui.obj_driver_duplex.clicked.connect(self.slot_checkDuplexSelection)
  187. self.ui.obj_server_driver.currentCellChanged.connect(self.slot_checkDriverSelection)
  188. self.ui.obj_driver_capture.currentIndexChanged[int].connect(self.slot_checkALSASelection)
  189. self.ui.obj_driver_playback.currentIndexChanged[int].connect(self.slot_checkALSASelection)
  190. self.ui.obj_net_manager_start.clicked.connect(self.net_manager_start)
  191. self.ui.obj_net_manager_stop.clicked.connect(self.net_manager_stop)
  192. self.ui.obj_net_reset.clicked.connect(self.net_manager_reset)
  193. # -------------------------------------------------------------
  194. # Load initial settings
  195. self.fDriverName = ""
  196. self.fBrokenServerClockSource = False
  197. self.checkEngine()
  198. self.loadServerSettings()
  199. self.loadDriverSettings(True) # reset because we'll change it below
  200. self.loadNetSettings()
  201. # -------------------------------------------------------------
  202. # Load selected JACK driver
  203. self.fDriverName = str(gJackctl.GetParameterValue(["engine", "driver"])[2])
  204. for i in range(self.ui.obj_server_driver.rowCount()):
  205. if self.ui.obj_server_driver.item(i, 0).text().lower() == self.fDriverName:
  206. self.ui.obj_server_driver.setCurrentCell(i, 0)
  207. break
  208. # Special ALSA check
  209. self.slot_checkALSASelection()
  210. # -------------------------------------------------------------
  211. # Load last GUI settings
  212. self.loadSettings()
  213. # -----------------------------------------------------------------
  214. # Engine calls
  215. def checkEngine(self):
  216. self.ui.obj_server_realtime.setEnabled(engineHasFeature("realtime"))
  217. self.ui.obj_server_realtime_priority.setEnabled(engineHasFeature("realtime-priority"))
  218. self.ui.obj_server_temporary.setEnabled(engineHasFeature("temporary"))
  219. self.ui.obj_server_verbose.setEnabled(engineHasFeature("verbose"))
  220. self.ui.obj_server_alias.setEnabled(engineHasFeature("alias"))
  221. self.ui.obj_server_client_timeout.setEnabled(engineHasFeature("client-timeout"))
  222. self.ui.obj_server_clock_source.setEnabled(engineHasFeature("clock-source"))
  223. self.ui.obj_server_port_max.setEnabled(engineHasFeature("port-max"))
  224. self.ui.obj_server_replace_registry.setEnabled(engineHasFeature("replace-registry"))
  225. self.ui.obj_server_sync.setEnabled(engineHasFeature("sync"))
  226. self.ui.obj_server_self_connect_mode.setEnabled(engineHasFeature("self-connect-mode"))
  227. # Disable clock-source if not on Linux
  228. if not LINUX:
  229. self.ui.obj_server_clock_source.setEnabled(False)
  230. # -----------------------------------------------------------------
  231. # Server calls
  232. def saveServerSettings(self):
  233. # always reset server name
  234. if engineHasFeature("name"):
  235. setEngineParameter("name", "default", True)
  236. if self.ui.obj_server_realtime.isEnabled():
  237. value = dbus.Boolean(self.ui.obj_server_realtime.isChecked())
  238. setEngineParameter("realtime", value, True)
  239. if self.ui.obj_server_realtime_priority.isEnabled():
  240. value = dbus.Int32(self.ui.obj_server_realtime_priority.value())
  241. setEngineParameter("realtime-priority", value, True)
  242. if self.ui.obj_server_temporary.isEnabled():
  243. value = dbus.Boolean(self.ui.obj_server_temporary.isChecked())
  244. setEngineParameter("temporary", value, True)
  245. if self.ui.obj_server_verbose.isEnabled():
  246. value = dbus.Boolean(self.ui.obj_server_verbose.isChecked())
  247. setEngineParameter("verbose", value, True)
  248. if self.ui.obj_server_alias.isEnabled():
  249. value = dbus.Boolean(self.ui.obj_server_alias.isChecked())
  250. setEngineParameter("alias", value, True)
  251. if self.ui.obj_server_client_timeout.isEnabled():
  252. value = dbus.Int32(int(self.ui.obj_server_client_timeout.currentText()))
  253. setEngineParameter("client-timeout", value, True)
  254. if self.ui.obj_server_clock_source.isEnabled():
  255. if self.ui.obj_server_clock_source_system.isChecked():
  256. if self.fBrokenServerClockSource:
  257. value = dbus.UInt32(JACK_TIMER_SYSTEM_CLOCK)
  258. else:
  259. value = dbus.Byte("s".encode("utf-8"))
  260. elif self.ui.obj_server_clock_source_cycle.isChecked():
  261. if self.fBrokenServerClockSource:
  262. value = dbus.UInt32(JACK_TIMER_CYCLE_COUNTER)
  263. else:
  264. value = dbus.Byte("c".encode("utf-8"))
  265. elif self.ui.obj_server_clock_source_hpet.isChecked():
  266. if self.fBrokenServerClockSource:
  267. value = dbus.UInt32(JACK_TIMER_HPET)
  268. else:
  269. value = dbus.Byte("h".encode("utf-8"))
  270. else:
  271. value = None
  272. print("JackSettingsW::saveServerSettings() - Cannot save clock-source value")
  273. if value != None:
  274. setEngineParameter("clock-source", value, True)
  275. if self.ui.obj_server_port_max.isEnabled():
  276. value = dbus.UInt32(int(self.ui.obj_server_port_max.currentText()))
  277. setEngineParameter("port-max", value, True)
  278. if self.ui.obj_server_replace_registry.isEnabled():
  279. value = dbus.Boolean(self.ui.obj_server_replace_registry.isChecked())
  280. setEngineParameter("replace-registry", value, True)
  281. if self.ui.obj_server_sync.isEnabled():
  282. value = dbus.Boolean(self.ui.obj_server_sync.isChecked())
  283. setEngineParameter("sync", value, True)
  284. if self.ui.obj_server_self_connect_mode.isEnabled():
  285. if self.ui.obj_server_self_connect_mode_0.isChecked():
  286. value = dbus.Byte(" ".encode("utf-8"))
  287. elif self.ui.obj_server_self_connect_mode_1.isChecked():
  288. value = dbus.Byte("E".encode("utf-8"))
  289. elif self.ui.obj_server_self_connect_mode_2.isChecked():
  290. value = dbus.Byte("e".encode("utf-8"))
  291. elif self.ui.obj_server_self_connect_mode_3.isChecked():
  292. value = dbus.Byte("A".encode("utf-8"))
  293. elif self.ui.obj_server_self_connect_mode_4.isChecked():
  294. value = dbus.Byte("a".encode("utf-8"))
  295. else:
  296. value = None
  297. print("JackSettingsW::saveServerSettings() - Cannot save self-connect-mode value")
  298. if value != None:
  299. setEngineParameter("self-connect-mode", value, True)
  300. def loadServerSettings(self, reset=False, forceReset=False):
  301. global gJackctl
  302. settings = gJackctl.ReadContainer(["engine"])
  303. for i in range(len(settings[1])):
  304. attribute = str(settings[1][i])
  305. if reset:
  306. valueTry = gJackctl.GetParameterValue(["engine", attribute])
  307. if valueTry is None:
  308. continue
  309. else:
  310. value = valueTry[1]
  311. if forceReset and attribute != "driver":
  312. gJackctl.ResetParameterValue(["engine", attribute])
  313. else:
  314. valueTry = gJackctl.GetParameterValue(["engine", attribute])
  315. if valueTry is None:
  316. continue
  317. else:
  318. value = valueTry[2]
  319. if attribute == "name":
  320. pass # Don't allow to change this
  321. elif attribute == "realtime":
  322. self.ui.obj_server_realtime.setChecked(bool(value))
  323. elif attribute == "realtime-priority":
  324. self.ui.obj_server_realtime_priority.setValue(int(value))
  325. elif attribute == "temporary":
  326. self.ui.obj_server_temporary.setChecked(bool(value))
  327. elif attribute == "verbose":
  328. self.ui.obj_server_verbose.setChecked(bool(value))
  329. elif attribute == "alias":
  330. self.ui.obj_server_alias.setChecked(bool(value))
  331. elif attribute == "client-timeout":
  332. self.setComboBoxValue(self.ui.obj_server_client_timeout, str(value))
  333. elif attribute == "clock-source":
  334. value = str(value)
  335. if value == "c":
  336. self.ui.obj_server_clock_source_cycle.setChecked(True)
  337. elif value == "h":
  338. self.ui.obj_server_clock_source_hpet.setChecked(True)
  339. elif value == "s":
  340. self.ui.obj_server_clock_source_system.setChecked(True)
  341. else:
  342. self.fBrokenServerClockSource = True
  343. if value == str(JACK_TIMER_SYSTEM_CLOCK):
  344. self.ui.obj_server_clock_source_system.setChecked(True)
  345. elif value == str(JACK_TIMER_CYCLE_COUNTER):
  346. self.ui.obj_server_clock_source_cycle.setChecked(True)
  347. elif value == str(JACK_TIMER_HPET):
  348. self.ui.obj_server_clock_source_hpet.setChecked(True)
  349. else:
  350. self.ui.obj_server_clock_source.setEnabled(False)
  351. print("JackSettingsW::saveServerSettings() - Invalid clock-source value '%s'" % value)
  352. elif attribute == "port-max":
  353. self.setComboBoxValue(self.ui.obj_server_port_max, str(value))
  354. elif attribute == "replace-registry":
  355. self.ui.obj_server_replace_registry.setChecked(bool(value))
  356. elif attribute == "sync":
  357. self.ui.obj_server_sync.setChecked(bool(value))
  358. elif attribute == "self-connect-mode":
  359. value = str(value)
  360. if value == " ":
  361. self.ui.obj_server_self_connect_mode_0.setChecked(True)
  362. elif value == "E":
  363. self.ui.obj_server_self_connect_mode_1.setChecked(True)
  364. elif value == "e":
  365. self.ui.obj_server_self_connect_mode_2.setChecked(True)
  366. elif value == "A":
  367. self.ui.obj_server_self_connect_mode_3.setChecked(True)
  368. elif value == "a":
  369. self.ui.obj_server_self_connect_mode_4.setChecked(True)
  370. else:
  371. self.ui.obj_server_self_connect_mode.setEnabled(False)
  372. print("JackSettingsW::loadServerSettings() - Invalid self-connect-mode value '%s'" % value)
  373. elif attribute in ("driver", "slave-drivers"):
  374. pass
  375. else:
  376. print("JackSettingsW::loadServerSettings() - Unimplemented server attribute '%s', value: '%s'" % (attribute, str(value)))
  377. # -----------------------------------------------------------------
  378. # Driver calls
  379. # resetIfNeeded: fix alsa parameter re-order bug in JACK 1.9.8 (reset/remove non-used values)
  380. def saveDriverSettings(self, resetIfNeeded):
  381. global gJackctl, gResetNeeded
  382. if resetIfNeeded and not gResetNeeded:
  383. resetIfNeeded = False
  384. if self.ui.obj_driver_device.isEnabled():
  385. value = dbus.String(self.ui.obj_driver_device.currentText().split(" [")[0])
  386. if value != gJackctl.GetParameterValue(["driver", "device"])[2]:
  387. gJackctl.SetParameterValue(["driver", "device"], value)
  388. elif resetIfNeeded:
  389. gJackctl.ResetParameterValue(["driver", "device"])
  390. if self.ui.obj_driver_capture.isEnabled():
  391. if self.fDriverName == "alsa":
  392. value = dbus.String(self.ui.obj_driver_capture.currentText().split(" ")[0])
  393. elif self.fDriverName == "dummy":
  394. value = dbus.UInt32(int(self.ui.obj_driver_capture.currentText()))
  395. elif self.fDriverName == "firewire":
  396. value = dbus.Boolean(self.ui.obj_driver_capture.currentIndex() == 1)
  397. else:
  398. value = None
  399. print("JackSettingsW::saveDriverSettings() - Cannot save capture value")
  400. if value != None:
  401. setDriverParameter("capture", value, True)
  402. elif resetIfNeeded:
  403. gJackctl.ResetParameterValue(["driver", "capture"])
  404. if self.ui.obj_driver_playback.isEnabled():
  405. if self.fDriverName == "alsa":
  406. value = dbus.String(self.ui.obj_driver_playback.currentText().split(" ")[0])
  407. elif self.fDriverName == "dummy":
  408. value = dbus.UInt32(int(self.ui.obj_driver_playback.currentText()))
  409. elif self.fDriverName == "firewire":
  410. value = dbus.Boolean(self.ui.obj_driver_playback.currentIndex() == 1)
  411. else:
  412. value = None
  413. print("JackSettingsW::saveDriverSettings() - Cannot save playback value")
  414. if value != None:
  415. setDriverParameter("playback", value, True)
  416. elif resetIfNeeded:
  417. gJackctl.ResetParameterValue(["driver", "playback"])
  418. if self.ui.obj_driver_rate.isEnabled():
  419. value = dbus.UInt32(int(self.ui.obj_driver_rate.currentText()))
  420. setDriverParameter("rate", value, True)
  421. if self.ui.obj_driver_period.isEnabled():
  422. value = dbus.UInt32(int(self.ui.obj_driver_period.currentText()))
  423. setDriverParameter("period", value, True)
  424. if self.ui.obj_driver_nperiods.isEnabled():
  425. value = dbus.UInt32(self.ui.obj_driver_nperiods.value())
  426. setDriverParameter("nperiods", value, True)
  427. if self.ui.obj_driver_hwmon.isEnabled():
  428. value = dbus.Boolean(self.ui.obj_driver_hwmon.isChecked())
  429. setDriverParameter("hwmon", value, True)
  430. if self.ui.obj_driver_hwmeter.isEnabled():
  431. value = dbus.Boolean(self.ui.obj_driver_hwmeter.isChecked())
  432. setDriverParameter("hwmeter", value, True)
  433. if self.ui.obj_driver_duplex.isEnabled():
  434. value = dbus.Boolean(self.ui.obj_driver_duplex.isChecked())
  435. setDriverParameter("duplex", value, True)
  436. if self.ui.obj_driver_hw_alias.isEnabled():
  437. value = dbus.Boolean(self.ui.obj_driver_hw_alias.isChecked())
  438. setDriverParameter("hw-alias", value, True)
  439. if self.ui.obj_driver_softmode.isEnabled():
  440. value = dbus.Boolean(self.ui.obj_driver_softmode.isChecked())
  441. setDriverParameter("softmode", value, True)
  442. if self.ui.obj_driver_monitor.isEnabled():
  443. value = dbus.Boolean(self.ui.obj_driver_monitor.isChecked())
  444. setDriverParameter("monitor", value, True)
  445. if self.ui.obj_driver_dither.isEnabled():
  446. if self.ui.obj_driver_dither.currentIndex() == 0:
  447. value = dbus.Byte("n".encode("utf-8"))
  448. elif self.ui.obj_driver_dither.currentIndex() == 1:
  449. value = dbus.Byte("r".encode("utf-8"))
  450. elif self.ui.obj_driver_dither.currentIndex() == 2:
  451. value = dbus.Byte("s".encode("utf-8"))
  452. elif self.ui.obj_driver_dither.currentIndex() == 3:
  453. value = dbus.Byte("t".encode("utf-8"))
  454. else:
  455. value = None
  456. print("JackSettingsW::saveDriverSettings() - Cannot save dither value")
  457. if value != None:
  458. setDriverParameter("dither", value, True)
  459. if self.ui.obj_driver_inchannels.isEnabled():
  460. value = dbus.UInt32(self.ui.obj_driver_inchannels.value())
  461. if self.fDriverName == 'net':
  462. value = dbus.Int32(self.ui.obj_driver_inchannels.value())
  463. setDriverParameter("input-ports", value, True)
  464. else:
  465. value = dbus.UInt32(self.ui.obj_driver_inchannels.value())
  466. setDriverParameter("inchannels", value, True)
  467. if self.ui.obj_driver_outchannels.isEnabled():
  468. if self.fDriverName == 'net':
  469. value = dbus.Int32(self.ui.obj_driver_outchannels.value())
  470. setDriverParameter("output-ports", value, True)
  471. else:
  472. value = dbus.UInt32(self.ui.obj_driver_outchannels.value())
  473. setDriverParameter("outchannels", value, True)
  474. if self.ui.obj_driver_shorts.isEnabled():
  475. value = dbus.Boolean(self.ui.obj_driver_shorts.isChecked())
  476. setDriverParameter("shorts", value, True)
  477. if self.ui.obj_driver_input_latency.isEnabled():
  478. value = dbus.UInt32(self.ui.obj_driver_input_latency.value())
  479. setDriverParameter("input-latency", value, True)
  480. if self.ui.obj_driver_output_latency.isEnabled():
  481. value = dbus.UInt32(self.ui.obj_driver_output_latency.value())
  482. setDriverParameter("output-latency", value, True)
  483. if self.ui.obj_driver_midi_driver.isEnabled():
  484. if self.ui.obj_driver_midi_driver.currentIndex() == 0:
  485. value = dbus.String("none")
  486. elif self.ui.obj_driver_midi_driver.currentIndex() == 1:
  487. value = dbus.String("seq")
  488. elif self.ui.obj_driver_midi_driver.currentIndex() == 2:
  489. value = dbus.String("raw")
  490. else:
  491. value = None
  492. print("JackSettingsW::saveDriverSettings() - Cannot save midi-driver value")
  493. if value != None:
  494. if driverHasFeature("midi"):
  495. setDriverParameter("midi", value, True)
  496. else:
  497. setDriverParameter("midi-driver", value, True)
  498. if self.ui.obj_driver_wait.isEnabled():
  499. value = dbus.UInt32(self.ui.obj_driver_wait.value())
  500. setDriverParameter("wait", value, True)
  501. if self.ui.obj_driver_verbose.isEnabled():
  502. value = dbus.UInt32(self.ui.obj_driver_verbose.value())
  503. setDriverParameter("verbose", value, True)
  504. if self.ui.obj_driver_snoop.isEnabled():
  505. value = dbus.Boolean(self.ui.obj_driver_snoop.isChecked())
  506. setDriverParameter("snoop", value, True)
  507. if self.ui.obj_driver_channels.isEnabled():
  508. value = dbus.Int32(self.ui.obj_driver_channels.value())
  509. setDriverParameter("channels", value, True)
  510. if self.ui.obj_driver_client_name.isEnabled():
  511. value = dbus.String(self.ui.obj_driver_client_name.text())
  512. setDriverParameter("client-name", value, True)
  513. def loadDriverSettings(self, reset=False, forceReset=False):
  514. global gJackctl
  515. settings = gJackctl.ReadContainer(["driver"])
  516. for i in range(len(settings[1])):
  517. attribute = str(settings[1][i])
  518. if reset:
  519. value = gJackctl.GetParameterValue(["driver", attribute])[1]
  520. if forceReset:
  521. gJackctl.ResetParameterValue(["driver", attribute])
  522. else:
  523. value = gJackctl.GetParameterValue(["driver", attribute])[2]
  524. if attribute == "device":
  525. self.setComboBoxValue(self.ui.obj_driver_device, str(value), True)
  526. elif attribute == "capture":
  527. if self.fDriverName == "firewire":
  528. self.ui.obj_driver_capture.setCurrentIndex(1 if bool(value) else 0)
  529. else:
  530. self.setComboBoxValue(self.ui.obj_driver_capture, str(value), True)
  531. elif attribute == "playback":
  532. if self.fDriverName == "firewire":
  533. self.ui.obj_driver_playback.setCurrentIndex(1 if bool(value) else 0)
  534. else:
  535. self.setComboBoxValue(self.ui.obj_driver_playback, str(value), True)
  536. elif attribute == "rate":
  537. self.setComboBoxValue(self.ui.obj_driver_rate, str(value))
  538. elif attribute == "period":
  539. self.setComboBoxValue(self.ui.obj_driver_period, str(value))
  540. elif attribute == "nperiods":
  541. self.ui.obj_driver_nperiods.setValue(int(value))
  542. elif attribute == "hwmon":
  543. self.ui.obj_driver_hwmon.setChecked(bool(value))
  544. elif attribute == "hwmeter":
  545. self.ui.obj_driver_hwmeter.setChecked(bool(value))
  546. elif attribute == "duplex":
  547. self.ui.obj_driver_duplex.setChecked(bool(value))
  548. elif attribute == "hw-alias":
  549. self.ui.obj_driver_hw_alias.setChecked(bool(value))
  550. elif attribute == "softmode":
  551. self.ui.obj_driver_softmode.setChecked(bool(value))
  552. elif attribute == "monitor":
  553. self.ui.obj_driver_monitor.setChecked(bool(value))
  554. elif attribute == "dither":
  555. value = str(value)
  556. if value == "n":
  557. self.ui.obj_driver_dither.setCurrentIndex(0)
  558. elif value == "r":
  559. self.ui.obj_driver_dither.setCurrentIndex(1)
  560. elif value == "s":
  561. self.ui.obj_driver_dither.setCurrentIndex(2)
  562. elif value == "t":
  563. self.ui.obj_driver_dither.setCurrentIndex(3)
  564. else:
  565. self.ui.obj_driver_dither.setEnabled(False)
  566. print("JackSettingsW::loadDriverSettings() - Invalid dither value '%s'" % value)
  567. elif attribute == "inchannels":
  568. self.ui.obj_driver_inchannels.setValue(int(value))
  569. elif attribute == "outchannels":
  570. self.ui.obj_driver_outchannels.setValue(int(value))
  571. elif attribute == "shorts":
  572. self.ui.obj_driver_shorts.setChecked(bool(value))
  573. elif attribute == "input-latency":
  574. self.ui.obj_driver_input_latency.setValue(int(value))
  575. elif attribute == "output-latency":
  576. self.ui.obj_driver_output_latency.setValue(int(value))
  577. elif attribute in ("midi", "midi-driver"):
  578. value = str(value)
  579. if value == "none":
  580. self.ui.obj_driver_midi_driver.setCurrentIndex(0)
  581. elif value == "seq":
  582. self.ui.obj_driver_midi_driver.setCurrentIndex(1)
  583. elif value == "raw":
  584. self.ui.obj_driver_midi_driver.setCurrentIndex(2)
  585. else:
  586. self.ui.obj_driver_midi_driver.setEnabled(False)
  587. print("JackSettingsW::loadDriverSettings() - Invalid midi-driver value '%s'" % value)
  588. elif attribute == "wait":
  589. self.ui.obj_driver_wait.setValue(int(value))
  590. elif attribute == "verbose":
  591. self.ui.obj_driver_verbose.setValue(int(value))
  592. elif attribute == "snoop":
  593. self.ui.obj_driver_snoop.setChecked(bool(value))
  594. elif attribute == "channels":
  595. self.ui.obj_driver_channels.setValue(int(value))
  596. elif attribute == 'client-name':
  597. self.ui.obj_driver_client_name.setText(value)
  598. elif attribute == 'input-ports':
  599. self.ui.obj_driver_inchannels.setValue(int(value))
  600. elif attribute == 'output-ports':
  601. self.ui.obj_driver_outchannels.setValue(int(value))
  602. else:
  603. print("JackSettingsW::loadDriverSettings() - Unimplemented driver attribute '%s', value: '%s'" % (attribute, str(value)))
  604. def saveNetSettings(self):
  605. path = ['internals', 'netmanager']
  606. isset, default, value = map(
  607. dbus_type_to_python_type,
  608. gJackctl.GetParameterValue(path + ['multicast-ip']))
  609. curvalue = self.ui.obj_net_multicast_ip.text()
  610. if curvalue != value:
  611. gJackctl.SetParameterValue(
  612. path + ['multicast-ip'],
  613. python_type_to_jackdbus_type(curvalue, 's'))
  614. isset, default, value = map(
  615. dbus_type_to_python_type,
  616. gJackctl.GetParameterValue(path + ['udp-net-port']))
  617. curvalue = self.ui.obj_net_multicast_port.value()
  618. if curvalue != value:
  619. gJackctl.SetParameterValue(
  620. path + ['udp-net-port'],
  621. python_type_to_jackdbus_type(curvalue, 'u'))
  622. isset, default, value = map(
  623. dbus_type_to_python_type,
  624. gJackctl.GetParameterValue(path + ['auto-connect']))
  625. curvalue = self.ui.obj_net_auto_connect.isChecked()
  626. if curvalue != value:
  627. gJackctl.SetParameterValue(path + ['auto-connect'], curvalue)
  628. isset, default, value = map(
  629. dbus_type_to_python_type,
  630. gJackctl.GetParameterValue(path + ['auto-save']))
  631. curvalue = self.ui.obj_net_auto_save.isChecked()
  632. if curvalue != value:
  633. gJackctl.SetParameterValue(path + ['auto-save'], curvalue)
  634. GlobalSettings = QSettings("Cadence", "GlobalSettings")
  635. GlobalSettings.setValue('JACKNETMANAGER/AutoStart',
  636. self.ui.obj_net_manager_at_boot.isChecked())
  637. def loadNetSettings(self):
  638. path = ['internals', 'netmanager']
  639. _, _, value = map(
  640. dbus_type_to_python_type,
  641. gJackctl.GetParameterValue(path + ['multicast-ip']))
  642. self.ui.obj_net_multicast_ip.setText(value)
  643. _, _, value = map(
  644. dbus_type_to_python_type,
  645. gJackctl.GetParameterValue(path + ['udp-net-port']))
  646. self.ui.obj_net_multicast_port.setValue(value)
  647. _, _, value = map(
  648. dbus_type_to_python_type,
  649. gJackctl.GetParameterValue(path + ['auto-connect']))
  650. self.ui.obj_net_auto_connect.setChecked(value)
  651. _, _, value = map(
  652. dbus_type_to_python_type,
  653. gJackctl.GetParameterValue(path + ['auto-save']))
  654. self.ui.obj_net_auto_save.setChecked(value)
  655. GlobalSettings = QSettings("Cadence", "GlobalSettings")
  656. self.ui.obj_net_manager_at_boot.setChecked(
  657. GlobalSettings.value('JACKNETMANAGER/AutoStart') == "true")
  658. # -----------------------------------------------------------------
  659. # Helper functions
  660. def getAlsaDeviceList(self):
  661. alsaDeviceList = []
  662. aplay_out = getoutput("env LANG=C LC_ALL=C aplay -l").split("\n")
  663. for line in aplay_out:
  664. line = line.strip()
  665. if line.startswith("card "):
  666. cardInfo = line.split(", ", 1)[0].split(": ")
  667. cardIndex = cardInfo[0].replace("card ", "")
  668. cardName = cardInfo[1].split(" [")[0]
  669. deviceInfo = line.split(", ", 1)[1].split(": ")
  670. deviceIndex = deviceInfo[0].replace("device ", "")
  671. deviceName = deviceInfo[1].split(" [")[0]
  672. if cardName != "Loopback":
  673. fullName = "hw:%s,%s [%s]" % (cardName, deviceIndex, deviceName)
  674. alsaDeviceList.append(fullName)
  675. return alsaDeviceList
  676. def setComboBoxValue(self, box, text, split=False):
  677. for i in range(box.count()):
  678. if box.itemText(i) == text or (box.itemText(i).split(" ")[0] == text and split):
  679. box.setCurrentIndex(i)
  680. break
  681. else:
  682. if text:
  683. box.addItem(text)
  684. box.setCurrentIndex(box.count() - 1)
  685. # -----------------------------------------------------------------
  686. # Qt SLOT calls
  687. @pyqtSlot(int)
  688. def slot_checkALSASelection(self, ignored=0):
  689. if self.fDriverName == "alsa":
  690. check = bool(self.ui.obj_driver_duplex.isChecked() and (self.ui.obj_driver_capture.currentIndex() > 0 or self.ui.obj_driver_playback.currentIndex() > 0))
  691. self.ui.obj_driver_device.setEnabled(not check)
  692. @pyqtSlot(bool)
  693. def slot_checkDuplexSelection(self, active):
  694. if driverHasFeature("duplex"):
  695. self.ui.obj_driver_capture.setEnabled(active)
  696. self.ui.obj_driver_capture_label.setEnabled(active)
  697. self.ui.obj_driver_playback.setEnabled(active)
  698. self.ui.obj_driver_playback_label.setEnabled(active)
  699. #self.ui.obj_driver_inchannels.setEnabled(active)
  700. #self.ui.obj_driver_inchannels_label.setEnabled(active)
  701. #self.ui.obj_driver_input_latency.setEnabled(active)
  702. #self.ui.obj_driver_input_latency_label.setEnabled(active)
  703. self.slot_checkALSASelection()
  704. @pyqtSlot(int)
  705. def slot_checkDriverSelection(self, row):
  706. global gJackctl
  707. # Save previous settings
  708. self.saveDriverSettings(False)
  709. self.saveNetSettings()
  710. # Set new Jack driver
  711. self.fDriverName = dbus.String(self.ui.obj_server_driver.item(row, 0).text().lower())
  712. gJackctl.SetParameterValue(["engine", "driver"], self.fDriverName)
  713. # Add device list
  714. self.ui.obj_driver_device.clear()
  715. if driverHasFeature("device"):
  716. if LINUX and self.fDriverName == "alsa":
  717. dev_list = self.getAlsaDeviceList()
  718. for dev in dev_list:
  719. self.ui.obj_driver_device.addItem(dev)
  720. else:
  721. dev_list = gJackctl.GetParameterConstraint(["driver", "device"])[3]
  722. for i in range(len(dev_list)):
  723. self.ui.obj_driver_device.addItem(dev_list[i][0] + " [%s]" % str(dev_list[i][1]))
  724. # Custom 'playback' and 'capture' values
  725. self.ui.obj_driver_capture.clear()
  726. self.ui.obj_driver_playback.clear()
  727. if self.fDriverName == "alsa":
  728. self.ui.obj_driver_capture.addItem("none")
  729. self.ui.obj_driver_playback.addItem("none")
  730. if LINUX:
  731. dev_list = self.getAlsaDeviceList()
  732. for dev in dev_list:
  733. self.ui.obj_driver_capture.addItem(dev)
  734. self.ui.obj_driver_playback.addItem(dev)
  735. else:
  736. dev_list = gJackctl.GetParameterConstraint(["driver", "device"])[3]
  737. for i in range(len(dev_list)):
  738. self.ui.obj_driver_capture.addItem(dev_list[i][0] + " [" + dev_list[i][1] + "]")
  739. self.ui.obj_driver_playback.addItem(dev_list[i][0] + " [" + dev_list[i][1] + "]")
  740. elif self.fDriverName == "dummy":
  741. for i in range(16):
  742. self.ui.obj_driver_capture.addItem("%i" % int((i * 2) + 2))
  743. self.ui.obj_driver_playback.addItem("%i" % int((i * 2) + 2))
  744. elif self.fDriverName == "firewire":
  745. self.ui.obj_driver_capture.addItem("no")
  746. self.ui.obj_driver_capture.addItem("yes")
  747. self.ui.obj_driver_playback.addItem("no")
  748. self.ui.obj_driver_playback.addItem("yes")
  749. elif driverHasFeature("playback") or driverHasFeature("capture"):
  750. print("JackSettingsW::slot_checkDriverSelection() - Custom playback/capture for driver '%s' not implemented yet" % self.fDriverName)
  751. # Load Driver Settings
  752. self.loadDriverSettings()
  753. # Enable widgets according to driver
  754. self.ui.obj_driver_capture.setEnabled(driverHasFeature("capture"))
  755. self.ui.obj_driver_capture_label.setEnabled(driverHasFeature("capture"))
  756. self.ui.obj_driver_playback.setEnabled(driverHasFeature("playback"))
  757. self.ui.obj_driver_playback_label.setEnabled(driverHasFeature("playback"))
  758. self.ui.obj_driver_device.setEnabled(driverHasFeature("device"))
  759. self.ui.obj_driver_device_label.setEnabled(driverHasFeature("device"))
  760. self.ui.obj_driver_rate.setEnabled(driverHasFeature("rate"))
  761. self.ui.obj_driver_rate_label.setEnabled(driverHasFeature("rate"))
  762. self.ui.obj_driver_period.setEnabled(driverHasFeature("period"))
  763. self.ui.obj_driver_period_label.setEnabled(driverHasFeature("period"))
  764. self.ui.obj_driver_nperiods.setEnabled(driverHasFeature("nperiods"))
  765. self.ui.obj_driver_nperiods_label.setEnabled(driverHasFeature("nperiods"))
  766. self.ui.obj_driver_hwmon.setEnabled(driverHasFeature("hwmon"))
  767. self.ui.obj_driver_hwmeter.setEnabled(driverHasFeature("hwmeter"))
  768. self.ui.obj_driver_duplex.setEnabled(driverHasFeature("duplex"))
  769. self.ui.obj_driver_hw_alias.setEnabled(driverHasFeature("hw-alias"))
  770. self.ui.obj_driver_softmode.setEnabled(driverHasFeature("softmode"))
  771. self.ui.obj_driver_monitor.setEnabled(driverHasFeature("monitor"))
  772. self.ui.obj_driver_dither.setEnabled(driverHasFeature("dither"))
  773. self.ui.obj_driver_dither_label.setEnabled(driverHasFeature("dither"))
  774. self.ui.obj_driver_inchannels.setEnabled(driverHasFeature("inchannels") or driverHasFeature("input-ports"))
  775. self.ui.obj_driver_inchannels_label.setEnabled(driverHasFeature("inchannels") or driverHasFeature("input-ports"))
  776. self.ui.obj_driver_outchannels.setEnabled(driverHasFeature("outchannels") or driverHasFeature("output-ports"))
  777. self.ui.obj_driver_outchannels_label.setEnabled(driverHasFeature("outchannels") or driverHasFeature("output-ports"))
  778. self.ui.obj_driver_shorts.setEnabled(driverHasFeature("shorts"))
  779. self.ui.obj_driver_input_latency.setEnabled(driverHasFeature("input-latency"))
  780. self.ui.obj_driver_input_latency_label.setEnabled(driverHasFeature("input-latency"))
  781. self.ui.obj_driver_output_latency.setEnabled(driverHasFeature("output-latency"))
  782. self.ui.obj_driver_output_latency_label.setEnabled(driverHasFeature("output-latency"))
  783. self.ui.obj_driver_midi_driver.setEnabled(driverHasFeature("midi") or driverHasFeature("midi-driver"))
  784. self.ui.obj_driver_midi_driver_label.setEnabled(driverHasFeature("midi") or driverHasFeature("midi-driver"))
  785. self.ui.obj_driver_wait.setEnabled(driverHasFeature("wait"))
  786. self.ui.obj_driver_wait_label.setEnabled(driverHasFeature("wait"))
  787. self.ui.obj_driver_verbose.setEnabled(driverHasFeature("verbose"))
  788. self.ui.obj_driver_verbose_label.setEnabled(driverHasFeature("verbose"))
  789. self.ui.obj_driver_snoop.setEnabled(driverHasFeature("snoop"))
  790. self.ui.obj_driver_channels.setEnabled(driverHasFeature("channels"))
  791. self.ui.obj_driver_channels_label.setEnabled(driverHasFeature("channels"))
  792. self.ui.obj_driver_client_name.setEnabled(driverHasFeature("client-name"))
  793. # Misc stuff
  794. if self.ui.obj_server_driver.item(row, 0).text() == "ALSA":
  795. self.ui.toolbox_driver_misc.setCurrentIndex(1)
  796. self.ui.obj_driver_capture_label.setText(self.tr("Input Device:"))
  797. self.ui.obj_driver_playback_label.setText(self.tr("Output Device:"))
  798. elif self.ui.obj_server_driver.item(row, 0).text() == "Dummy":
  799. self.ui.toolbox_driver_misc.setCurrentIndex(2)
  800. self.ui.obj_driver_capture_label.setText(self.tr("Input Ports:"))
  801. self.ui.obj_driver_playback_label.setText(self.tr("Output Ports:"))
  802. elif self.ui.obj_server_driver.item(row, 0).text() == "FireWire":
  803. self.ui.toolbox_driver_misc.setCurrentIndex(3)
  804. self.ui.obj_driver_capture_label.setText(self.tr("Capture Ports:"))
  805. self.ui.obj_driver_playback_label.setText(self.tr("Playback Ports:"))
  806. elif self.ui.obj_server_driver.item(row, 0).text() == "Loopback":
  807. self.ui.toolbox_driver_misc.setCurrentIndex(4)
  808. elif self.ui.obj_server_driver.item(row, 0).text() == "Net":
  809. self.ui.toolbox_driver_misc.setCurrentIndex(5)
  810. else:
  811. self.ui.toolbox_driver_misc.setCurrentIndex(0)
  812. self.slot_checkDuplexSelection(self.ui.obj_driver_duplex.isChecked())
  813. def net_manager_start(self):
  814. jack_control_iface.LoadInternal("netmanager")
  815. def net_manager_stop(self):
  816. jack_control_iface.UnloadInternal("netmanager")
  817. def net_manager_reset(self):
  818. path = ['internals', 'netmanager']
  819. for _, name, _, _ in gJackctl.GetParametersInfo(path):
  820. gJackctl.ResetParameterValue(path + [name])
  821. GlobalSettings = QSettings("Cadence", "GlobalSettings")
  822. GlobalSettings.setValue('JACKNETMANAGER/AutoStart', False)
  823. self.loadNetSettings()
  824. @pyqtSlot()
  825. def slot_saveJackSettings(self):
  826. self.saveServerSettings()
  827. self.saveDriverSettings(True)
  828. self.saveNetSettings()
  829. @pyqtSlot()
  830. def slot_resetJackSettings(self):
  831. if self.ui.tabWidget.currentIndex() == 0:
  832. self.loadServerSettings(True, True)
  833. elif self.ui.tabWidget.currentIndex() == 1:
  834. self.loadDriverSettings(True, True)
  835. @pyqtSlot()
  836. def slot_closeWithError(self):
  837. QMessageBox.critical(self, self.tr("Error"), self.tr("jackdbus is not available!\nIt's not possible to configure JACK at this point."))
  838. self.close()
  839. def saveSettings(self):
  840. settings = QSettings("Cadence", "JackSettings")
  841. settings.setValue("Geometry", self.saveGeometry())
  842. settings.setValue("CurrentTab", self.ui.tabWidget.currentIndex())
  843. def loadSettings(self):
  844. settings = QSettings("Cadence", "JackSettings")
  845. self.restoreGeometry(settings.value("Geometry", b""))
  846. self.ui.tabWidget.setCurrentIndex(settings.value("CurrentTab", 0, type=int))
  847. def closeEvent(self, event):
  848. self.saveSettings()
  849. QDialog.closeEvent(self, event)
  850. def done(self, r):
  851. QDialog.done(self, r)
  852. self.close()
  853. # ------------------------------------------------------------------------------------------------------------
  854. # Allow to use this as a standalone app
  855. if __name__ == '__main__':
  856. # Additional imports
  857. import resources_rc
  858. from sys import argv as sys_argv, exit as sys_exit
  859. from PyQt5.QtGui import QIcon
  860. from PyQt5.QtWidgets import QApplication
  861. # App initialization
  862. app = QApplication(sys_argv)
  863. # Connect to DBus
  864. if dbus:
  865. if initBus(dbus.SessionBus()):
  866. QMessageBox.critical(None, app.translate("JackSettingsW", "Error"), app.translate("JackSettingsW",
  867. "jackdbus is not available!\n"
  868. "Is not possible to configure JACK at this point."))
  869. sys_exit(1)
  870. else:
  871. QMessageBox.critical(None, app.translate("JackSettingsW", "Error"),
  872. app.translate("JackSettingsW", "DBus is not available, cannot continue."))
  873. sys_exit(1)
  874. # Show GUI
  875. gui = JackSettingsW(None)
  876. gui.setWindowIcon(QIcon(":/scalable/jack.svg"))
  877. gui.show()
  878. # App-Loop
  879. sys_exit(app.exec_())