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.

2122 lines
85KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # ...
  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 platform import architecture
  19. from PyQt4.QtCore import QThread
  20. from PyQt4.QtGui import QApplication, QLabel, QMainWindow, QSizePolicy
  21. from subprocess import getoutput
  22. # Imports (Custom Stuff)
  23. import ui_cadence
  24. import ui_cadence_tb_jack, ui_cadence_tb_alsa, ui_cadence_tb_a2j, ui_cadence_tb_pa, ui_cadence_rwait
  25. import systray
  26. from shared_cadence import *
  27. from shared_jack import *
  28. from shared_settings import *
  29. try:
  30. import dbus
  31. from dbus.mainloop.qt import DBusQtMainLoop
  32. haveDBus = True
  33. except:
  34. haveDBus = False
  35. havePulseAudio = os.path.exists("/usr/bin/pulseaudio")
  36. haveWine = os.path.exists("/usr/bin/regedit")
  37. if haveWine:
  38. WINEPREFIX = os.getenv("WINEPREFIX")
  39. if not WINEPREFIX:
  40. WINEPREFIX = os.path.join(HOME, ".wine")
  41. # ---------------------------------------------------------------------
  42. DESKTOP_X_IMAGE = [
  43. "eog.desktop",
  44. "kde4/digikam.desktop",
  45. "kde4/gwenview.desktop"
  46. ]
  47. DESKTOP_X_MUSIC = [
  48. "audacious.desktop",
  49. "clementine.desktop",
  50. "smplayer.desktop",
  51. "vlc.desktop",
  52. "kde4/amarok.desktop"
  53. ]
  54. DESKTOP_X_VIDEO = [
  55. "smplayer.desktop",
  56. "vlc.desktop"
  57. ]
  58. DESKTOP_X_TEXT = [
  59. "gedit.desktop",
  60. "kde4/kate.desktop",
  61. "kde4/kwrite.desktop"
  62. ]
  63. DESKTOP_X_BROWSER = [
  64. "chrome.desktop",
  65. "firefox.desktop",
  66. "kde4/konqbrowser.desktop"
  67. ]
  68. XDG_APPLICATIONS_PATH = [
  69. "/usr/share/applications",
  70. "/usr/local/share/applications"
  71. ]
  72. WINEASIO_PREFIX = "HKEY_CURRENT_USER\Software\Wine\WineASIO"
  73. # ---------------------------------------------------------------------
  74. global jackClientIdALSA, jackClientIdPulse
  75. jackClientIdALSA = -1
  76. jackClientIdPulse = -1
  77. # jackdbus indexes
  78. iGraphVersion = 0
  79. iJackClientId = 1
  80. iJackClientName = 2
  81. iJackPortId = 3
  82. iJackPortName = 4
  83. iJackPortNewName = 5
  84. iJackPortFlags = 5
  85. iJackPortType = 6
  86. asoundrc_aloop = (""
  87. "# ------------------------------------------------------\n"
  88. "# Custom asoundrc file for use with snd-aloop and JACK\n"
  89. "#\n"
  90. "# use it like this:\n"
  91. "# env JACK_SAMPLE_RATE=44100 JACK_PERIOD_SIZE=1024 alsa_in (...)\n"
  92. "#\n"
  93. "\n"
  94. "# ------------------------------------------------------\n"
  95. "# playback device\n"
  96. "pcm.aloopPlayback {\n"
  97. " type dmix\n"
  98. " ipc_key 1\n"
  99. " ipc_key_add_uid true\n"
  100. " slave {\n"
  101. " pcm \"hw:Loopback,0,0\"\n"
  102. " format S32_LE\n"
  103. " rate {\n"
  104. " @func igetenv\n"
  105. " vars [ JACK_SAMPLE_RATE ]\n"
  106. " default 44100\n"
  107. " }\n"
  108. " period_size {\n"
  109. " @func igetenv\n"
  110. " vars [ JACK_PERIOD_SIZE ]\n"
  111. " default 1024\n"
  112. " }\n"
  113. " buffer_size 4096\n"
  114. " }\n"
  115. "}\n"
  116. "\n"
  117. "# capture device\n"
  118. "pcm.aloopCapture {\n"
  119. " type dsnoop\n"
  120. " ipc_key 2\n"
  121. " ipc_key_add_uid true\n"
  122. " slave {\n"
  123. " pcm \"hw:Loopback,0,1\"\n"
  124. " format S32_LE\n"
  125. " rate {\n"
  126. " @func igetenv\n"
  127. " vars [ JACK_SAMPLE_RATE ]\n"
  128. " default 44100\n"
  129. " }\n"
  130. " period_size {\n"
  131. " @func igetenv\n"
  132. " vars [ JACK_PERIOD_SIZE ]\n"
  133. " default 1024\n"
  134. " }\n"
  135. " buffer_size 4096\n"
  136. " }\n"
  137. "}\n"
  138. "\n"
  139. "# duplex device\n"
  140. "pcm.aloopDuplex {\n"
  141. " type asym\n"
  142. " playback.pcm \"aloopPlayback\"\n"
  143. " capture.pcm \"aloopCapture\"\n"
  144. "}\n"
  145. "\n"
  146. "# ------------------------------------------------------\n"
  147. "# default device\n"
  148. "pcm.!default {\n"
  149. " type plug\n"
  150. " slave.pcm \"aloopDuplex\"\n"
  151. "}\n"
  152. "\n"
  153. "# ------------------------------------------------------\n"
  154. "# alsa_in -j alsa_in -dcloop -q 1\n"
  155. "pcm.cloop {\n"
  156. " type dsnoop\n"
  157. " ipc_key 3\n"
  158. " ipc_key_add_uid true\n"
  159. " slave {\n"
  160. " pcm \"hw:Loopback,1,0\"\n"
  161. " format S32_LE\n"
  162. " rate {\n"
  163. " @func igetenv\n"
  164. " vars [ JACK_SAMPLE_RATE ]\n"
  165. " default 44100\n"
  166. " }\n"
  167. " period_size {\n"
  168. " @func igetenv\n"
  169. " vars [ JACK_PERIOD_SIZE ]\n"
  170. " default 1024\n"
  171. " }\n"
  172. " buffer_size 4096\n"
  173. " }\n"
  174. "}\n"
  175. "\n"
  176. "# ------------------------------------------------------\n"
  177. "# alsa_out -j alsa_out -dploop -q 1\n"
  178. "pcm.ploop {\n"
  179. " type plug\n"
  180. " slave {\n"
  181. " pcm \"hw:Loopback,1,1\"\n"
  182. " }\n"
  183. "}")
  184. asoundrc_jack = (""
  185. "pcm.!default {\n"
  186. " type plug\n"
  187. " slave { pcm \"jack\" }\n"
  188. "}\n"
  189. "\n"
  190. "pcm.jack {\n"
  191. " type jack\n"
  192. " playback_ports {\n"
  193. " 0 system:playback_1\n"
  194. " 1 system:playback_2\n"
  195. " }\n"
  196. " capture_ports {\n"
  197. " 0 system:capture_1\n"
  198. " 1 system:capture_2\n"
  199. " }\n"
  200. "}\n"
  201. "\n"
  202. "ctl.mixer0 {\n"
  203. " type hw\n"
  204. " card 0\n"
  205. "}")
  206. asoundrc_pulse = (""
  207. "pcm.!default {\n"
  208. " type plug\n"
  209. " slave { pcm \"pulse\" }\n"
  210. "}\n"
  211. "\n"
  212. "pcm.pulse {\n"
  213. " type pulse\n"
  214. "}\n"
  215. "\n"
  216. "ctl.mixer0 {\n"
  217. " type hw\n"
  218. " card 0\n"
  219. "}")
  220. # ---------------------------------------------------------------------
  221. def get_architecture():
  222. return architecture()[0]
  223. def get_haiku_information():
  224. # TODO
  225. return ("Haiku OS", "Unknown")
  226. def get_linux_information():
  227. if os.path.exists("/etc/lsb-release"):
  228. distro = getoutput(". /etc/lsb-release && echo $DISTRIB_DESCRIPTION")
  229. elif os.path.exists("/etc/arch-release"):
  230. distro = "ArchLinux"
  231. else:
  232. distro = os.uname()[0]
  233. kernel = os.uname()[2]
  234. return (distro, kernel)
  235. def get_mac_information():
  236. # TODO
  237. return ("Mac OS", "Unknown")
  238. def get_windows_information():
  239. major = sys.getwindowsversion()[0]
  240. minor = sys.getwindowsversion()[1]
  241. servp = sys.getwindowsversion()[4]
  242. os = "Windows"
  243. version = servp
  244. if major == 4 and minor == 0:
  245. os = "Windows 95"
  246. version = "RTM"
  247. elif major == 4 and minor == 10:
  248. os = "Windows 98"
  249. version = "Second Edition"
  250. elif major == 5 and minor == 0:
  251. os = "Windows 2000"
  252. elif major == 5 and minor == 1:
  253. os = "Windows XP"
  254. elif major == 5 and minor == 2:
  255. os = "Windows Server 2003"
  256. elif major == 6 and minor == 0:
  257. os = "Windows Vista"
  258. elif major == 6 and minor == 1:
  259. os = "Windows 7"
  260. elif major == 6 and minor == 2:
  261. os = "Windows 8"
  262. return (os, version)
  263. # ---------------------------------------------------------------------
  264. def isAlsaAudioBridged():
  265. global jackClientIdALSA
  266. return bool(jackClientIdALSA != -1)
  267. def isPulseAudioStarted():
  268. return bool("pulseaudio" in getProcList())
  269. def isPulseAudioBridged():
  270. global jackClientIdPulse
  271. return bool(jackClientIdPulse != -1)
  272. def isDesktopFileInstalled(desktop):
  273. for X_PATH in XDG_APPLICATIONS_PATH:
  274. if os.path.exists(os.path.join(X_PATH, desktop)):
  275. return True
  276. return False
  277. def getDesktopFileContents(desktop):
  278. for X_PATH in XDG_APPLICATIONS_PATH:
  279. if os.path.exists(os.path.join(X_PATH, desktop)):
  280. fd = open(os.path.join(X_PATH, desktop), "r")
  281. contents = fd.read()
  282. fd.close()
  283. return contents
  284. return None
  285. def getXdgProperty(fileRead, key):
  286. fileReadSplit = fileRead.split(key, 1)
  287. if len(fileReadSplit) > 1:
  288. fileReadLine = fileReadSplit[1].split("\n",1)[0]
  289. fileReadLineStripped = fileReadLine.rsplit(";",1)[0].strip()
  290. value = fileReadLineStripped.replace("=","",1)
  291. return value
  292. return None
  293. def getWineAsioKeyValue(key, default):
  294. wineFile = os.path.join(WINEPREFIX, "user.reg")
  295. if not os.path.exists(wineFile):
  296. return default
  297. wineDumpF = open(wineFile, "r")
  298. wineDump = wineDumpF.read()
  299. wineDumpF.close()
  300. wineDumpSplit = wineDump.split("[Software\\\\Wine\\\\WineASIO]")
  301. if len(wineDumpSplit) <= 1:
  302. return default
  303. wineDumpSmall = wineDumpSplit[1].split("[")[0]
  304. keyDumpSplit = wineDumpSmall.split('"%s"' % key)
  305. if len(keyDumpSplit) <= 1:
  306. return default
  307. keyDumpSmall = keyDumpSplit[1].split(":")[1].split("\n")[0]
  308. return keyDumpSmall
  309. def searchAndSetComboBoxValue(comboBox, value):
  310. for i in range(comboBox.count()):
  311. if comboBox.itemText(i).replace("/","-") == value:
  312. comboBox.setCurrentIndex(i)
  313. comboBox.setEnabled(True)
  314. return True
  315. return False
  316. def smartHex(value, length):
  317. hexStr = hex(value).replace("0x","")
  318. if len(hexStr) < length:
  319. zeroCount = length - len(hexStr)
  320. hexStr = "%s%s" % ("0"*zeroCount, hexStr)
  321. return hexStr
  322. # ---------------------------------------------------------------------
  323. cadenceSystemChecks = []
  324. class CadenceSystemCheck(object):
  325. ICON_ERROR = 0
  326. ICON_WARN = 1
  327. ICON_OK = 2
  328. def __init__(self):
  329. object.__init__(self)
  330. self.name = self.tr("check")
  331. self.icon = self.ICON_OK
  332. self.result = self.tr("yes")
  333. self.moreInfo = self.tr("nothing to report")
  334. def tr(self, text):
  335. return app.translate("CadenceSystemCheck", text)
  336. class CadenceSystemCheck_audioGroup(CadenceSystemCheck):
  337. def __init__(self):
  338. CadenceSystemCheck.__init__(self)
  339. self.name = self.tr("User in audio group")
  340. user = getoutput("whoami").strip()
  341. groups = getoutput("groups").strip().split(" ")
  342. if "audio" in groups:
  343. self.icon = self.ICON_OK
  344. self.result = self.tr("Yes")
  345. self.moreInfo = None
  346. else:
  347. fd = open("/etc/group", "r")
  348. groupRead = fd.read().strip().split("\n")
  349. fd.close()
  350. onAudioGroup = False
  351. for lineRead in groupRead:
  352. if lineRead.startswith("audio:"):
  353. groups = lineRead.split(":")[-1].split(",")
  354. if user in groups:
  355. onAudioGroup = True
  356. break
  357. if onAudioGroup:
  358. self.icon = self.ICON_WARN
  359. self.result = self.tr("Yes, but needs relogin")
  360. self.moreInfo = None
  361. else:
  362. self.icon = self.ICON_ERROR
  363. self.result = self.tr("No")
  364. self.moreInfo = None
  365. class CadenceSystemCheck_kernel(CadenceSystemCheck):
  366. def __init__(self):
  367. CadenceSystemCheck.__init__(self)
  368. self.name = self.tr("Current kernel")
  369. uname3 = os.uname()[2]
  370. versionInt = []
  371. versionStr = uname3.split("-",1)[0]
  372. versionSplit = versionStr.split(".")
  373. for split in versionSplit:
  374. if split.isdigit():
  375. versionInt.append(int(split))
  376. else:
  377. versionInt = [0, 0, 0]
  378. break
  379. self.result = versionStr + " "
  380. if "-" not in uname3:
  381. self.icon = self.ICON_WARN
  382. self.result += self.tr("Vanilla")
  383. self.moreInfo = None
  384. else:
  385. if uname3.endswith("-pae"):
  386. kernelType = uname3.split("-")[-2].lower()
  387. self.result += kernelType.title() + " (PAE)"
  388. else:
  389. kernelType = uname3.split("-")[-1].lower()
  390. self.result += kernelType.title()
  391. if kernelType in ("rt", "realtime") or (kernelType == "lowlatency" and versionInt >= [2, 6, 39]):
  392. self.icon = self.ICON_OK
  393. self.moreInfo = None
  394. elif versionInt >= [2, 6, 39]:
  395. self.icon = self.ICON_WARN
  396. self.moreInfo = None
  397. else:
  398. self.icon = self.ICON_ERROR
  399. self.moreInfo = None
  400. def initSystemChecks():
  401. if LINUX:
  402. cadenceSystemChecks.append(CadenceSystemCheck_kernel())
  403. cadenceSystemChecks.append(CadenceSystemCheck_audioGroup())
  404. # ---------------------------------------------------------------------
  405. # Wait while JACK restarts
  406. class ForceRestartThread(QThread):
  407. def __init__(self, parent):
  408. QThread.__init__(self, parent)
  409. self.m_wasStarted = False
  410. def wasJackStarted(self):
  411. return self.m_wasStarted
  412. def run(self):
  413. # Not started yet
  414. self.m_wasStarted = False
  415. self.emit(SIGNAL("progressChanged(int)"), 0)
  416. # Kill All
  417. stopAllAudioProcesses()
  418. self.emit(SIGNAL("progressChanged(int)"), 30)
  419. # Connect to jackdbus
  420. self.parent().DBusReconnect()
  421. if not DBus.jack:
  422. return
  423. for x in range(30):
  424. self.emit(SIGNAL("progressChanged(int)"), 30+x*2)
  425. procsList = getProcList()
  426. if "jackdbus" in procsList:
  427. break
  428. else:
  429. sleep(0.1)
  430. self.emit(SIGNAL("progressChanged(int)"), 90)
  431. # Start it
  432. DBus.jack.StartServer()
  433. self.emit(SIGNAL("progressChanged(int)"), 93)
  434. # If we made it this far, then JACK is started
  435. self.m_wasStarted = True
  436. # Start bridges according to user settings
  437. # ALSA-Audio
  438. if GlobalSettings.value("ALSA-Audio/BridgeIndexType", iAlsaFileNone, type=int) == iAlsaFileLoop:
  439. os.system("cadence-aloop-daemon &")
  440. sleep(0.5)
  441. self.emit(SIGNAL("progressChanged(int)"), 94)
  442. # ALSA-MIDI
  443. if GlobalSettings.value("A2J/AutoStart", True, type=bool) and DBus.a2j and not bool(DBus.a2j.is_started()):
  444. a2jExportHW = GlobalSettings.value("A2J/ExportHW", True, type=bool)
  445. DBus.a2j.set_hw_export(a2jExportHW)
  446. DBus.a2j.start()
  447. self.emit(SIGNAL("progressChanged(int)"), 96)
  448. # PulseAudio
  449. if GlobalSettings.value("Pulse2JACK/AutoStart", True, type=bool) and not isPulseAudioBridged():
  450. if GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool):
  451. os.system("cadence-pulse2jack -p")
  452. else:
  453. os.system("cadence-pulse2jack")
  454. self.emit(SIGNAL("progressChanged(int)"), 100)
  455. # Force Restart Dialog
  456. class ForceWaitDialog(QDialog, ui_cadence_rwait.Ui_Dialog):
  457. def __init__(self, parent):
  458. QDialog.__init__(self, parent)
  459. self.setupUi(self)
  460. self.setWindowFlags(Qt.Dialog|Qt.WindowCloseButtonHint)
  461. self.rThread = ForceRestartThread(self)
  462. self.rThread.start()
  463. self.connect(self.rThread, SIGNAL("progressChanged(int)"), self.progressBar, SLOT("setValue(int)"))
  464. self.connect(self.rThread, SIGNAL("finished()"), SLOT("slot_rThreadFinished()"))
  465. def DBusReconnect(self):
  466. self.parent().DBusReconnect()
  467. @pyqtSlot()
  468. def slot_rThreadFinished(self):
  469. self.close()
  470. if self.rThread.wasJackStarted():
  471. QMessageBox.information(self, self.tr("Info"), self.tr("JACK was re-started sucessfully"))
  472. else:
  473. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not start JACK!"))
  474. def done(self, r):
  475. QDialog.done(self, r)
  476. self.close()
  477. # Additional JACK options
  478. class ToolBarJackDialog(QDialog, ui_cadence_tb_jack.Ui_Dialog):
  479. def __init__(self, parent):
  480. QDialog.__init__(self, parent)
  481. self.setupUi(self)
  482. self.m_ladishLoaded = False
  483. if haveDBus:
  484. if GlobalSettings.value("JACK/AutoLoadLadishStudio", False, type=bool):
  485. self.rb_ladish.setChecked(True)
  486. self.m_ladishLoaded = True
  487. elif "org.ladish" in DBus.bus.list_names():
  488. self.m_ladishLoaded = True
  489. else:
  490. self.rb_ladish.setEnabled(False)
  491. self.rb_jack.setChecked(True)
  492. if self.m_ladishLoaded:
  493. self.fillStudioNames()
  494. self.connect(self, SIGNAL("accepted()"), SLOT("slot_setOptions()"))
  495. self.connect(self.rb_ladish, SIGNAL("clicked()"), SLOT("slot_maybeFillStudioNames()"))
  496. def fillStudioNames(self):
  497. DBus.ladish_control = DBus.bus.get_object("org.ladish", "/org/ladish/Control")
  498. ladishStudioName = dbus.String(GlobalSettings.value("JACK/LadishStudioName", "", type=str))
  499. ladishStudioListDump = DBus.ladish_control.GetStudioList()
  500. if len(ladishStudioListDump) == 0:
  501. self.rb_ladish.setEnabled(False)
  502. self.rb_jack.setChecked(True)
  503. else:
  504. i=0
  505. for thisStudioName, thisStudioDict in ladishStudioListDump:
  506. self.cb_studio_name.addItem(thisStudioName)
  507. if ladishStudioName and thisStudioName == ladishStudioName:
  508. self.cb_studio_name.setCurrentIndex(i)
  509. i += 1
  510. @pyqtSlot()
  511. def slot_maybeFillStudioNames(self):
  512. if not self.m_ladishLoaded:
  513. self.fillStudioNames()
  514. self.m_ladishLoaded = True
  515. @pyqtSlot()
  516. def slot_setOptions(self):
  517. GlobalSettings.setValue("JACK/AutoLoadLadishStudio", self.rb_ladish.isChecked())
  518. GlobalSettings.setValue("JACK/LadishStudioName", self.cb_studio_name.currentText())
  519. def done(self, r):
  520. QDialog.done(self, r)
  521. self.close()
  522. # Additional ALSA Audio options
  523. class ToolBarAlsaAudioDialog(QDialog, ui_cadence_tb_alsa.Ui_Dialog):
  524. def __init__(self, parent):
  525. QDialog.__init__(self, parent)
  526. self.setupUi(self)
  527. asoundrcFile = os.path.join(HOME, ".asoundrc")
  528. asoundrcFd = open(asoundrcFile, "r")
  529. asoundrcRead = asoundrcFd.read().strip()
  530. asoundrcFd.close()
  531. self.textBrowser.setPlainText(asoundrcRead)
  532. def done(self, r):
  533. QDialog.done(self, r)
  534. self.close()
  535. # Additional ALSA MIDI options
  536. class ToolBarA2JDialog(QDialog, ui_cadence_tb_a2j.Ui_Dialog):
  537. def __init__(self, parent):
  538. QDialog.__init__(self, parent)
  539. self.setupUi(self)
  540. self.cb_export_hw.setChecked(GlobalSettings.value("A2J/ExportHW", True, type=bool))
  541. self.connect(self, SIGNAL("accepted()"), SLOT("slot_setOptions()"))
  542. @pyqtSlot()
  543. def slot_setOptions(self):
  544. GlobalSettings.setValue("A2J/ExportHW", self.cb_export_hw.isChecked())
  545. def done(self, r):
  546. QDialog.done(self, r)
  547. self.close()
  548. # Additional PulseAudio options
  549. class ToolBarPADialog(QDialog, ui_cadence_tb_pa.Ui_Dialog):
  550. def __init__(self, parent):
  551. QDialog.__init__(self, parent)
  552. self.setupUi(self)
  553. self.cb_playback_only.setChecked(GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool))
  554. self.connect(self, SIGNAL("accepted()"), SLOT("slot_setOptions()"))
  555. @pyqtSlot()
  556. def slot_setOptions(self):
  557. GlobalSettings.setValue("Pulse2JACK/PlaybackModeOnly", self.cb_playback_only.isChecked())
  558. def done(self, r):
  559. QDialog.done(self, r)
  560. self.close()
  561. # Main Window
  562. class CadenceMainW(QMainWindow, ui_cadence.Ui_CadenceMainW):
  563. def __init__(self, parent=None):
  564. QMainWindow.__init__(self, parent)
  565. self.setupUi(self)
  566. self.settings = QSettings("Cadence", "Cadence")
  567. self.loadSettings(True)
  568. self.pix_apply = QIcon(getIcon("dialog-ok-apply", 16)).pixmap(16, 16)
  569. self.pix_cancel = QIcon(getIcon("dialog-cancel", 16)).pixmap(16, 16)
  570. self.pix_error = QIcon(getIcon("dialog-error", 16)).pixmap(16, 16)
  571. self.pix_warning = QIcon(getIcon("dialog-warning", 16)).pixmap(16, 16)
  572. self.m_lastAlsaIndexType = -2 # invalid
  573. # -------------------------------------------------------------
  574. # Set-up GUI (System Information)
  575. if HAIKU:
  576. info = get_haiku_information()
  577. elif LINUX:
  578. info = get_linux_information()
  579. elif MACOS:
  580. info = get_mac_information()
  581. elif WINDOWS:
  582. info = get_windows_information()
  583. else:
  584. info = ("Unknown", "Unknown")
  585. self.label_info_os.setText(info[0])
  586. self.label_info_version.setText(info[1])
  587. self.label_info_arch.setText(get_architecture())
  588. # -------------------------------------------------------------
  589. # Set-up GUI (System Checks)
  590. #self.label_check_helper1.setVisible(False)
  591. #self.label_check_helper2.setVisible(False)
  592. #self.label_check_helper3.setVisible(False)
  593. index = 2
  594. checksLayout = self.groupBox_checks.layout()
  595. for check in cadenceSystemChecks:
  596. widgetName = QLabel("%s:" % check.name)
  597. widgetIcon = QLabel("")
  598. widgetResult = QLabel(check.result)
  599. if check.moreInfo:
  600. widgetName.setToolTip(check.moreInfo)
  601. widgetIcon.setToolTip(check.moreInfo)
  602. widgetResult.setToolTip(check.moreInfo)
  603. #widgetName.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
  604. #widgetIcon.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
  605. #widgetIcon.setMinimumSize(16, 16)
  606. #widgetIcon.setMaximumSize(16, 16)
  607. #widgetResult.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
  608. if check.icon == check.ICON_ERROR:
  609. widgetIcon.setPixmap(self.pix_error)
  610. elif check.icon == check.ICON_WARN:
  611. widgetIcon.setPixmap(self.pix_warning)
  612. elif check.icon == check.ICON_OK:
  613. widgetIcon.setPixmap(self.pix_apply)
  614. else:
  615. widgetIcon.setPixmap(self.pix_cancel)
  616. checksLayout.addWidget(widgetName, index, 0, Qt.AlignRight)
  617. checksLayout.addWidget(widgetIcon, index, 1, Qt.AlignHCenter)
  618. checksLayout.addWidget(widgetResult, index, 2, Qt.AlignLeft)
  619. index += 1
  620. # -------------------------------------------------------------
  621. # Set-up GUI (Tweaks)
  622. self.settings_changed_types = []
  623. self.frame_tweaks_settings.setVisible(False)
  624. for i in range(self.tw_tweaks.rowCount()):
  625. self.tw_tweaks.item(0, i).setTextAlignment(Qt.AlignCenter)
  626. self.tw_tweaks.setCurrentCell(0, 0)
  627. # -------------------------------------------------------------
  628. # Set-up GUI (Tweaks, Audio Plugins PATH)
  629. self.b_tweak_plugins_change.setEnabled(False)
  630. self.b_tweak_plugins_remove.setEnabled(False)
  631. for iPath in DEFAULT_LADSPA_PATH:
  632. self.list_LADSPA.addItem(iPath)
  633. for iPath in DEFAULT_DSSI_PATH:
  634. self.list_DSSI.addItem(iPath)
  635. for iPath in DEFAULT_LV2_PATH:
  636. self.list_LV2.addItem(iPath)
  637. for iPath in DEFAULT_VST_PATH:
  638. self.list_VST.addItem(iPath)
  639. EXTRA_LADSPA_DIRS = GlobalSettings.value("AudioPlugins/EXTRA_LADSPA_PATH", "", type=str)
  640. EXTRA_DSSI_DIRS = GlobalSettings.value("AudioPlugins/EXTRA_DSSI_PATH", "", type=str)
  641. EXTRA_LV2_DIRS = GlobalSettings.value("AudioPlugins/EXTRA_LV2_PATH", "", type=str)
  642. EXTRA_VST_DIRS = GlobalSettings.value("AudioPlugins/EXTRA_VST_PATH", "", type=str)
  643. for iPath in EXTRA_LADSPA_DIRS.split(":"):
  644. if os.path.exists(iPath):
  645. self.list_LADSPA.addItem(iPath)
  646. for iPath in EXTRA_DSSI_DIRS.split(":"):
  647. if os.path.exists(iPath):
  648. self.list_DSSI.addItem(iPath)
  649. for iPath in EXTRA_LV2_DIRS.split(":"):
  650. if os.path.exists(iPath):
  651. self.list_LV2.addItem(iPath)
  652. for iPath in EXTRA_VST_DIRS.split(":"):
  653. if os.path.exists(iPath):
  654. self.list_VST.addItem(iPath)
  655. self.list_LADSPA.sortItems(Qt.AscendingOrder)
  656. self.list_DSSI.sortItems(Qt.AscendingOrder)
  657. self.list_LV2.sortItems(Qt.AscendingOrder)
  658. self.list_VST.sortItems(Qt.AscendingOrder)
  659. self.list_LADSPA.setCurrentRow(0)
  660. self.list_DSSI.setCurrentRow(0)
  661. self.list_LV2.setCurrentRow(0)
  662. self.list_VST.setCurrentRow(0)
  663. # -------------------------------------------------------------
  664. # Set-up GUI (Tweaks, Default Applications)
  665. for desktop in DESKTOP_X_IMAGE:
  666. if isDesktopFileInstalled(desktop):
  667. self.cb_app_image.addItem(desktop)
  668. for desktop in DESKTOP_X_MUSIC:
  669. if isDesktopFileInstalled(desktop):
  670. self.cb_app_music.addItem(desktop)
  671. for desktop in DESKTOP_X_VIDEO:
  672. if isDesktopFileInstalled(desktop):
  673. self.cb_app_video.addItem(desktop)
  674. for desktop in DESKTOP_X_TEXT:
  675. if isDesktopFileInstalled(desktop):
  676. self.cb_app_text.addItem(desktop)
  677. for desktop in DESKTOP_X_BROWSER:
  678. if isDesktopFileInstalled(desktop):
  679. self.cb_app_browser.addItem(desktop)
  680. if self.cb_app_image.count() == 0:
  681. self.ch_app_image.setEnabled(False)
  682. if self.cb_app_music.count() == 0:
  683. self.ch_app_music.setEnabled(False)
  684. if self.cb_app_video.count() == 0:
  685. self.ch_app_video.setEnabled(False)
  686. if self.cb_app_text.count() == 0:
  687. self.ch_app_text.setEnabled(False)
  688. if self.cb_app_browser.count() == 0:
  689. self.ch_app_browser.setEnabled(False)
  690. mimeappsPath = os.path.join(HOME, ".local", "share", "applications", "mimeapps.list")
  691. if os.path.exists(mimeappsPath):
  692. fd = open(mimeappsPath, "r")
  693. mimeappsRead = fd.read()
  694. fd.close()
  695. x_image = getXdgProperty(mimeappsRead, "image/bmp")
  696. x_music = getXdgProperty(mimeappsRead, "audio/wav")
  697. x_video = getXdgProperty(mimeappsRead, "video/webm")
  698. x_text = getXdgProperty(mimeappsRead, "text/plain")
  699. x_browser = getXdgProperty(mimeappsRead, "text/html")
  700. if x_image and searchAndSetComboBoxValue(self.cb_app_image, x_image):
  701. self.ch_app_image.setChecked(True)
  702. if x_music and searchAndSetComboBoxValue(self.cb_app_music, x_music):
  703. self.ch_app_music.setChecked(True)
  704. if x_video and searchAndSetComboBoxValue(self.cb_app_video, x_video):
  705. self.ch_app_video.setChecked(True)
  706. if x_text and searchAndSetComboBoxValue(self.cb_app_text, x_text):
  707. self.ch_app_text.setChecked(True)
  708. if x_browser and searchAndSetComboBoxValue(self.cb_app_browser, x_browser):
  709. self.ch_app_browser.setChecked(True)
  710. else: # ~/.local/share/applications/mimeapps.list doesn't exist
  711. if not os.path.exists(os.path.join(HOME, ".local")):
  712. os.mkdir(os.path.join(HOME, ".local"))
  713. elif not os.path.exists(os.path.join(HOME, ".local", "share")):
  714. os.mkdir(os.path.join(HOME, ".local", "share"))
  715. elif not os.path.exists(os.path.join(HOME, ".local", "share", "applications")):
  716. os.mkdir(os.path.join(HOME, ".local", "share", "applications"))
  717. # -------------------------------------------------------------
  718. # Set-up GUI (Tweaks, WineASIO)
  719. if haveWine:
  720. ins = int(getWineAsioKeyValue("Number of inputs", "00000010"), 16)
  721. outs = int(getWineAsioKeyValue("Number of outputs", "00000010"), 16)
  722. hw = bool(int(getWineAsioKeyValue("Connect to hardware", "00000001"), 10))
  723. autostart = bool(int(getWineAsioKeyValue("Autostart server", "00000000"), 10))
  724. fixed_bsize = bool(int(getWineAsioKeyValue("Fixed buffersize", "00000001"), 10))
  725. prefer_bsize = int(getWineAsioKeyValue("Preferred buffersize", "00000400"), 16)
  726. for bsize in buffer_sizes:
  727. self.cb_wineasio_bsizes.addItem(str(bsize))
  728. if bsize == prefer_bsize:
  729. self.cb_wineasio_bsizes.setCurrentIndex(self.cb_wineasio_bsizes.count()-1)
  730. self.sb_wineasio_ins.setValue(ins)
  731. self.sb_wineasio_outs.setValue(outs)
  732. self.cb_wineasio_hw.setChecked(hw)
  733. self.cb_wineasio_autostart.setChecked(autostart)
  734. self.cb_wineasio_fixed_bsize.setChecked(fixed_bsize)
  735. else:
  736. # No Wine
  737. self.tw_tweaks.hideRow(2)
  738. # -------------------------------------------------------------
  739. # Set-up systray
  740. self.systray = systray.GlobalSysTray(self, "Cadence", "cadence")
  741. if haveDBus:
  742. self.systray.addAction("jack_start", self.tr("Start JACK"))
  743. self.systray.addAction("jack_stop", self.tr("Stop JACK"))
  744. self.systray.addAction("jack_configure", self.tr("Configure JACK"))
  745. self.systray.addSeparator("sep1")
  746. self.systray.addMenu("alsa", self.tr("ALSA Audio Bridge"))
  747. self.systray.addMenuAction("alsa", "alsa_start", self.tr("Start"))
  748. self.systray.addMenuAction("alsa", "alsa_stop", self.tr("Stop"))
  749. self.systray.addMenu("a2j", self.tr("ALSA MIDI Bridge"))
  750. self.systray.addMenuAction("a2j", "a2j_start", self.tr("Start"))
  751. self.systray.addMenuAction("a2j", "a2j_stop", self.tr("Stop"))
  752. self.systray.addMenuAction("a2j", "a2j_export_hw", self.tr("Export Hardware Ports..."))
  753. self.systray.addMenu("pulse", self.tr("PulseAudio Bridge"))
  754. self.systray.addMenuAction("pulse", "pulse_start", self.tr("Start"))
  755. self.systray.addMenuAction("pulse", "pulse_stop", self.tr("Stop"))
  756. self.systray.setActionIcon("jack_start", "media-playback-start")
  757. self.systray.setActionIcon("jack_stop", "media-playback-stop")
  758. self.systray.setActionIcon("jack_configure", "configure")
  759. self.systray.setActionIcon("alsa_start", "media-playback-start")
  760. self.systray.setActionIcon("alsa_stop", "media-playback-stop")
  761. self.systray.setActionIcon("a2j_start", "media-playback-start")
  762. self.systray.setActionIcon("a2j_stop", "media-playback-stop")
  763. self.systray.setActionIcon("pulse_start", "media-playback-start")
  764. self.systray.setActionIcon("pulse_stop", "media-playback-stop")
  765. self.systray.connect("jack_start", self.slot_JackServerStart)
  766. self.systray.connect("jack_stop", self.slot_JackServerStop)
  767. self.systray.connect("jack_configure", self.slot_JackServerConfigure)
  768. self.systray.connect("alsa_start", self.slot_AlsaBridgeStart)
  769. self.systray.connect("alsa_stop", self.slot_AlsaBridgeStop)
  770. self.systray.connect("a2j_start", self.slot_A2JBridgeStart)
  771. self.systray.connect("a2j_stop", self.slot_A2JBridgeStop)
  772. self.systray.connect("a2j_export_hw", self.slot_A2JBridgeExportHW)
  773. self.systray.connect("pulse_start", self.slot_PulseAudioBridgeStart)
  774. self.systray.connect("pulse_stop", self.slot_PulseAudioBridgeStop)
  775. self.systray.addMenu("tools", self.tr("Tools"))
  776. self.systray.addMenuAction("tools", "app_catarina", "Catarina")
  777. self.systray.addMenuAction("tools", "app_catia", "Catia")
  778. self.systray.addMenuAction("tools", "app_claudia", "Claudia")
  779. self.systray.addMenuAction("tools", "app_carla", "Carla")
  780. self.systray.addMenuSeparator("tools", "tools_sep")
  781. self.systray.addMenuAction("tools", "app_logs", "Logs")
  782. self.systray.addMenuAction("tools", "app_meter", "Meter")
  783. self.systray.addMenuAction("tools", "app_render", "Render")
  784. self.systray.addMenuAction("tools", "app_xy-controller", "XY-Controller")
  785. self.systray.addSeparator("sep2")
  786. self.systray.connect("app_catarina", lambda tool="catarina": self.func_start_tool(tool))
  787. self.systray.connect("app_catia", lambda tool="catia": self.func_start_tool(tool))
  788. self.systray.connect("app_claudia", lambda tool="claudia": self.func_start_tool(tool))
  789. self.systray.connect("app_carla", lambda tool="carla": self.func_start_tool(tool))
  790. self.systray.connect("app_logs", lambda tool="cadence-logs": self.func_start_tool(tool))
  791. self.systray.connect("app_meter", lambda tool="cadence-jackmeter": self.func_start_tool(tool))
  792. self.systray.connect("app_render", lambda tool="cadence-render": self.func_start_tool(tool))
  793. self.systray.connect("app_xy-controller", lambda tool="cadence-xycontroller": self.func_start_tool(tool))
  794. self.systray.setToolTip("Cadence")
  795. self.systray.show()
  796. # -------------------------------------------------------------
  797. # Set-up connections
  798. self.connect(self.b_jack_start, SIGNAL("clicked()"), SLOT("slot_JackServerStart()"))
  799. self.connect(self.b_jack_stop, SIGNAL("clicked()"), SLOT("slot_JackServerStop()"))
  800. self.connect(self.b_jack_restart, SIGNAL("clicked()"), SLOT("slot_JackServerForceRestart()"))
  801. self.connect(self.b_jack_configure, SIGNAL("clicked()"), SLOT("slot_JackServerConfigure()"))
  802. self.connect(self.tb_jack_options, SIGNAL("clicked()"), SLOT("slot_JackOptions()"))
  803. self.connect(self.b_alsa_start, SIGNAL("clicked()"), SLOT("slot_AlsaBridgeStart()"))
  804. self.connect(self.b_alsa_stop, SIGNAL("clicked()"), SLOT("slot_AlsaBridgeStop()"))
  805. self.connect(self.cb_alsa_type, SIGNAL("currentIndexChanged(int)"), SLOT("slot_AlsaBridgeChanged(int)"))
  806. self.connect(self.tb_alsa_options, SIGNAL("clicked()"), SLOT("slot_AlsaAudioBridgeOptions()"))
  807. self.connect(self.b_a2j_start, SIGNAL("clicked()"), SLOT("slot_A2JBridgeStart()"))
  808. self.connect(self.b_a2j_stop, SIGNAL("clicked()"), SLOT("slot_A2JBridgeStop()"))
  809. self.connect(self.b_a2j_export_hw, SIGNAL("clicked()"), SLOT("slot_A2JBridgeExportHW()"))
  810. self.connect(self.tb_a2j_options, SIGNAL("clicked()"), SLOT("slot_A2JBridgeOptions()"))
  811. self.connect(self.b_pulse_start, SIGNAL("clicked()"), SLOT("slot_PulseAudioBridgeStart()"))
  812. self.connect(self.b_pulse_stop, SIGNAL("clicked()"), SLOT("slot_PulseAudioBridgeStop()"))
  813. self.connect(self.tb_pulse_options, SIGNAL("clicked()"), SLOT("slot_PulseAudioBridgeOptions()"))
  814. self.connect(self.pic_catia, SIGNAL("clicked()"), lambda tool="catia": self.func_start_tool(tool))
  815. self.connect(self.pic_claudia, SIGNAL("clicked()"), lambda tool="claudia": self.func_start_tool(tool))
  816. self.connect(self.pic_carla, SIGNAL("clicked()"), lambda tool="carla": self.func_start_tool(tool))
  817. self.connect(self.pic_logs, SIGNAL("clicked()"), lambda tool="cadence-logs": self.func_start_tool(tool))
  818. self.connect(self.pic_render, SIGNAL("clicked()"), lambda tool="cadence-render": self.func_start_tool(tool))
  819. self.connect(self.pic_xycontroller, SIGNAL("clicked()"), lambda tool="cadence-xycontroller": self.func_start_tool(tool))
  820. self.connect(self.b_tweaks_apply_now, SIGNAL("clicked()"), SLOT("slot_tweaksApply()"))
  821. self.connect(self.b_tweak_plugins_add, SIGNAL("clicked()"), SLOT("slot_tweakPluginAdd()"))
  822. self.connect(self.b_tweak_plugins_change, SIGNAL("clicked()"), SLOT("slot_tweakPluginChange()"))
  823. self.connect(self.b_tweak_plugins_remove, SIGNAL("clicked()"), SLOT("slot_tweakPluginRemove()"))
  824. self.connect(self.b_tweak_plugins_reset, SIGNAL("clicked()"), SLOT("slot_tweakPluginReset()"))
  825. self.connect(self.tb_tweak_plugins, SIGNAL("currentChanged(int)"), SLOT("slot_tweakPluginTypeChanged(int)"))
  826. self.connect(self.list_LADSPA, SIGNAL("currentRowChanged(int)"), SLOT("slot_tweakPluginsLadspaRowChanged(int)"))
  827. self.connect(self.list_DSSI, SIGNAL("currentRowChanged(int)"), SLOT("slot_tweakPluginsDssiRowChanged(int)"))
  828. self.connect(self.list_LV2, SIGNAL("currentRowChanged(int)"), SLOT("slot_tweakPluginsLv2RowChanged(int)"))
  829. self.connect(self.list_VST, SIGNAL("currentRowChanged(int)"), SLOT("slot_tweakPluginsVstRowChanged(int)"))
  830. self.connect(self.ch_app_image, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_apps()"))
  831. self.connect(self.cb_app_image, SIGNAL("highlighted(int)"), SLOT("slot_tweakAppImageHighlighted(int)"))
  832. self.connect(self.cb_app_image, SIGNAL("currentIndexChanged(int)"), SLOT("slot_tweakAppImageChanged(int)"))
  833. self.connect(self.ch_app_music, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_apps()"))
  834. self.connect(self.cb_app_music, SIGNAL("highlighted(int)"), SLOT("slot_tweakAppMusicHighlighted(int)"))
  835. self.connect(self.cb_app_music, SIGNAL("currentIndexChanged(int)"), SLOT("slot_tweakAppMusicChanged(int)"))
  836. self.connect(self.ch_app_video, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_apps()"))
  837. self.connect(self.cb_app_video, SIGNAL("highlighted(int)"), SLOT("slot_tweakAppVideoHighlighted(int)"))
  838. self.connect(self.cb_app_video, SIGNAL("currentIndexChanged(int)"), SLOT("slot_tweakAppVideoChanged(int)"))
  839. self.connect(self.ch_app_text, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_apps()"))
  840. self.connect(self.cb_app_text, SIGNAL("highlighted(int)"), SLOT("slot_tweakAppTextHighlighted(int)"))
  841. self.connect(self.cb_app_text, SIGNAL("currentIndexChanged(int)"), SLOT("slot_tweakAppTextChanged(int)"))
  842. self.connect(self.ch_app_browser, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_apps()"))
  843. self.connect(self.cb_app_browser, SIGNAL("highlighted(int)"), SLOT("slot_tweakAppBrowserHighlighted(int)"))
  844. self.connect(self.cb_app_browser, SIGNAL("currentIndexChanged(int)"),SLOT("slot_tweakAppBrowserChanged(int)"))
  845. self.connect(self.sb_wineasio_ins, SIGNAL("valueChanged(int)"), SLOT("slot_tweaksSettingsChanged_wineasio()"))
  846. self.connect(self.sb_wineasio_outs, SIGNAL("valueChanged(int)"), SLOT("slot_tweaksSettingsChanged_wineasio()"))
  847. self.connect(self.cb_wineasio_hw, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_wineasio()"))
  848. self.connect(self.cb_wineasio_autostart, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_wineasio()"))
  849. self.connect(self.cb_wineasio_fixed_bsize, SIGNAL("clicked()"), SLOT("slot_tweaksSettingsChanged_wineasio()"))
  850. self.connect(self.cb_wineasio_bsizes, SIGNAL("currentIndexChanged(int)"), SLOT("slot_tweaksSettingsChanged_wineasio()"))
  851. # org.jackaudio.JackControl
  852. self.connect(self, SIGNAL("DBusJackServerStartedCallback()"), SLOT("slot_DBusJackServerStartedCallback()"))
  853. self.connect(self, SIGNAL("DBusJackServerStoppedCallback()"), SLOT("slot_DBusJackServerStoppedCallback()"))
  854. # org.jackaudio.JackPatchbay
  855. self.connect(self, SIGNAL("DBusJackClientAppearedCallback(int, QString)"), SLOT("slot_DBusJackClientAppearedCallback(int, QString)"))
  856. self.connect(self, SIGNAL("DBusJackClientDisappearedCallback(int)"), SLOT("slot_DBusJackClientDisappearedCallback(int)"))
  857. # org.gna.home.a2jmidid.control
  858. self.connect(self, SIGNAL("DBusA2JBridgeStartedCallback()"), SLOT("slot_DBusA2JBridgeStartedCallback()"))
  859. self.connect(self, SIGNAL("DBusA2JBridgeStoppedCallback()"), SLOT("slot_DBusA2JBridgeStoppedCallback()"))
  860. # -------------------------------------------------------------
  861. self.m_last_dsp_load = None
  862. self.m_last_xruns = None
  863. self.m_last_buffer_size = None
  864. self.m_timer500 = None
  865. self.m_timer2000 = self.startTimer(2000)
  866. self.DBusReconnect()
  867. if haveDBus:
  868. DBus.bus.add_signal_receiver(self.DBusSignalReceiver, destination_keyword='dest', path_keyword='path',
  869. member_keyword='member', interface_keyword='interface', sender_keyword='sender', )
  870. def DBusReconnect(self):
  871. if haveDBus:
  872. try:
  873. DBus.jack = DBus.bus.get_object("org.jackaudio.service", "/org/jackaudio/Controller")
  874. DBus.patchbay = dbus.Interface(DBus.jack, "org.jackaudio.JackPatchbay")
  875. jacksettings.initBus(DBus.bus)
  876. except:
  877. DBus.jack = None
  878. DBus.patchbay = None
  879. try:
  880. DBus.a2j = dbus.Interface(DBus.bus.get_object("org.gna.home.a2jmidid", "/"), "org.gna.home.a2jmidid.control")
  881. except:
  882. DBus.a2j = None
  883. if DBus.jack:
  884. if DBus.jack.IsStarted():
  885. # Check for pulseaudio in jack graph
  886. version, groups, conns = DBus.patchbay.GetGraph(0)
  887. for group_id, group_name, ports in groups:
  888. if group_name == "alsa2jack":
  889. global jackClientIdALSA
  890. jackClientIdALSA = group_id
  891. elif group_name == "PulseAudio JACK Sink":
  892. global jackClientIdPulse
  893. jackClientIdPulse = group_id
  894. self.jackStarted()
  895. else:
  896. self.jackStopped()
  897. self.label_jack_realtime.setText("Yes" if jacksettings.isRealtime() else "No")
  898. else:
  899. self.jackStopped()
  900. self.label_jack_status.setText("Unavailable")
  901. self.label_jack_status_ico.setPixmap(self.pix_error)
  902. self.label_jack_realtime.setText("Unknown")
  903. self.label_jack_realtime_ico.setPixmap(self.pix_error)
  904. self.groupBox_jack.setEnabled(False)
  905. self.groupBox_jack.setTitle("-- jackdbus is not available --")
  906. self.b_jack_start.setEnabled(False)
  907. self.b_jack_stop.setEnabled(False)
  908. self.b_jack_restart.setEnabled(False)
  909. self.b_jack_configure.setEnabled(False)
  910. self.groupBox_bridges.setEnabled(False)
  911. if DBus.a2j:
  912. if DBus.a2j.is_started():
  913. self.a2jStarted()
  914. else:
  915. self.a2jStopped()
  916. else:
  917. self.toolBox_alsamidi.setEnabled(False)
  918. self.cb_a2j_autostart.setChecked(False)
  919. self.label_bridge_a2j.setText("ALSA MIDI Bridge is not installed")
  920. self.settings.setValue("A2J/AutoStart", False)
  921. self.updateSystrayTooltip()
  922. def DBusSignalReceiver(self, *args, **kwds):
  923. if kwds['interface'] == "org.freedesktop.DBus" and kwds['path'] == "/org/freedesktop/DBus" and kwds['member'] == "NameOwnerChanged":
  924. appInterface, appId, newId = args
  925. if not newId:
  926. # Something crashed
  927. if appInterface == "org.jackaudio.service":
  928. QTimer.singleShot(0, self, SLOT("slot_handleCrash_jack()"))
  929. elif appInterface == "org.gna.home.a2jmidid":
  930. QTimer.singleShot(0, self, SLOT("slot_handleCrash_a2j()"))
  931. elif kwds['interface'] == "org.jackaudio.JackControl":
  932. if DEBUG: print("org.jackaudio.JackControl", kwds['member'])
  933. if kwds['member'] == "ServerStarted":
  934. self.emit(SIGNAL("DBusJackServerStartedCallback()"))
  935. elif kwds['member'] == "ServerStopped":
  936. self.emit(SIGNAL("DBusJackServerStoppedCallback()"))
  937. elif kwds['interface'] == "org.jackaudio.JackPatchbay":
  938. if DBus.patchbay and kwds['path'] == DBus.patchbay.object_path:
  939. if DEBUG: print("org.jackaudio.JackPatchbay,", kwds['member'])
  940. if kwds['member'] == "ClientAppeared":
  941. self.emit(SIGNAL("DBusJackClientAppearedCallback(int, QString)"), args[iJackClientId], args[iJackClientName])
  942. elif kwds['member'] == "ClientDisappeared":
  943. self.emit(SIGNAL("DBusJackClientDisappearedCallback(int)"), args[iJackClientId])
  944. elif kwds['interface'] == "org.gna.home.a2jmidid.control":
  945. if DEBUG: print("org.gna.home.a2jmidid.control", kwds['member'])
  946. if kwds['member'] == "bridge_started":
  947. self.emit(SIGNAL("DBusA2JBridgeStartedCallback()"))
  948. elif kwds['member'] == "bridge_stopped":
  949. self.emit(SIGNAL("DBusA2JBridgeStoppedCallback()"))
  950. def jackStarted(self):
  951. self.m_last_dsp_load = DBus.jack.GetLoad()
  952. self.m_last_xruns = DBus.jack.GetXruns()
  953. self.m_last_buffer_size = DBus.jack.GetBufferSize()
  954. self.b_jack_start.setEnabled(False)
  955. self.b_jack_stop.setEnabled(True)
  956. self.systray.setActionEnabled("jack_start", False)
  957. self.systray.setActionEnabled("jack_stop", True)
  958. self.label_jack_status.setText("Started")
  959. self.label_jack_status_ico.setPixmap(self.pix_apply)
  960. if DBus.jack.IsRealtime():
  961. self.label_jack_realtime.setText("Yes")
  962. self.label_jack_realtime_ico.setPixmap(self.pix_apply)
  963. else:
  964. self.label_jack_realtime.setText("No")
  965. self.label_jack_realtime_ico.setPixmap(self.pix_cancel)
  966. self.label_jack_dsp.setText("%.2f%%" % self.m_last_dsp_load)
  967. self.label_jack_xruns.setText(str(self.m_last_xruns))
  968. self.label_jack_bfsize.setText("%i samples" % self.m_last_buffer_size)
  969. self.label_jack_srate.setText("%i Hz" % DBus.jack.GetSampleRate())
  970. self.label_jack_latency.setText("%.1f ms" % DBus.jack.GetLatency())
  971. self.m_timer500 = self.startTimer(500)
  972. if DBus.a2j and not DBus.a2j.is_started():
  973. self.b_a2j_start.setEnabled(True)
  974. self.systray.setActionEnabled("a2j_start", True)
  975. self.checkAlsaAudio()
  976. self.checkPulseAudio()
  977. def jackStopped(self):
  978. if self.m_timer500:
  979. self.killTimer(self.m_timer500)
  980. self.m_timer500 = None
  981. self.m_last_dsp_load = None
  982. self.m_last_xruns = None
  983. self.m_last_buffer_size = None
  984. self.b_jack_start.setEnabled(True)
  985. self.b_jack_stop.setEnabled(False)
  986. if haveDBus:
  987. self.systray.setActionEnabled("jack_start", True)
  988. self.systray.setActionEnabled("jack_stop", False)
  989. self.label_jack_status.setText("Stopped")
  990. self.label_jack_status_ico.setPixmap(self.pix_cancel)
  991. self.label_jack_dsp.setText("---")
  992. self.label_jack_xruns.setText("---")
  993. self.label_jack_bfsize.setText("---")
  994. self.label_jack_srate.setText("---")
  995. self.label_jack_latency.setText("---")
  996. if DBus.a2j:
  997. self.b_a2j_start.setEnabled(False)
  998. self.systray.setActionEnabled("a2j_start", False)
  999. global jackClientIdALSA, jackClientIdPulse
  1000. jackClientIdALSA = -1
  1001. jackClientIdPulse = -1
  1002. if haveDBus:
  1003. self.checkAlsaAudio()
  1004. self.checkPulseAudio()
  1005. def a2jStarted(self):
  1006. self.b_a2j_start.setEnabled(False)
  1007. self.b_a2j_stop.setEnabled(True)
  1008. self.b_a2j_export_hw.setEnabled(False)
  1009. self.systray.setActionEnabled("a2j_start", False)
  1010. self.systray.setActionEnabled("a2j_stop", True)
  1011. self.systray.setActionEnabled("a2j_export_hw", False)
  1012. self.label_bridge_a2j.setText(self.tr("ALSA MIDI Bridge is running"))
  1013. def a2jStopped(self):
  1014. jackRunning = bool(DBus.jack and DBus.jack.IsStarted())
  1015. self.b_a2j_start.setEnabled(jackRunning)
  1016. self.b_a2j_stop.setEnabled(False)
  1017. self.b_a2j_export_hw.setEnabled(True)
  1018. self.systray.setActionEnabled("a2j_start", jackRunning)
  1019. self.systray.setActionEnabled("a2j_stop", False)
  1020. self.systray.setActionEnabled("a2j_export_hw", True)
  1021. self.label_bridge_a2j.setText(self.tr("ALSA MIDI Bridge is stopped"))
  1022. def checkAlsaAudio(self):
  1023. asoundrcFile = os.path.join(HOME, ".asoundrc")
  1024. if not os.path.exists(asoundrcFile):
  1025. self.b_alsa_start.setEnabled(False)
  1026. self.b_alsa_stop.setEnabled(False)
  1027. self.cb_alsa_type.setCurrentIndex(iAlsaFileNone)
  1028. self.tb_alsa_options.setEnabled(False)
  1029. self.label_bridge_alsa.setText(self.tr("No bridge in use"))
  1030. self.m_lastAlsaIndexType = -1 # null
  1031. return
  1032. asoundrcFd = open(asoundrcFile, "r")
  1033. asoundrcRead = asoundrcFd.read().strip()
  1034. asoundrcFd.close()
  1035. if asoundrcRead == asoundrc_aloop:
  1036. if isAlsaAudioBridged():
  1037. self.b_alsa_start.setEnabled(False)
  1038. self.b_alsa_stop.setEnabled(True)
  1039. self.systray.setActionEnabled("alsa_start", False)
  1040. self.systray.setActionEnabled("alsa_stop", True)
  1041. self.label_bridge_alsa.setText(self.tr("Using Cadence snd-aloop daemon, started"))
  1042. else:
  1043. jackRunning = bool(DBus.jack and DBus.jack.IsStarted())
  1044. self.b_alsa_start.setEnabled(jackRunning)
  1045. self.b_alsa_stop.setEnabled(False)
  1046. self.systray.setActionEnabled("alsa_start", jackRunning)
  1047. self.systray.setActionEnabled("alsa_stop", False)
  1048. self.label_bridge_alsa.setText(self.tr("Using Cadence snd-aloop daemon, stopped"))
  1049. self.cb_alsa_type.setCurrentIndex(iAlsaFileLoop)
  1050. self.tb_alsa_options.setEnabled(False)
  1051. elif asoundrcRead == asoundrc_jack:
  1052. self.b_alsa_start.setEnabled(False)
  1053. self.b_alsa_stop.setEnabled(False)
  1054. self.systray.setActionEnabled("alsa_start", False)
  1055. self.systray.setActionEnabled("alsa_stop", False)
  1056. self.cb_alsa_type.setCurrentIndex(iAlsaFileJACK)
  1057. self.tb_alsa_options.setEnabled(False)
  1058. self.label_bridge_alsa.setText(self.tr("Using JACK plugin bridge"))
  1059. elif asoundrcRead == asoundrc_pulse:
  1060. self.b_alsa_start.setEnabled(False)
  1061. self.b_alsa_stop.setEnabled(False)
  1062. self.systray.setActionEnabled("alsa_start", False)
  1063. self.systray.setActionEnabled("alsa_stop", False)
  1064. self.cb_alsa_type.setCurrentIndex(iAlsaFilePulse)
  1065. self.tb_alsa_options.setEnabled(False)
  1066. self.label_bridge_alsa.setText(self.tr("Using PulseAudio plugin bridge"))
  1067. else:
  1068. self.b_alsa_start.setEnabled(False)
  1069. self.b_alsa_stop.setEnabled(False)
  1070. self.systray.setActionEnabled("alsa_start", False)
  1071. self.systray.setActionEnabled("alsa_stop", False)
  1072. self.cb_alsa_type.addItem(self.tr("Custom"))
  1073. self.cb_alsa_type.setCurrentIndex(iAlsaFileMax)
  1074. self.tb_alsa_options.setEnabled(True)
  1075. self.label_bridge_alsa.setText(self.tr("Using custom asoundrc, not managed by Cadence"))
  1076. self.m_lastAlsaIndexType = self.cb_alsa_type.currentIndex()
  1077. def checkPulseAudio(self):
  1078. if isPulseAudioStarted():
  1079. if isPulseAudioBridged():
  1080. self.b_pulse_start.setEnabled(False)
  1081. self.b_pulse_stop.setEnabled(True)
  1082. self.systray.setActionEnabled("pulse_start", False)
  1083. self.systray.setActionEnabled("pulse_stop", True)
  1084. self.label_bridge_pulse.setText(self.tr("PulseAudio is started and bridged to JACK"))
  1085. else:
  1086. jackRunning = bool(DBus.jack and DBus.jack.IsStarted())
  1087. self.b_pulse_start.setEnabled(DBus.jack and DBus.jack.IsStarted())
  1088. self.b_pulse_stop.setEnabled(False)
  1089. self.systray.setActionEnabled("pulse_start", jackRunning)
  1090. self.systray.setActionEnabled("pulse_stop", False)
  1091. self.label_bridge_pulse.setText(self.tr("PulseAudio is started but not bridged"))
  1092. else:
  1093. jackRunning = bool(DBus.jack and DBus.jack.IsStarted())
  1094. self.b_pulse_start.setEnabled(jackRunning)
  1095. self.b_pulse_stop.setEnabled(False)
  1096. self.systray.setActionEnabled("pulse_start", jackRunning)
  1097. self.systray.setActionEnabled("pulse_stop", False)
  1098. self.label_bridge_pulse.setText(self.tr("PulseAudio is not started"))
  1099. def setAppDetails(self, desktop):
  1100. appContents = getDesktopFileContents(desktop)
  1101. name = getXdgProperty(appContents, "Name")
  1102. icon = getXdgProperty(appContents, "Icon")
  1103. comment = getXdgProperty(appContents, "Comment")
  1104. if not name:
  1105. name = self.cb_app_image.currentText().replace(".desktop","").title()
  1106. if not icon:
  1107. icon = ""
  1108. if not comment:
  1109. comment = ""
  1110. self.ico_app.setPixmap(getIcon(icon, 48).pixmap(48, 48))
  1111. self.label_app_name.setText(name)
  1112. self.label_app_comment.setText(comment)
  1113. def updateSystrayTooltip(self):
  1114. systrayText = "<table>"
  1115. #systrayText += "<tr><td align='center' colspan='2'><h4>Cadence</h4></td></tr>"
  1116. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("JACK Status"), self.label_jack_status.text())
  1117. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("Realtime"), self.label_jack_realtime.text())
  1118. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("DSP Load"), self.label_jack_dsp.text())
  1119. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("Xruns"), self.label_jack_xruns.text())
  1120. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("Buffer Size"), self.label_jack_bfsize.text())
  1121. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("Sample Rate"), self.label_jack_srate.text())
  1122. systrayText += "<tr><td align='right'>%s:</td><td>%s</td></tr>" % (self.tr("Latency"), self.label_jack_latency.text())
  1123. systrayText += "</table>"
  1124. self.systray.setToolTip(systrayText)
  1125. def func_start_tool(self, tool):
  1126. # TODO - multiplatform
  1127. os.system("%s &" % tool)
  1128. def func_settings_changed(self, stype):
  1129. if stype not in self.settings_changed_types:
  1130. self.settings_changed_types.append(stype)
  1131. self.frame_tweaks_settings.setVisible(True)
  1132. @pyqtSlot()
  1133. def slot_DBusJackServerStartedCallback(self):
  1134. self.jackStarted()
  1135. @pyqtSlot()
  1136. def slot_DBusJackServerStoppedCallback(self):
  1137. self.jackStopped()
  1138. @pyqtSlot(int, str)
  1139. def slot_DBusJackClientAppearedCallback(self, group_id, group_name):
  1140. if group_name == "alsa2jack":
  1141. global jackClientIdALSA
  1142. jackClientIdALSA = group_id
  1143. self.checkAlsaAudio()
  1144. elif group_name == "PulseAudio JACK Sink":
  1145. global jackClientIdPulse
  1146. jackClientIdPulse = group_id
  1147. self.checkPulseAudio()
  1148. @pyqtSlot(int)
  1149. def slot_DBusJackClientDisappearedCallback(self, group_id):
  1150. global jackClientIdALSA, jackClientIdPulse
  1151. if group_id == jackClientIdALSA:
  1152. jackClientIdALSA = -1
  1153. self.checkAlsaAudio()
  1154. elif group_id == jackClientIdPulse:
  1155. jackClientIdPulse = -1
  1156. self.checkPulseAudio()
  1157. @pyqtSlot()
  1158. def slot_DBusA2JBridgeStartedCallback(self):
  1159. self.a2jStarted()
  1160. @pyqtSlot()
  1161. def slot_DBusA2JBridgeStoppedCallback(self):
  1162. self.a2jStopped()
  1163. @pyqtSlot()
  1164. def slot_JackServerStart(self):
  1165. self.saveSettings()
  1166. try:
  1167. DBus.jack.StartServer()
  1168. except:
  1169. QMessageBox.warning(self, self.tr("Warning"), self.tr("Failed to start JACK, please check the logs for more information."))
  1170. @pyqtSlot()
  1171. def slot_JackServerStop(self):
  1172. try:
  1173. DBus.jack.StopServer()
  1174. except:
  1175. QMessageBox.warning(self, self.tr("Warning"), self.tr("Failed to stop JACK, please check the logs for more information."))
  1176. @pyqtSlot()
  1177. def slot_JackServerForceRestart(self):
  1178. if DBus.jack.IsStarted():
  1179. ask = CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  1180. self.tr("This will force kill all JACK applications!<br>Make sure to save your projects before continue."),
  1181. self.tr("Are you sure you want to force the restart of JACK?"))
  1182. if ask != QMessageBox.Yes:
  1183. return
  1184. if self.m_timer500:
  1185. self.killTimer(self.m_timer500)
  1186. self.m_timer500 = None
  1187. self.saveSettings()
  1188. ForceWaitDialog(self).exec_()
  1189. @pyqtSlot()
  1190. def slot_JackServerConfigure(self):
  1191. jacksettingsW = jacksettings.JackSettingsW(self)
  1192. jacksettingsW.exec_()
  1193. del jacksettingsW
  1194. @pyqtSlot()
  1195. def slot_JackOptions(self):
  1196. ToolBarJackDialog(self).exec_()
  1197. @pyqtSlot()
  1198. def slot_JackClearXruns(self):
  1199. if DBus.jack:
  1200. DBus.jack.ResetXruns()
  1201. @pyqtSlot()
  1202. def slot_AlsaBridgeStart(self):
  1203. self.slot_AlsaBridgeStop()
  1204. self.func_start_tool("cadence-aloop-daemon")
  1205. @pyqtSlot()
  1206. def slot_AlsaBridgeStop(self):
  1207. checkFile = "/tmp/.cadence-aloop-daemon.x"
  1208. if os.path.exists(checkFile):
  1209. os.remove(checkFile)
  1210. @pyqtSlot(int)
  1211. def slot_AlsaBridgeChanged(self, index):
  1212. if self.m_lastAlsaIndexType == -2 or self.m_lastAlsaIndexType == index:
  1213. return
  1214. if self.m_lastAlsaIndexType == iAlsaFileMax:
  1215. ask = CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  1216. self.tr(""
  1217. "You're using a custom ~/.asoundrc file not managed by Cadence.<br/>"
  1218. "By choosing to use a Cadence ALSA-Audio bridge, <b>the file will be replaced</b>."
  1219. ""),
  1220. self.tr("Are you sure you want to do this?"))
  1221. if ask == QMessageBox.Yes:
  1222. self.cb_alsa_type.blockSignals(True)
  1223. self.cb_alsa_type.removeItem(iAlsaFileMax)
  1224. self.cb_alsa_type.setCurrentIndex(index)
  1225. self.cb_alsa_type.blockSignals(False)
  1226. else:
  1227. self.cb_alsa_type.blockSignals(True)
  1228. self.cb_alsa_type.setCurrentIndex(iAlsaFileMax)
  1229. self.cb_alsa_type.blockSignals(False)
  1230. return
  1231. asoundrcFile = os.path.join(HOME, ".asoundrc")
  1232. if index == iAlsaFileNone:
  1233. os.remove(asoundrcFile)
  1234. elif index == iAlsaFileLoop:
  1235. asoundrcFd = open(asoundrcFile, "w")
  1236. asoundrcFd.write(asoundrc_aloop+"\n")
  1237. asoundrcFd.close()
  1238. elif index == iAlsaFileJACK:
  1239. asoundrcFd = open(asoundrcFile, "w")
  1240. asoundrcFd.write(asoundrc_jack+"\n")
  1241. asoundrcFd.close()
  1242. elif index == iAlsaFilePulse:
  1243. asoundrcFd = open(asoundrcFile, "w")
  1244. asoundrcFd.write(asoundrc_pulse+"\n")
  1245. asoundrcFd.close()
  1246. else:
  1247. print("Cadence::AlsaBridgeChanged(%i) - invalid index" % index)
  1248. self.checkAlsaAudio()
  1249. @pyqtSlot()
  1250. def slot_AlsaAudioBridgeOptions(self):
  1251. ToolBarAlsaAudioDialog(self).exec_()
  1252. @pyqtSlot()
  1253. def slot_A2JBridgeStart(self):
  1254. DBus.a2j.start()
  1255. @pyqtSlot()
  1256. def slot_A2JBridgeStop(self):
  1257. DBus.a2j.stop()
  1258. @pyqtSlot()
  1259. def slot_A2JBridgeExportHW(self):
  1260. ask = QMessageBox.question(self, self.tr("ALSA MIDI Hardware Export"), self.tr("Enable Hardware Export on the ALSA MIDI Bridge?"), QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel, QMessageBox.Yes)
  1261. if ask == QMessageBox.Yes:
  1262. DBus.a2j.set_hw_export(True)
  1263. elif ask == QMessageBox.No:
  1264. DBus.a2j.set_hw_export(False)
  1265. @pyqtSlot()
  1266. def slot_A2JBridgeOptions(self):
  1267. ToolBarA2JDialog(self).exec_()
  1268. @pyqtSlot()
  1269. def slot_PulseAudioBridgeStart(self):
  1270. if GlobalSettings.value("Pulse2JACK/PlaybackModeOnly", False, type=bool):
  1271. os.system("cadence-pulse2jack -p")
  1272. else:
  1273. os.system("cadence-pulse2jack")
  1274. @pyqtSlot()
  1275. def slot_PulseAudioBridgeStop(self):
  1276. os.system("pulseaudio -k")
  1277. @pyqtSlot()
  1278. def slot_PulseAudioBridgeOptions(self):
  1279. ToolBarPADialog(self).exec_()
  1280. @pyqtSlot()
  1281. def slot_handleCrash_jack(self):
  1282. self.DBusReconnect()
  1283. @pyqtSlot()
  1284. def slot_handleCrash_a2j(self):
  1285. pass
  1286. @pyqtSlot()
  1287. def slot_tweaksApply(self):
  1288. if "plugins" in self.settings_changed_types:
  1289. EXTRA_LADSPA_DIRS = []
  1290. EXTRA_DSSI_DIRS = []
  1291. EXTRA_LV2_DIRS = []
  1292. EXTRA_VST_DIRS = []
  1293. for i in range(self.list_LADSPA.count()):
  1294. iPath = self.list_LADSPA.item(i).text()
  1295. if iPath not in DEFAULT_LADSPA_PATH and iPath not in EXTRA_LADSPA_DIRS:
  1296. EXTRA_LADSPA_DIRS.append(iPath)
  1297. for i in range(self.list_DSSI.count()):
  1298. iPath = self.list_DSSI.item(i).text()
  1299. if iPath not in DEFAULT_DSSI_PATH and iPath not in EXTRA_DSSI_DIRS:
  1300. EXTRA_DSSI_DIRS.append(iPath)
  1301. for i in range(self.list_LV2.count()):
  1302. iPath = self.list_LV2.item(i).text()
  1303. if iPath not in DEFAULT_LV2_PATH and iPath not in EXTRA_LV2_DIRS:
  1304. EXTRA_LV2_DIRS.append(iPath)
  1305. for i in range(self.list_VST.count()):
  1306. iPath = self.list_VST.item(i).text()
  1307. if iPath not in DEFAULT_VST_PATH and iPath not in EXTRA_VST_DIRS:
  1308. EXTRA_VST_DIRS.append(iPath)
  1309. GlobalSettings.setValue("AudioPlugins/EXTRA_LADSPA_PATH", ":".join(EXTRA_LADSPA_DIRS))
  1310. GlobalSettings.setValue("AudioPlugins/EXTRA_DSSI_PATH", ":".join(EXTRA_DSSI_DIRS))
  1311. GlobalSettings.setValue("AudioPlugins/EXTRA_LV2_PATH", ":".join(EXTRA_LV2_DIRS))
  1312. GlobalSettings.setValue("AudioPlugins/EXTRA_VST_PATH", ":".join(EXTRA_VST_DIRS))
  1313. if "apps" in self.settings_changed_types:
  1314. mimeFileContent = ""
  1315. # Fix common mime errors
  1316. mimeFileContent += "application/x-designer=designer-qt4.desktop;\n"
  1317. mimeFileContent += "application/x-ms-dos-executable=wine.desktop;\n"
  1318. mimeFileContent += "audio/x-minipsf=audacious.desktop;\n"
  1319. mimeFileContent += "audio/x-psf=audacious.desktop;\n"
  1320. if self.ch_app_image.isChecked():
  1321. imageApp = self.cb_app_image.currentText().replace("/","-")
  1322. mimeFileContent += "image/bmp=%s;\n" % imageApp
  1323. mimeFileContent += "image/gif=%s;\n" % imageApp
  1324. mimeFileContent += "image/jp2=%s;\n" % imageApp
  1325. mimeFileContent += "image/jpeg=%s;\n" % imageApp
  1326. mimeFileContent += "image/png=%s;\n" % imageApp
  1327. mimeFileContent += "image/svg+xml=%s;\n" % imageApp
  1328. mimeFileContent += "image/svg+xml-compressed=%s;\n" % imageApp
  1329. mimeFileContent += "image/tiff=%s;\n" % imageApp
  1330. mimeFileContent += "image/x-canon-cr2=%s;\n" % imageApp
  1331. mimeFileContent += "image/x-canon-crw=%s;\n" % imageApp
  1332. mimeFileContent += "image/x-eps=%s;\n" % imageApp
  1333. mimeFileContent += "image/x-kodak-dcr=%s;\n" % imageApp
  1334. mimeFileContent += "image/x-kodak-k25=%s;\n" % imageApp
  1335. mimeFileContent += "image/x-kodak-kdc=%s;\n" % imageApp
  1336. mimeFileContent += "image/x-nikon-nef=%s;\n" % imageApp
  1337. mimeFileContent += "image/x-olympus-orf=%s;\n" % imageApp
  1338. mimeFileContent += "image/x-panasonic-raw=%s;\n" % imageApp
  1339. mimeFileContent += "image/x-pcx=%s;\n" % imageApp
  1340. mimeFileContent += "image/x-pentax-pef=%s;\n" % imageApp
  1341. mimeFileContent += "image/x-portable-anymap=%s;\n" % imageApp
  1342. mimeFileContent += "image/x-portable-bitmap=%s;\n" % imageApp
  1343. mimeFileContent += "image/x-portable-graymap=%s;\n" % imageApp
  1344. mimeFileContent += "image/x-portable-pixmap=%s;\n" % imageApp
  1345. mimeFileContent += "image/x-sony-arw=%s;\n" % imageApp
  1346. mimeFileContent += "image/x-sony-sr2=%s;\n" % imageApp
  1347. mimeFileContent += "image/x-sony-srf=%s;\n" % imageApp
  1348. mimeFileContent += "image/x-tga=%s;\n" % imageApp
  1349. mimeFileContent += "image/x-xbitmap=%s;\n" % imageApp
  1350. mimeFileContent += "image/x-xpixmap=%s;\n" % imageApp
  1351. if self.ch_app_music.isChecked():
  1352. musicApp = self.cb_app_music.currentText().replace("/","-")
  1353. mimeFileContent += "application/vnd.apple.mpegurl=%s;\n" % musicApp
  1354. mimeFileContent += "application/xspf+xml=%s;\n" % musicApp
  1355. mimeFileContent += "application/x-smaf=%s;\n" % musicApp
  1356. mimeFileContent += "audio/AMR=%s;\n" % musicApp
  1357. mimeFileContent += "audio/AMR-WB=%s;\n" % musicApp
  1358. mimeFileContent += "audio/aac=%s;\n" % musicApp
  1359. mimeFileContent += "audio/ac3=%s;\n" % musicApp
  1360. mimeFileContent += "audio/basic=%s;\n" % musicApp
  1361. mimeFileContent += "audio/flac=%s;\n" % musicApp
  1362. mimeFileContent += "audio/m3u=%s;\n" % musicApp
  1363. mimeFileContent += "audio/mp2=%s;\n" % musicApp
  1364. mimeFileContent += "audio/mp4=%s;\n" % musicApp
  1365. mimeFileContent += "audio/mpeg=%s;\n" % musicApp
  1366. mimeFileContent += "audio/ogg=%s;\n" % musicApp
  1367. mimeFileContent += "audio/vnd.rn-realaudio=%s;\n" % musicApp
  1368. mimeFileContent += "audio/vorbis=%s;\n" % musicApp
  1369. mimeFileContent += "audio/webm=%s;\n" % musicApp
  1370. mimeFileContent += "audio/wav=%s;\n" % musicApp
  1371. mimeFileContent += "audio/x-adpcm=%s;\n" % musicApp
  1372. mimeFileContent += "audio/x-aifc=%s;\n" % musicApp
  1373. mimeFileContent += "audio/x-aiff=%s;\n" % musicApp
  1374. mimeFileContent += "audio/x-aiffc=%s;\n" % musicApp
  1375. mimeFileContent += "audio/x-ape=%s;\n" % musicApp
  1376. mimeFileContent += "audio/x-cda=%s;\n" % musicApp
  1377. mimeFileContent += "audio/x-flac=%s;\n" % musicApp
  1378. mimeFileContent += "audio/x-flac+ogg=%s;\n" % musicApp
  1379. mimeFileContent += "audio/x-gsm=%s;\n" % musicApp
  1380. mimeFileContent += "audio/x-m4b=%s;\n" % musicApp
  1381. mimeFileContent += "audio/x-matroska=%s;\n" % musicApp
  1382. mimeFileContent += "audio/x-mp2=%s;\n" % musicApp
  1383. mimeFileContent += "audio/x-mpegurl=%s;\n" % musicApp
  1384. mimeFileContent += "audio/x-ms-asx=%s;\n" % musicApp
  1385. mimeFileContent += "audio/x-ms-wma=%s;\n" % musicApp
  1386. mimeFileContent += "audio/x-musepack=%s;\n" % musicApp
  1387. mimeFileContent += "audio/x-ogg=%s;\n" % musicApp
  1388. mimeFileContent += "audio/x-oggflac=%s;\n" % musicApp
  1389. mimeFileContent += "audio/x-pn-realaudio-plugin=%s;\n" % musicApp
  1390. mimeFileContent += "audio/x-riff=%s;\n" % musicApp
  1391. mimeFileContent += "audio/x-scpls=%s;\n" % musicApp
  1392. mimeFileContent += "audio/x-speex=%s;\n" % musicApp
  1393. mimeFileContent += "audio/x-speex+ogg=%s;\n" % musicApp
  1394. mimeFileContent += "audio/x-tta=%s;\n" % musicApp
  1395. mimeFileContent += "audio/x-vorbis+ogg=%s;\n" % musicApp
  1396. mimeFileContent += "audio/x-wav=%s;\n" % musicApp
  1397. mimeFileContent += "audio/x-wavpack=%s;\n" % musicApp
  1398. if self.ch_app_video.isChecked():
  1399. videoApp = self.cb_app_video.currentText().replace("/","-")
  1400. mimeFileContent +="application/mxf=%s;\n" % videoApp
  1401. mimeFileContent +="application/ogg=%s;\n" % videoApp
  1402. mimeFileContent +="application/ram=%s;\n" % videoApp
  1403. mimeFileContent +="application/vnd.ms-asf=%s;\n" % videoApp
  1404. mimeFileContent +="application/vnd.ms-wpl=%s;\n" % videoApp
  1405. mimeFileContent +="application/vnd.rn-realmedia=%s;\n" % videoApp
  1406. mimeFileContent +="application/x-ms-wmp=%s;\n" % videoApp
  1407. mimeFileContent +="application/x-ms-wms=%s;\n" % videoApp
  1408. mimeFileContent +="application/x-netshow-channel=%s;\n" % videoApp
  1409. mimeFileContent +="application/x-ogg=%s;\n" % videoApp
  1410. mimeFileContent +="application/x-quicktime-media-link=%s;\n" % videoApp
  1411. mimeFileContent +="video/3gpp=%s;\n" % videoApp
  1412. mimeFileContent +="video/3gpp2=%s;\n" % videoApp
  1413. mimeFileContent +="video/divx=%s;\n" % videoApp
  1414. mimeFileContent +="video/dv=%s;\n" % videoApp
  1415. mimeFileContent +="video/flv=%s;\n" % videoApp
  1416. mimeFileContent +="video/mp2t=%s;\n" % videoApp
  1417. mimeFileContent +="video/mp4=%s;\n" % videoApp
  1418. mimeFileContent +="video/mpeg=%s;\n" % videoApp
  1419. mimeFileContent +="video/ogg=%s;\n" % videoApp
  1420. mimeFileContent +="video/quicktime=%s;\n" % videoApp
  1421. mimeFileContent +="video/vivo=%s;\n" % videoApp
  1422. mimeFileContent +="video/vnd.rn-realvideo=%s;\n" % videoApp
  1423. mimeFileContent +="video/webm=%s;\n" % videoApp
  1424. mimeFileContent +="video/x-anim=%s;\n" % videoApp
  1425. mimeFileContent +="video/x-flic=%s;\n" % videoApp
  1426. mimeFileContent +="video/x-flv=%s;\n" % videoApp
  1427. mimeFileContent +="video/x-m4v=%s;\n" % videoApp
  1428. mimeFileContent +="video/x-matroska=%s;\n" % videoApp
  1429. mimeFileContent +="video/x-ms-asf=%s;\n" % videoApp
  1430. mimeFileContent +="video/x-ms-wm=%s;\n" % videoApp
  1431. mimeFileContent +="video/x-ms-wmp=%s;\n" % videoApp
  1432. mimeFileContent +="video/x-ms-wmv=%s;\n" % videoApp
  1433. mimeFileContent +="video/x-ms-wvx=%s;\n" % videoApp
  1434. mimeFileContent +="video/x-msvideo=%s;\n" % videoApp
  1435. mimeFileContent +="video/x-nsv=%s;\n" % videoApp
  1436. mimeFileContent +="video/x-ogg=%s;\n" % videoApp
  1437. mimeFileContent +="video/x-ogm=%s;\n" % videoApp
  1438. mimeFileContent +="video/x-ogm+ogg=%s;\n" % videoApp
  1439. mimeFileContent +="video/x-theora=%s;\n" % videoApp
  1440. mimeFileContent +="video/x-theora+ogg=%s;\n" % videoApp
  1441. mimeFileContent +="video/x-wmv=%s;\n" % videoApp
  1442. if self.ch_app_text.isChecked():
  1443. # TODO - more mimetypes
  1444. textApp = self.cb_app_text.currentText().replace("/","-")
  1445. mimeFileContent +="application/rdf+xml=%s;\n" % textApp
  1446. mimeFileContent +="application/xml=%s;\n" % textApp
  1447. mimeFileContent +="application/xml-dtd=%s;\n" % textApp
  1448. mimeFileContent +="application/xml-external-parsed-entity=%s;\n" % textApp
  1449. mimeFileContent +="application/xsd=%s;\n" % textApp
  1450. mimeFileContent +="application/xslt+xml=%s;\n" % textApp
  1451. mimeFileContent +="application/x-trash=%s;\n" % textApp
  1452. mimeFileContent +="application/x-wine-extension-inf=%s;\n" % textApp
  1453. mimeFileContent +="application/x-wine-extension-ini=%s;\n" % textApp
  1454. mimeFileContent +="application/x-zerosize=%s;\n" % textApp
  1455. mimeFileContent +="text/css=%s;\n" % textApp
  1456. mimeFileContent +="text/plain=%s;\n" % textApp
  1457. mimeFileContent +="text/x-authors=%s;\n" % textApp
  1458. mimeFileContent +="text/x-c++-hdr=%s;\n" % textApp
  1459. mimeFileContent +="text/x-c++-src=%s;\n" % textApp
  1460. mimeFileContent +="text/x-changelog=%s;\n" % textApp
  1461. mimeFileContent +="text/x-chdr=%s;\n" % textApp
  1462. mimeFileContent +="text/x-cmake=%s;\n" % textApp
  1463. mimeFileContent +="text/x-copying=%s;\n" % textApp
  1464. mimeFileContent +="text/x-credits=%s;\n" % textApp
  1465. mimeFileContent +="text/x-csharp=%s;\n" % textApp
  1466. mimeFileContent +="text/x-csrc=%s;\n" % textApp
  1467. mimeFileContent +="text/x-install=%s;\n" % textApp
  1468. mimeFileContent +="text/x-log=%s;\n" % textApp
  1469. mimeFileContent +="text/x-lua=%s;\n" % textApp
  1470. mimeFileContent +="text/x-makefile=%s;\n" % textApp
  1471. mimeFileContent +="text/x-ms-regedit=%s;\n" % textApp
  1472. mimeFileContent +="text/x-nfo=%s;\n" % textApp
  1473. mimeFileContent +="text/x-objchdr=%s;\n" % textApp
  1474. mimeFileContent +="text/x-objcsrc=%s;\n" % textApp
  1475. mimeFileContent +="text/x-pascal=%s;\n" % textApp
  1476. mimeFileContent +="text/x-patch=%s;\n" % textApp
  1477. mimeFileContent +="text/x-python=%s;\n" % textApp
  1478. mimeFileContent +="text/x-readme=%s;\n" % textApp
  1479. mimeFileContent +="text/x-vhdl=%s;\n" % textApp
  1480. if self.ch_app_browser.isChecked():
  1481. # TODO - needs something else for default browser
  1482. browserApp = self.cb_app_browser.currentText().replace("/","-")
  1483. mimeFileContent +="application/atom+xml=%s;\n" % browserApp
  1484. mimeFileContent +="application/rss+xml=%s;\n" % browserApp
  1485. mimeFileContent +="application/vnd.mozilla.xul+xml=%s;\n" % browserApp
  1486. mimeFileContent +="application/x-mozilla-bookmarks=%s;\n" % browserApp
  1487. mimeFileContent +="application/x-mswinurl=%s;\n" % browserApp
  1488. mimeFileContent +="application/x-xbel=%s;\n" % browserApp
  1489. mimeFileContent +="application/xhtml+xml=%s;\n" % browserApp
  1490. mimeFileContent +="text/html=%s;\n" % browserApp
  1491. mimeFileContent +="text/opml+xml=%s;\n" % browserApp
  1492. realMimeFileContent ="[Default Applications]\n"
  1493. realMimeFileContent += mimeFileContent
  1494. realMimeFileContent +="\n"
  1495. realMimeFileContent +="[Added Associations]\n"
  1496. realMimeFileContent += mimeFileContent
  1497. realMimeFileContent +="\n"
  1498. local_xdg_defaults = os.path.join(HOME, ".local", "share", "applications", "defaults.list")
  1499. local_xdg_mimeapps = os.path.join(HOME, ".local", "share", "applications", "mimeapps.list")
  1500. writeFile = open(local_xdg_defaults, "w")
  1501. writeFile.write(realMimeFileContent)
  1502. writeFile.close()
  1503. writeFile = open(local_xdg_mimeapps, "w")
  1504. writeFile.write(realMimeFileContent)
  1505. writeFile.close()
  1506. if "wineasio" in self.settings_changed_types:
  1507. REGFILE = 'REGEDIT4\n'
  1508. REGFILE += '\n'
  1509. REGFILE += '[HKEY_CURRENT_USER\Software\Wine\WineASIO]\n'
  1510. REGFILE += '"Autostart server"=dword:0000000%i\n' % int(1 if self.cb_wineasio_autostart.isChecked() else 0)
  1511. REGFILE += '"Connect to hardware"=dword:0000000%i\n' % int(1 if self.cb_wineasio_hw.isChecked() else 0)
  1512. REGFILE += '"Fixed buffersize"=dword:0000000%i\n' % int(1 if self.cb_wineasio_fixed_bsize.isChecked() else 0)
  1513. REGFILE += '"Number of inputs"=dword:000000%s\n' % smartHex(self.sb_wineasio_ins.value(), 2)
  1514. REGFILE += '"Number of outputs"=dword:000000%s\n' % smartHex(self.sb_wineasio_outs.value(), 2)
  1515. REGFILE += '"Preferred buffersize"=dword:0000%s\n' % smartHex(int(self.cb_wineasio_bsizes.currentText()), 4)
  1516. writeFile = open("/tmp/cadence-wineasio.reg", "w")
  1517. writeFile.write(REGFILE)
  1518. writeFile.close()
  1519. os.system("regedit /tmp/cadence-wineasio.reg")
  1520. self.settings_changed_types = []
  1521. self.frame_tweaks_settings.setVisible(False)
  1522. @pyqtSlot()
  1523. def slot_tweaksSettingsChanged_apps(self):
  1524. self.func_settings_changed("apps")
  1525. @pyqtSlot()
  1526. def slot_tweaksSettingsChanged_wineasio(self):
  1527. self.func_settings_changed("wineasio")
  1528. @pyqtSlot(int)
  1529. def slot_tweakAppImageHighlighted(self, index):
  1530. self.setAppDetails(self.cb_app_image.itemText(index))
  1531. @pyqtSlot(int)
  1532. def slot_tweakAppImageChanged(self):
  1533. self.setAppDetails(self.cb_app_image.currentText())
  1534. self.func_settings_changed("apps")
  1535. @pyqtSlot(int)
  1536. def slot_tweakAppMusicHighlighted(self, index):
  1537. self.setAppDetails(self.cb_app_music.itemText(index))
  1538. @pyqtSlot(int)
  1539. def slot_tweakAppMusicChanged(self):
  1540. self.setAppDetails(self.cb_app_music.currentText())
  1541. self.func_settings_changed("apps")
  1542. @pyqtSlot(int)
  1543. def slot_tweakAppVideoHighlighted(self, index):
  1544. self.setAppDetails(self.cb_app_video.itemText(index))
  1545. @pyqtSlot(int)
  1546. def slot_tweakAppVideoChanged(self):
  1547. self.setAppDetails(self.cb_app_video.currentText())
  1548. self.func_settings_changed("apps")
  1549. @pyqtSlot(int)
  1550. def slot_tweakAppTextHighlighted(self, index):
  1551. self.setAppDetails(self.cb_app_text.itemText(index))
  1552. @pyqtSlot(int)
  1553. def slot_tweakAppTextChanged(self):
  1554. self.setAppDetails(self.cb_app_text.currentText())
  1555. self.func_settings_changed("apps")
  1556. @pyqtSlot(int)
  1557. def slot_tweakAppBrowserHighlighted(self, index):
  1558. self.setAppDetails(self.cb_app_browser.itemText(index))
  1559. @pyqtSlot(int)
  1560. def slot_tweakAppBrowserChanged(self):
  1561. self.setAppDetails(self.cb_app_browser.currentText())
  1562. self.func_settings_changed("apps")
  1563. @pyqtSlot()
  1564. def slot_tweakPluginAdd(self):
  1565. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), "", QFileDialog.ShowDirsOnly)
  1566. if not newPath:
  1567. return
  1568. if self.tb_tweak_plugins.currentIndex() == 0:
  1569. self.list_LADSPA.addItem(newPath)
  1570. elif self.tb_tweak_plugins.currentIndex() == 1:
  1571. self.list_DSSI.addItem(newPath)
  1572. elif self.tb_tweak_plugins.currentIndex() == 2:
  1573. self.list_LV2.addItem(newPath)
  1574. elif self.tb_tweak_plugins.currentIndex() == 3:
  1575. self.list_VST.addItem(newPath)
  1576. self.func_settings_changed("plugins")
  1577. @pyqtSlot()
  1578. def slot_tweakPluginChange(self):
  1579. if self.tb_tweak_plugins.currentIndex() == 0:
  1580. curPath = self.list_LADSPA.item(self.list_LADSPA.currentRow()).text()
  1581. elif self.tb_tweak_plugins.currentIndex() == 1:
  1582. curPath = self.list_DSSI.item(self.list_DSSI.currentRow()).text()
  1583. elif self.tb_tweak_plugins.currentIndex() == 2:
  1584. curPath = self.list_LV2.item(self.list_LV2.currentRow()).text()
  1585. elif self.tb_tweak_plugins.currentIndex() == 3:
  1586. curPath = self.list_VST.item(self.list_VST.currentRow()).text()
  1587. else:
  1588. curPath = ""
  1589. newPath = QFileDialog.getExistingDirectory(self, self.tr("Change Path"), curPath, QFileDialog.ShowDirsOnly)
  1590. if not newPath:
  1591. return
  1592. if self.tb_tweak_plugins.currentIndex() == 0:
  1593. self.list_LADSPA.item(self.list_LADSPA.currentRow()).setText(newPath)
  1594. elif self.tb_tweak_plugins.currentIndex() == 1:
  1595. self.list_DSSI.item(self.list_DSSI.currentRow()).setText(newPath)
  1596. elif self.tb_tweak_plugins.currentIndex() == 2:
  1597. self.list_LV2.item(self.list_LV2.currentRow()).setText(newPath)
  1598. elif self.tb_tweak_plugins.currentIndex() == 3:
  1599. self.list_VST.item(self.list_VST.currentRow()).setText(newPath)
  1600. self.func_settings_changed("plugins")
  1601. @pyqtSlot()
  1602. def slot_tweakPluginRemove(self):
  1603. if self.tb_tweak_plugins.currentIndex() == 0:
  1604. self.list_LADSPA.takeItem(self.list_LADSPA.currentRow())
  1605. elif self.tb_tweak_plugins.currentIndex() == 1:
  1606. self.list_DSSI.takeItem(self.list_DSSI.currentRow())
  1607. elif self.tb_tweak_plugins.currentIndex() == 2:
  1608. self.list_LV2.takeItem(self.list_LV2.currentRow())
  1609. elif self.tb_tweak_plugins.currentIndex() == 3:
  1610. self.list_VST.takeItem(self.list_VST.currentRow())
  1611. self.func_settings_changed("plugins")
  1612. @pyqtSlot()
  1613. def slot_tweakPluginReset(self):
  1614. if self.tb_tweak_plugins.currentIndex() == 0:
  1615. self.list_LADSPA.clear()
  1616. for iPath in DEFAULT_LADSPA_PATH:
  1617. self.list_LADSPA.addItem(iPath)
  1618. elif self.tb_tweak_plugins.currentIndex() == 1:
  1619. self.list_DSSI.clear()
  1620. for iPath in DEFAULT_DSSI_PATH:
  1621. self.list_DSSI.addItem(iPath)
  1622. elif self.tb_tweak_plugins.currentIndex() == 2:
  1623. self.list_LV2.clear()
  1624. for iPath in DEFAULT_LV2_PATH:
  1625. self.list_LV2.addItem(iPath)
  1626. elif self.tb_tweak_plugins.currentIndex() == 3:
  1627. self.list_VST.clear()
  1628. for iPath in DEFAULT_VST_PATH:
  1629. self.list_VST.addItem(iPath)
  1630. self.func_settings_changed("plugins")
  1631. @pyqtSlot(int)
  1632. def slot_tweakPluginTypeChanged(self, index):
  1633. # Force row change
  1634. if index == 0:
  1635. self.list_LADSPA.setCurrentRow(-1)
  1636. self.list_LADSPA.setCurrentRow(0)
  1637. elif index == 1:
  1638. self.list_DSSI.setCurrentRow(-1)
  1639. self.list_DSSI.setCurrentRow(0)
  1640. elif index == 2:
  1641. self.list_LV2.setCurrentRow(-1)
  1642. self.list_LV2.setCurrentRow(0)
  1643. elif index == 3:
  1644. self.list_VST.setCurrentRow(-1)
  1645. self.list_VST.setCurrentRow(0)
  1646. @pyqtSlot(int)
  1647. def slot_tweakPluginsLadspaRowChanged(self, index):
  1648. nonRemovable = (index >= 0 and self.list_LADSPA.item(index).text() not in DEFAULT_LADSPA_PATH)
  1649. self.b_tweak_plugins_change.setEnabled(nonRemovable)
  1650. self.b_tweak_plugins_remove.setEnabled(nonRemovable)
  1651. @pyqtSlot(int)
  1652. def slot_tweakPluginsDssiRowChanged(self, index):
  1653. nonRemovable = (index >= 0 and self.list_DSSI.item(index).text() not in DEFAULT_DSSI_PATH)
  1654. self.b_tweak_plugins_change.setEnabled(nonRemovable)
  1655. self.b_tweak_plugins_remove.setEnabled(nonRemovable)
  1656. @pyqtSlot(int)
  1657. def slot_tweakPluginsLv2RowChanged(self, index):
  1658. nonRemovable = (index >= 0 and self.list_LV2.item(index).text() not in DEFAULT_LV2_PATH)
  1659. self.b_tweak_plugins_change.setEnabled(nonRemovable)
  1660. self.b_tweak_plugins_remove.setEnabled(nonRemovable)
  1661. @pyqtSlot(int)
  1662. def slot_tweakPluginsVstRowChanged(self, index):
  1663. nonRemovable = (index >= 0 and self.list_VST.item(index).text() not in DEFAULT_VST_PATH)
  1664. self.b_tweak_plugins_change.setEnabled(nonRemovable)
  1665. self.b_tweak_plugins_remove.setEnabled(nonRemovable)
  1666. def saveSettings(self):
  1667. self.settings.setValue("Geometry", self.saveGeometry())
  1668. GlobalSettings.setValue("JACK/AutoStart", self.cb_jack_autostart.isChecked())
  1669. GlobalSettings.setValue("ALSA-Audio/BridgeIndexType", self.cb_alsa_type.currentIndex())
  1670. GlobalSettings.setValue("A2J/AutoStart", self.cb_a2j_autostart.isChecked())
  1671. GlobalSettings.setValue("Pulse2JACK/AutoStart", (havePulseAudio and self.cb_pulse_autostart.isChecked()))
  1672. def loadSettings(self, geometry):
  1673. if geometry:
  1674. self.restoreGeometry(self.settings.value("Geometry", ""))
  1675. self.m_savedSettings = {
  1676. "Main/UseSystemTray": self.settings.value("Main/UseSystemTray", True, type=bool),
  1677. "Main/CloseToTray": self.settings.value("Main/CloseToTray", True, type=bool)
  1678. }
  1679. self.cb_jack_autostart.setChecked(GlobalSettings.value("JACK/AutoStart", True, type=bool))
  1680. self.cb_a2j_autostart.setChecked(GlobalSettings.value("A2J/AutoStart", True, type=bool))
  1681. self.cb_pulse_autostart.setChecked(GlobalSettings.value("Pulse2JACK/AutoStart", havePulseAudio, type=bool))
  1682. def timerEvent(self, event):
  1683. if event.timerId() == self.m_timer500:
  1684. if DBus.jack and self.m_last_dsp_load != None:
  1685. next_dsp_load = DBus.jack.GetLoad()
  1686. next_xruns = DBus.jack.GetXruns()
  1687. needUpdateTip = False
  1688. if self.m_last_dsp_load != next_dsp_load:
  1689. self.m_last_dsp_load = next_dsp_load
  1690. self.label_jack_dsp.setText("%.2f%%" % self.m_last_dsp_load)
  1691. needUpdateTip = True
  1692. if self.m_last_xruns != next_xruns:
  1693. self.m_last_xruns = next_xruns
  1694. self.label_jack_xruns.setText(str(self.m_last_xruns))
  1695. needUpdateTip = True
  1696. if needUpdateTip:
  1697. self.updateSystrayTooltip()
  1698. elif event.timerId() == self.m_timer2000:
  1699. if DBus.jack and self.m_last_buffer_size != None:
  1700. next_buffer_size = DBus.jack.GetBufferSize()
  1701. if self.m_last_buffer_size != next_buffer_size:
  1702. self.m_last_buffer_size = next_buffer_size
  1703. self.label_jack_bfsize.setText("%i samples" % self.m_last_buffer_size)
  1704. self.label_jack_latency.setText("%.1f ms" % DBus.jack.GetLatency())
  1705. else:
  1706. self.update()
  1707. QMainWindow.timerEvent(self, event)
  1708. def closeEvent(self, event):
  1709. self.saveSettings()
  1710. self.systray.close()
  1711. QMainWindow.closeEvent(self, event)
  1712. #--------------- main ------------------
  1713. if __name__ == '__main__':
  1714. # App initialization
  1715. app = QApplication(sys.argv)
  1716. app.setApplicationName("Cadence")
  1717. app.setApplicationVersion(VERSION)
  1718. app.setOrganizationName("Cadence")
  1719. app.setWindowIcon(QIcon(":/scalable/cadence.svg"))
  1720. if haveDBus:
  1721. DBus.loop = DBusQtMainLoop(set_as_default=True)
  1722. DBus.bus = dbus.SessionBus(mainloop=DBus.loop)
  1723. initSystemChecks()
  1724. # Show GUI
  1725. gui = CadenceMainW()
  1726. # Set-up custom signal handling
  1727. setUpSignals(gui)
  1728. if "--gnome-settings" in app.arguments():
  1729. gui.tabWidget.removeTab(0)
  1730. gui.tabWidget.removeTab(0)
  1731. gui.tabWidget.tabBar().hide()
  1732. gui.label_tweaks.setText(gui.tr("Cadence Tweaks"))
  1733. gui.systray.hide()
  1734. if "--minimized" in app.arguments():
  1735. gui.hide()
  1736. gui.systray.setActionText("show", gui.tr("Restore"))
  1737. else:
  1738. gui.show()
  1739. # Exit properly
  1740. sys.exit(gui.systray.exec_(app))