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.

938 lines
40KB

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