Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1623 lines
62KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin database code
  4. # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or 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 doc/GPL.txt file.
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. try:
  20. from PyQt5.QtCore import Qt, QThread, QSettings
  21. from PyQt5.QtWidgets import QDialog, QTableWidgetItem
  22. except:
  23. from PyQt4.QtCore import Qt, QThread, QSettings
  24. from PyQt4.QtGui import QDialog, QTableWidgetItem
  25. # ------------------------------------------------------------------------------------------------------------
  26. # Imports (Custom)
  27. import ui_carla_database
  28. import ui_carla_refresh
  29. from carla_shared import *
  30. # ------------------------------------------------------------------------------------------------------------
  31. # Import json
  32. if haveLRDF:
  33. import json
  34. # ------------------------------------------------------------------------------------------------------------
  35. # Plugin Query (helper functions)
  36. def findBinaries(binPath, OS):
  37. binaries = []
  38. if OS == "WINDOWS":
  39. extensions = (".dll",)
  40. elif OS == "MACOS":
  41. extensions = (".dylib", ".so")
  42. else:
  43. extensions = (".so",)
  44. for root, dirs, files in os.walk(binPath):
  45. for name in [name for name in files if name.lower().endswith(extensions)]:
  46. binaries.append(os.path.join(root, name))
  47. return binaries
  48. def findLV2Bundles(bundlePath):
  49. bundles = []
  50. for root, dirs, files in os.walk(bundlePath):
  51. if os.path.exists(os.path.join(root, "manifest.ttl")):
  52. bundles.append(root)
  53. return bundles
  54. def findMacVSTBundles(bundlePath):
  55. bundles = []
  56. for root, dirs, files in os.walk(bundlePath):
  57. for name in [name for name in dirs if name.lower().endswith(".vst")]:
  58. bundles.append(os.path.join(root, name))
  59. return bundles
  60. def findFilenames(filePath, stype):
  61. filenames = []
  62. if stype == "csound":
  63. extensions = (".csd",)
  64. elif stype == "gig":
  65. extensions = (".gig",)
  66. elif stype == "sf2":
  67. extensions = (".sf2",)
  68. elif stype == "sfz":
  69. extensions = (".sfz",)
  70. else:
  71. return []
  72. for root, dirs, files in os.walk(filePath):
  73. for name in [name for name in files if name.lower().endswith(extensions)]:
  74. filenames.append(os.path.join(root, name))
  75. return filenames
  76. # FIXME - put this into c++ discovery
  77. def findDSSIGUI(filename, name, label):
  78. pluginDir = filename.rsplit(".", 1)[0]
  79. shortName = os.path.basename(pluginDir)
  80. guiFilename = ""
  81. checkName = name.replace(" ", "_")
  82. checkLabel = label
  83. checkSName = shortName
  84. if checkName[-1] != "_": checkName += "_"
  85. if checkLabel[-1] != "_": checkLabel += "_"
  86. if checkSName[-1] != "_": checkSName += "_"
  87. for root, dirs, files in os.walk(pluginDir):
  88. guiFiles = files
  89. break
  90. else:
  91. guiFiles = []
  92. for guiFile in guiFiles:
  93. if guiFile.startswith((checkName, checkLabel, checkSName)):
  94. guiFilename = os.path.join(pluginDir, guiFile)
  95. break
  96. return guiFilename
  97. # ------------------------------------------------------------------------------------------------------------
  98. # Plugin Query
  99. PLUGIN_QUERY_API_VERSION = 1
  100. PyPluginInfo = {
  101. 'API': PLUGIN_QUERY_API_VERSION,
  102. 'build': BINARY_NONE,
  103. 'type': PLUGIN_NONE,
  104. 'hints': 0x0,
  105. 'binary': "",
  106. 'name': "",
  107. 'label': "",
  108. 'maker': "",
  109. 'copyright': "",
  110. 'uniqueId': 0,
  111. 'audio.ins': 0,
  112. 'audio.outs': 0,
  113. 'audio.total': 0,
  114. 'midi.ins': 0,
  115. 'midi.outs': 0,
  116. 'midi.total': 0,
  117. 'parameters.ins': 0,
  118. 'parameters.outs': 0,
  119. 'parameters.total': 0,
  120. 'programs.total': 0
  121. }
  122. global discoveryProcess
  123. discoveryProcess = None
  124. def runCarlaDiscovery(itype, stype, filename, tool, isWine=False):
  125. if not os.path.exists(tool):
  126. qCritical("runCarlaDiscovery() - tool '%s' does not exist" % tool)
  127. return
  128. command = []
  129. if LINUX or MACOS:
  130. command.append("env")
  131. command.append("LANG=C")
  132. if isWine:
  133. command.append("WINEDEBUG=-all")
  134. command.append(tool)
  135. command.append(stype)
  136. command.append(filename)
  137. global discoveryProcess
  138. discoveryProcess = Popen(command, stdout=PIPE)
  139. try:
  140. discoveryProcess.wait()
  141. output = discoveryProcess.stdout.read().decode("utf-8", errors="ignore").split("\n")
  142. except:
  143. output = ()
  144. pinfo = None
  145. plugins = []
  146. fakeLabel = os.path.basename(filename).rsplit(".", 1)[0]
  147. for line in output:
  148. line = line.strip()
  149. if line == "carla-discovery::init::-----------":
  150. pinfo = deepcopy(PyPluginInfo)
  151. pinfo['type'] = itype
  152. pinfo['binary'] = filename
  153. elif line == "carla-discovery::end::------------":
  154. if pinfo != None:
  155. plugins.append(pinfo)
  156. del pinfo
  157. pinfo = None
  158. elif line == "Segmentation fault":
  159. print("carla-discovery::crash::%s crashed during discovery" % filename)
  160. elif line.startswith("err:module:import_dll Library"):
  161. print(line)
  162. elif line.startswith("carla-discovery::error::"):
  163. print("%s - %s" % (line, filename))
  164. elif line.startswith("carla-discovery::"):
  165. if pinfo == None:
  166. continue
  167. try:
  168. prop, value = line.replace("carla-discovery::", "").split("::", 1)
  169. except:
  170. continue
  171. if prop == "name":
  172. pinfo['name'] = value if value else fakeLabel
  173. elif prop == "label":
  174. pinfo['label'] = value if value else fakeLabel
  175. elif prop == "maker":
  176. pinfo['maker'] = value
  177. elif prop == "copyright":
  178. pinfo['copyright'] = value
  179. elif prop == "uniqueId":
  180. if value.isdigit(): pinfo['uniqueId'] = int(value)
  181. elif prop == "hints":
  182. if value.isdigit(): pinfo['hints'] = int(value)
  183. elif prop == "audio.ins":
  184. if value.isdigit(): pinfo['audio.ins'] = int(value)
  185. elif prop == "audio.outs":
  186. if value.isdigit(): pinfo['audio.outs'] = int(value)
  187. elif prop == "audio.total":
  188. if value.isdigit(): pinfo['audio.total'] = int(value)
  189. elif prop == "midi.ins":
  190. if value.isdigit(): pinfo['midi.ins'] = int(value)
  191. elif prop == "midi.outs":
  192. if value.isdigit(): pinfo['midi.outs'] = int(value)
  193. elif prop == "midi.total":
  194. if value.isdigit(): pinfo['midi.total'] = int(value)
  195. elif prop == "parameters.ins":
  196. if value.isdigit(): pinfo['parameters.ins'] = int(value)
  197. elif prop == "parameters.outs":
  198. if value.isdigit(): pinfo['parameters.outs'] = int(value)
  199. elif prop == "parameters.total":
  200. if value.isdigit(): pinfo['parameters.total'] = int(value)
  201. elif prop == "programs.total":
  202. if value.isdigit(): pinfo['programs.total'] = int(value)
  203. elif prop == "build":
  204. if value.isdigit(): pinfo['build'] = int(value)
  205. elif prop == "uri":
  206. if value: pinfo['label'] = value
  207. else:
  208. # cannot use empty URIs
  209. del pinfo
  210. pinfo = None
  211. continue
  212. # FIXME - put this into c++ discovery
  213. for pinfo in plugins:
  214. if itype == PLUGIN_DSSI:
  215. if findDSSIGUI(pinfo['binary'], pinfo['name'], pinfo['label']):
  216. pinfo['hints'] |= PLUGIN_HAS_GUI
  217. # FIXME?
  218. tmp = discoveryProcess
  219. discoveryProcess = None
  220. del discoveryProcess, tmp
  221. return plugins
  222. def killDiscovery():
  223. global discoveryProcess
  224. if discoveryProcess is not None:
  225. discoveryProcess.kill()
  226. def checkPluginInternal(desc):
  227. plugins = []
  228. pinfo = deepcopy(PyPluginInfo)
  229. pinfo['build'] = BINARY_NATIVE
  230. pinfo['type'] = PLUGIN_INTERNAL
  231. pinfo['hints'] = int(desc['hints'])
  232. pinfo['name'] = cString(desc['name'])
  233. pinfo['label'] = cString(desc['label'])
  234. pinfo['maker'] = cString(desc['maker'])
  235. pinfo['copyright'] = cString(desc['copyright'])
  236. pinfo['audio.ins'] = int(desc['audioIns'])
  237. pinfo['audio.outs'] = int(desc['audioOuts'])
  238. pinfo['audio.total'] = pinfo['audio.ins'] + pinfo['audio.outs']
  239. pinfo['midi.ins'] = int(desc['midiIns'])
  240. pinfo['midi.outs'] = int(desc['midiOuts'])
  241. pinfo['midi.total'] = pinfo['midi.ins'] + pinfo['midi.outs']
  242. pinfo['parameters.ins'] = int(desc['parameterIns'])
  243. pinfo['parameters.outs'] = int(desc['parameterOuts'])
  244. pinfo['parameters.total'] = pinfo['parameters.ins'] + pinfo['parameters.outs']
  245. plugins.append(pinfo)
  246. return plugins
  247. def checkPluginLADSPA(filename, tool, isWine=False):
  248. return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, isWine)
  249. def checkPluginDSSI(filename, tool, isWine=False):
  250. return runCarlaDiscovery(PLUGIN_DSSI, "DSSI", filename, tool, isWine)
  251. def checkPluginLV2(filename, tool, isWine=False):
  252. return runCarlaDiscovery(PLUGIN_LV2, "LV2", filename, tool, isWine)
  253. def checkPluginVST(filename, tool, isWine=False):
  254. return runCarlaDiscovery(PLUGIN_VST, "VST", filename, tool, isWine)
  255. def checkPluginAU(filename, tool):
  256. return runCarlaDiscovery(PLUGIN_AU, "AU", filename, tool)
  257. def checkPluginCSOUND(filename, tool):
  258. return runCarlaDiscovery(PLUGIN_CSOUND, "CSOUND", filename, tool)
  259. def checkPluginGIG(filename, tool):
  260. return runCarlaDiscovery(PLUGIN_GIG, "GIG", filename, tool)
  261. def checkPluginSF2(filename, tool):
  262. return runCarlaDiscovery(PLUGIN_SF2, "SF2", filename, tool)
  263. def checkPluginSFZ(filename, tool):
  264. return runCarlaDiscovery(PLUGIN_SFZ, "SFZ", filename, tool)
  265. # ------------------------------------------------------------------------------------------------------------
  266. # Separate Thread for Plugin Search
  267. class SearchPluginsThread(QThread):
  268. pluginLook = pyqtSignal(int, str)
  269. def __init__(self, parent):
  270. QThread.__init__(self, parent)
  271. self.fContinueChecking = False
  272. self.fCheckNative = False
  273. self.fCheckPosix32 = False
  274. self.fCheckPosix64 = False
  275. self.fCheckWin32 = False
  276. self.fCheckWin64 = False
  277. self.fCheckLADSPA = False
  278. self.fCheckDSSI = False
  279. self.fCheckLV2 = False
  280. self.fCheckVST = False
  281. self.fCheckAU = False
  282. self.fCheckCSOUND = False
  283. self.fCheckGIG = False
  284. self.fCheckSF2 = False
  285. self.fCheckSFZ = False
  286. self.fToolNative = carla_discovery_native
  287. self.fCurCount = 0
  288. self.fCurPercentValue = 0
  289. self.fLastCheckValue = 0
  290. self.fSomethingChanged = False
  291. self.fLadspaPlugins = []
  292. self.fDssiPlugins = []
  293. self.fLv2Plugins = []
  294. self.fVstPlugins = []
  295. self.fAuPlugins = []
  296. self.fCsoundPlugins = []
  297. self.fKitPlugins = []
  298. # -------------------------------------------------------------
  299. def hasSomethingChanged(self):
  300. return self.fSomethingChanged
  301. def setSearchBinaryTypes(self, native, posix32, posix64, win32, win64):
  302. self.fCheckNative = native
  303. self.fCheckPosix32 = posix32
  304. self.fCheckPosix64 = posix64
  305. self.fCheckWin32 = win32
  306. self.fCheckWin64 = win64
  307. def setSearchPluginTypes(self, ladspa, dssi, lv2, vst, au, csound, gig, sf2, sfz):
  308. self.fCheckLADSPA = ladspa
  309. self.fCheckDSSI = dssi
  310. self.fCheckLV2 = lv2
  311. self.fCheckVST = vst
  312. self.fCheckAU = au and MACOS
  313. self.fCheckCSOUND = csound
  314. self.fCheckGIG = gig
  315. self.fCheckSF2 = sf2
  316. self.fCheckSFZ = sfz
  317. def setSearchToolNative(self, tool):
  318. self.fToolNative = tool
  319. def stop(self):
  320. self.fContinueChecking = False
  321. def run(self):
  322. self.fContinueChecking = True
  323. self.fCurCount = 0
  324. pluginCount = 0
  325. settingsDB = QSettings("falkTX", "CarlaPlugins")
  326. if self.fCheckLADSPA: pluginCount += 1
  327. if self.fCheckDSSI: pluginCount += 1
  328. if self.fCheckLV2: pluginCount += 1
  329. if self.fCheckVST: pluginCount += 1
  330. if self.fCheckAU: pluginCount += 1
  331. if self.fCheckNative:
  332. self.fCurCount += pluginCount
  333. if self.fCheckPosix32:
  334. self.fCurCount += pluginCount
  335. if self.fCheckPosix64:
  336. self.fCurCount += pluginCount
  337. if self.fCheckWin32:
  338. self.fCurCount += pluginCount
  339. if self.fCheckAU: self.fCurCount -= 1
  340. if self.fCheckWin64:
  341. self.fCurCount += pluginCount
  342. if self.fCheckAU: self.fCurCount -= 1
  343. if self.fCheckNative and self.fToolNative:
  344. if self.fCheckCSOUND: self.fCurCount += 1
  345. if self.fCheckGIG: self.fCurCount += 1
  346. if self.fCheckSF2: self.fCurCount += 1
  347. if self.fCheckSFZ: self.fCurCount += 1
  348. else:
  349. self.fCheckCSOUND = False
  350. self.fCheckGIG = False
  351. self.fCheckSF2 = False
  352. self.fCheckSFZ = False
  353. if self.fCurCount == 0:
  354. return
  355. self.fCurPercentValue = 100.0 / self.fCurCount
  356. self.fLastCheckValue = 0.0
  357. if HAIKU:
  358. OS = "HAIKU"
  359. elif LINUX:
  360. OS = "LINUX"
  361. elif MACOS:
  362. OS = "MACOS"
  363. elif WINDOWS:
  364. OS = "WINDOWS"
  365. else:
  366. OS = "UNKNOWN"
  367. if not self.fContinueChecking: return
  368. if self.fCheckLADSPA:
  369. checkValue = 0.0
  370. if haveLRDF:
  371. if self.fCheckNative: checkValue += 0.1
  372. if self.fCheckPosix32: checkValue += 0.1
  373. if self.fCheckPosix64: checkValue += 0.1
  374. if self.fCheckWin32: checkValue += 0.1
  375. if self.fCheckWin64: checkValue += 0.1
  376. rdfPadValue = self.fCurPercentValue * checkValue
  377. if self.fCheckNative:
  378. self._checkLADSPA(OS, self.fToolNative)
  379. settingsDB.setValue("Plugins/LADSPA_native", self.fLadspaPlugins)
  380. if not self.fContinueChecking: return
  381. if self.fCheckPosix32:
  382. self._checkLADSPA(OS, carla_discovery_posix32)
  383. settingsDB.setValue("Plugins/LADSPA_posix32", self.fLadspaPlugins)
  384. if not self.fContinueChecking: return
  385. if self.fCheckPosix64:
  386. self._checkLADSPA(OS, carla_discovery_posix64)
  387. settingsDB.setValue("Plugins/LADSPA_posix64", self.fLadspaPlugins)
  388. if not self.fContinueChecking: return
  389. if self.fCheckWin32:
  390. self._checkLADSPA("WINDOWS", carla_discovery_win32, not WINDOWS)
  391. settingsDB.setValue("Plugins/LADSPA_win32", self.fLadspaPlugins)
  392. if not self.fContinueChecking: return
  393. if self.fCheckWin64:
  394. self._checkLADSPA("WINDOWS", carla_discovery_win64, not WINDOWS)
  395. settingsDB.setValue("Plugins/LADSPA_win64", self.fLadspaPlugins)
  396. settingsDB.sync()
  397. if not self.fContinueChecking: return
  398. if haveLRDF and checkValue > 0:
  399. startValue = self.fLastCheckValue - rdfPadValue
  400. self._pluginLook(startValue, "LADSPA RDFs...")
  401. ladspaRdfInfo = ladspa_rdf.recheck_all_plugins(self, startValue, self.fCurPercentValue, checkValue)
  402. settingsDir = os.path.join(HOME, ".config", "falkTX")
  403. fdLadspa = open(os.path.join(settingsDir, "ladspa_rdf.db"), 'w')
  404. json.dump(ladspaRdfInfo, fdLadspa)
  405. fdLadspa.close()
  406. if not self.fContinueChecking: return
  407. if self.fCheckDSSI:
  408. if self.fCheckNative:
  409. self._checkDSSI(OS, self.fToolNative)
  410. settingsDB.setValue("Plugins/DSSI_native", self.fDssiPlugins)
  411. if not self.fContinueChecking: return
  412. if self.fCheckPosix32:
  413. self._checkDSSI(OS, carla_discovery_posix32)
  414. settingsDB.setValue("Plugins/DSSI_posix32", self.fDssiPlugins)
  415. if not self.fContinueChecking: return
  416. if self.fCheckPosix64:
  417. self._checkDSSI(OS, carla_discovery_posix64)
  418. settingsDB.setValue("Plugins/DSSI_posix64", self.fDssiPlugins)
  419. if not self.fContinueChecking: return
  420. if self.fCheckWin32:
  421. self._checkDSSI("WINDOWS", carla_discovery_win32, not WINDOWS)
  422. settingsDB.setValue("Plugins/DSSI_win32", self.fDssiPlugins)
  423. if not self.fContinueChecking: return
  424. if self.fCheckWin64:
  425. self._checkDSSI("WINDOWS", carla_discovery_win64, not WINDOWS)
  426. settingsDB.setValue("Plugins/DSSI_win64", self.fDssiPlugins)
  427. settingsDB.sync()
  428. if not self.fContinueChecking: return
  429. if self.fCheckLV2:
  430. if self.fCheckNative:
  431. self._checkLV2(self.fToolNative)
  432. settingsDB.setValue("Plugins/LV2_native", self.fLv2Plugins)
  433. if not self.fContinueChecking: return
  434. if self.fCheckPosix32:
  435. self._checkLV2(carla_discovery_posix32)
  436. settingsDB.setValue("Plugins/LV2_posix32", self.fLv2Plugins)
  437. if not self.fContinueChecking: return
  438. if self.fCheckPosix64:
  439. self._checkLV2(carla_discovery_posix64)
  440. settingsDB.setValue("Plugins/LV2_posix64", self.fLv2Plugins)
  441. if not self.fContinueChecking: return
  442. if self.fCheckWin32:
  443. self._checkLV2(carla_discovery_win32, not WINDOWS)
  444. settingsDB.setValue("Plugins/LV2_win32", self.fLv2Plugins)
  445. if not self.fContinueChecking: return
  446. if self.fCheckWin64:
  447. self._checkLV2(carla_discovery_win64, not WINDOWS)
  448. settingsDB.setValue("Plugins/LV2_win64", self.fLv2Plugins)
  449. settingsDB.sync()
  450. if not self.fContinueChecking: return
  451. if self.fCheckVST:
  452. if self.fCheckNative:
  453. self._checkVST(OS, self.fToolNative)
  454. settingsDB.setValue("Plugins/VST_native", self.fVstPlugins)
  455. if not self.fContinueChecking: return
  456. if self.fCheckPosix32:
  457. self._checkVST(OS, carla_discovery_posix32)
  458. settingsDB.setValue("Plugins/VST_posix32", self.fVstPlugins)
  459. if not self.fContinueChecking: return
  460. if self.fCheckPosix64:
  461. self._checkVST(OS, carla_discovery_posix64)
  462. settingsDB.setValue("Plugins/VST_posix64", self.fVstPlugins)
  463. if not self.fContinueChecking: return
  464. if self.fCheckWin32:
  465. self._checkVST("WINDOWS", carla_discovery_win32, not WINDOWS)
  466. settingsDB.setValue("Plugins/VST_win32", self.fVstPlugins)
  467. if not self.fContinueChecking: return
  468. if self.fCheckWin64:
  469. self._checkVST("WINDOWS", carla_discovery_win64, not WINDOWS)
  470. settingsDB.setValue("Plugins/VST_win64", self.fVstPlugins)
  471. settingsDB.sync()
  472. if not self.fContinueChecking: return
  473. if self.fCheckAU:
  474. if self.fCheckNative:
  475. self._checkAU(self.fToolNative)
  476. settingsDB.setValue("Plugins/AU_native", self.fAuPlugins)
  477. if not self.fContinueChecking: return
  478. if self.fCheckPosix32:
  479. self._checkAU(carla_discovery_posix32)
  480. settingsDB.setValue("Plugins/AU_posix32", self.fAuPlugins)
  481. if not self.fContinueChecking: return
  482. if self.fCheckPosix64:
  483. self._checkAU(carla_discovery_posix64)
  484. settingsDB.setValue("Plugins/AU_posix64", self.fAuPlugins)
  485. settingsDB.sync()
  486. if not self.fContinueChecking: return
  487. if self.fCheckCSOUND:
  488. self._checkCSOUND()
  489. settingsDB.setValue("Plugins/CSOUND", self.fCsoundPlugins)
  490. if not self.fContinueChecking: return
  491. if self.fCheckGIG:
  492. self._checkKIT(Carla.GIG_PATH, "gig")
  493. settingsDB.setValue("Plugins/GIG", self.fKitPlugins)
  494. if not self.fContinueChecking: return
  495. if self.fCheckSF2:
  496. self._checkKIT(Carla.SF2_PATH, "sf2")
  497. settingsDB.setValue("Plugins/SF2", self.fKitPlugins)
  498. if not self.fContinueChecking: return
  499. if self.fCheckSFZ:
  500. self._checkKIT(Carla.SFZ_PATH, "sfz")
  501. settingsDB.setValue("Plugins/SFZ", self.fKitPlugins)
  502. settingsDB.sync()
  503. def _checkLADSPA(self, OS, tool, isWine=False):
  504. ladspaBinaries = []
  505. self.fLadspaPlugins = []
  506. self._pluginLook(self.fLastCheckValue, "LADSPA plugins...")
  507. for iPATH in Carla.LADSPA_PATH:
  508. binaries = findBinaries(iPATH, OS)
  509. for binary in binaries:
  510. if binary not in ladspaBinaries:
  511. ladspaBinaries.append(binary)
  512. ladspaBinaries.sort()
  513. if not self.fContinueChecking: return
  514. for i in range(len(ladspaBinaries)):
  515. ladspa = ladspaBinaries[i]
  516. percent = ( float(i) / len(ladspaBinaries) ) * self.fCurPercentValue
  517. self._pluginLook((self.fLastCheckValue + percent) * 0.9, ladspa)
  518. plugins = checkPluginLADSPA(ladspa, tool, isWine)
  519. if plugins:
  520. self.fLadspaPlugins.append(plugins)
  521. self.fSomethingChanged = True
  522. if not self.fContinueChecking: break
  523. self.fLastCheckValue += self.fCurPercentValue
  524. def _checkDSSI(self, OS, tool, isWine=False):
  525. dssiBinaries = []
  526. self.fDssiPlugins = []
  527. self._pluginLook(self.fLastCheckValue, "DSSI plugins...")
  528. for iPATH in Carla.DSSI_PATH:
  529. binaries = findBinaries(iPATH, OS)
  530. for binary in binaries:
  531. if binary not in dssiBinaries:
  532. dssiBinaries.append(binary)
  533. dssiBinaries.sort()
  534. if not self.fContinueChecking: return
  535. for i in range(len(dssiBinaries)):
  536. dssi = dssiBinaries[i]
  537. percent = ( float(i) / len(dssiBinaries) ) * self.fCurPercentValue
  538. self._pluginLook(self.fLastCheckValue + percent, dssi)
  539. plugins = checkPluginDSSI(dssi, tool, isWine)
  540. if plugins:
  541. self.fDssiPlugins.append(plugins)
  542. self.fSomethingChanged = True
  543. if not self.fContinueChecking: break
  544. self.fLastCheckValue += self.fCurPercentValue
  545. def _checkLV2(self, tool, isWine=False):
  546. lv2Bundles = []
  547. self.fLv2Plugins = []
  548. self._pluginLook(self.fLastCheckValue, "LV2 bundles...")
  549. for iPATH in Carla.LV2_PATH:
  550. bundles = findLV2Bundles(iPATH)
  551. for bundle in bundles:
  552. if bundle not in lv2Bundles:
  553. lv2Bundles.append(bundle)
  554. lv2Bundles.sort()
  555. if not self.fContinueChecking: return
  556. for i in range(len(lv2Bundles)):
  557. lv2 = lv2Bundles[i]
  558. percent = ( float(i) / len(lv2Bundles) ) * self.fCurPercentValue
  559. self._pluginLook(self.fLastCheckValue + percent, lv2)
  560. plugins = checkPluginLV2(lv2, tool, isWine)
  561. if plugins:
  562. self.fLv2Plugins.append(plugins)
  563. self.fSomethingChanged = True
  564. if not self.fContinueChecking: break
  565. self.fLastCheckValue += self.fCurPercentValue
  566. def _checkVST(self, OS, tool, isWine=False):
  567. vstBinaries = []
  568. self.fVstPlugins = []
  569. if MACOS and not isWine:
  570. self._pluginLook(self.fLastCheckValue, "VST bundles...")
  571. else:
  572. self._pluginLook(self.fLastCheckValue, "VST plugins...")
  573. for iPATH in Carla.VST_PATH:
  574. if MACOS and not isWine:
  575. binaries = findMacVSTBundles(iPATH)
  576. else:
  577. binaries = findBinaries(iPATH, OS)
  578. for binary in binaries:
  579. if binary not in vstBinaries:
  580. vstBinaries.append(binary)
  581. vstBinaries.sort()
  582. if not self.fContinueChecking: return
  583. for i in range(len(vstBinaries)):
  584. vst = vstBinaries[i]
  585. percent = ( float(i) / len(vstBinaries) ) * self.fCurPercentValue
  586. self._pluginLook(self.fLastCheckValue + percent, vst)
  587. plugins = checkPluginVST(vst, tool, isWine)
  588. if plugins:
  589. self.fVstPlugins.append(plugins)
  590. self.fSomethingChanged = True
  591. if not self.fContinueChecking: break
  592. self.fLastCheckValue += self.fCurPercentValue
  593. def _checkAU(self, tool):
  594. auBinaries = []
  595. self.fAuPlugins = []
  596. # FIXME - this probably uses bundles
  597. self._pluginLook(self.fLastCheckValue, "AU plugins...")
  598. for iPATH in Carla.AU_PATH:
  599. binaries = findBinaries(iPATH, "MACOS")
  600. for binary in binaries:
  601. if binary not in auBinaries:
  602. auBinaries.append(binary)
  603. auBinaries.sort()
  604. if not self.fContinueChecking: return
  605. for i in range(len(auBinaries)):
  606. au = auBinaries[i]
  607. percent = ( float(i) / len(auBinaries) ) * self.fCurPercentValue
  608. self._pluginLook(self.fLastCheckValue + percent, au)
  609. plugins = checkPluginAU(au, tool)
  610. if plugins:
  611. self.fAuPlugins.append(plugins)
  612. self.fSomethingChanged = True
  613. if not self.fContinueChecking: break
  614. self.fLastCheckValue += self.fCurPercentValue
  615. def _checkCSOUND(self):
  616. csoundFiles = []
  617. self.fCsoundPlugins = []
  618. for iPATH in Carla.CSOUND_PATH:
  619. files = findFilenames(iPATH, "csd")
  620. for file_ in files:
  621. if file_ not in csoundFiles:
  622. csoundFiles.append(file_)
  623. csoundFiles.sort()
  624. if not self.fContinueChecking: return
  625. for i in range(len(csoundFiles)):
  626. csd = csoundFiles[i]
  627. percent = ( float(i) / len(csoundFiles) ) * self.fCurPercentValue
  628. self._pluginLook(self.fLastCheckValue + percent, csd)
  629. plugins = checkPluginCSOUND(csd, self.fToolNative)
  630. if plugins:
  631. self.fCsoundPlugins.append(plugins)
  632. self.fSomethingChanged = True
  633. if not self.fContinueChecking: break
  634. self.fLastCheckValue += self.fCurPercentValue
  635. def _checkKIT(self, kitPATH, kitExtension):
  636. kitFiles = []
  637. self.fKitPlugins = []
  638. for iPATH in kitPATH:
  639. files = findFilenames(iPATH, kitExtension)
  640. for file_ in files:
  641. if file_ not in kitFiles:
  642. kitFiles.append(file_)
  643. kitFiles.sort()
  644. if not self.fContinueChecking: return
  645. for i in range(len(kitFiles)):
  646. kit = kitFiles[i]
  647. percent = ( float(i) / len(kitFiles) ) * self.fCurPercentValue
  648. self._pluginLook(self.fLastCheckValue + percent, kit)
  649. if kitExtension == "gig":
  650. plugins = checkPluginGIG(kit, self.fToolNative)
  651. elif kitExtension == "sf2":
  652. plugins = checkPluginSF2(kit, self.fToolNative)
  653. elif kitExtension == "sfz":
  654. plugins = checkPluginSFZ(kit, self.fToolNative)
  655. else:
  656. plugins = None
  657. if plugins:
  658. self.fKitPlugins.append(plugins)
  659. self.fSomethingChanged = True
  660. if not self.fContinueChecking: break
  661. self.fLastCheckValue += self.fCurPercentValue
  662. def _pluginLook(self, percent, plugin):
  663. self.pluginLook.emit(percent, plugin)
  664. # ------------------------------------------------------------------------------------------------------------
  665. # Plugin Refresh Dialog
  666. class PluginRefreshW(QDialog):
  667. def __init__(self, parent):
  668. QDialog.__init__(self, parent)
  669. self.ui = ui_carla_refresh.Ui_PluginRefreshW()
  670. self.ui.setupUi(self)
  671. # -------------------------------------------------------------
  672. # Internal stuff
  673. self.fThread = SearchPluginsThread(self)
  674. # -------------------------------------------------------------
  675. # Load settings
  676. self.loadSettings()
  677. # -------------------------------------------------------------
  678. # Set-up GUI
  679. self.fIconYes = getIcon("dialog-ok-apply").pixmap(16, 16)
  680. self.fIconNo = getIcon("dialog-error").pixmap(16, 16)
  681. self.ui.b_skip.setVisible(False)
  682. if HAIKU:
  683. self.ui.ch_posix32.setText("Haiku 32bit")
  684. self.ui.ch_posix64.setText("Haiku 64bit")
  685. elif LINUX:
  686. self.ui.ch_posix32.setText("Linux 32bit")
  687. self.ui.ch_posix64.setText("Linux 64bit")
  688. elif MACOS:
  689. self.ui.ch_posix32.setText("MacOS 32bit")
  690. self.ui.ch_posix64.setText("MacOS 64bit")
  691. if carla_discovery_posix32 and not WINDOWS:
  692. self.ui.ico_posix32.setPixmap(self.fIconYes)
  693. else:
  694. self.ui.ico_posix32.setPixmap(self.fIconNo)
  695. self.ui.ch_posix32.setChecked(False)
  696. self.ui.ch_posix32.setEnabled(False)
  697. if carla_discovery_posix64 and not WINDOWS:
  698. self.ui.ico_posix64.setPixmap(self.fIconYes)
  699. else:
  700. self.ui.ico_posix64.setPixmap(self.fIconNo)
  701. self.ui.ch_posix64.setChecked(False)
  702. self.ui.ch_posix64.setEnabled(False)
  703. if carla_discovery_win32:
  704. self.ui.ico_win32.setPixmap(self.fIconYes)
  705. else:
  706. self.ui.ico_win32.setPixmap(self.fIconNo)
  707. self.ui.ch_win32.setChecked(False)
  708. self.ui.ch_win32.setEnabled(False)
  709. if carla_discovery_win64:
  710. self.ui.ico_win64.setPixmap(self.fIconYes)
  711. else:
  712. self.ui.ico_win64.setPixmap(self.fIconNo)
  713. self.ui.ch_win64.setChecked(False)
  714. self.ui.ch_win64.setEnabled(False)
  715. if haveLRDF:
  716. self.ui.ico_rdflib.setPixmap(self.fIconYes)
  717. else:
  718. self.ui.ico_rdflib.setPixmap(self.fIconNo)
  719. hasNative = bool(carla_discovery_native)
  720. hasNonNative = False
  721. if WINDOWS:
  722. if kIs64bit:
  723. hasNative = bool(carla_discovery_win64)
  724. hasNonNative = bool(carla_discovery_win32)
  725. self.fThread.setSearchToolNative(carla_discovery_win64)
  726. self.ui.ch_win64.setChecked(False)
  727. self.ui.ch_win64.setVisible(False)
  728. self.ui.ico_win64.setVisible(False)
  729. self.ui.label_win64.setVisible(False)
  730. else:
  731. hasNative = bool(carla_discovery_win32)
  732. hasNonNative = bool(carla_discovery_win64)
  733. self.fThread.setSearchToolNative(carla_discovery_win32)
  734. self.ui.ch_win32.setChecked(False)
  735. self.ui.ch_win32.setVisible(False)
  736. self.ui.ico_win32.setVisible(False)
  737. self.ui.label_win32.setVisible(False)
  738. elif LINUX or MACOS:
  739. if kIs64bit:
  740. hasNonNative = bool(carla_discovery_posix32 or carla_discovery_win32 or carla_discovery_win64)
  741. self.ui.ch_posix64.setChecked(False)
  742. self.ui.ch_posix64.setVisible(False)
  743. self.ui.ico_posix64.setVisible(False)
  744. self.ui.label_posix64.setVisible(False)
  745. else:
  746. hasNonNative = bool(carla_discovery_posix64 or carla_discovery_win32 or carla_discovery_win64)
  747. self.ui.ch_posix32.setChecked(False)
  748. self.ui.ch_posix32.setVisible(False)
  749. self.ui.ico_posix32.setVisible(False)
  750. self.ui.label_posix32.setVisible(False)
  751. if hasNative:
  752. self.ui.ico_native.setPixmap(self.fIconYes)
  753. else:
  754. self.ui.ico_native.setPixmap(self.fIconNo)
  755. self.ui.ch_native.setChecked(False)
  756. self.ui.ch_native.setEnabled(False)
  757. self.ui.ch_csound.setChecked(False)
  758. self.ui.ch_csound.setEnabled(False)
  759. self.ui.ch_gig.setChecked(False)
  760. self.ui.ch_gig.setEnabled(False)
  761. self.ui.ch_sf2.setChecked(False)
  762. self.ui.ch_sf2.setEnabled(False)
  763. self.ui.ch_sfz.setChecked(False)
  764. self.ui.ch_sfz.setEnabled(False)
  765. if not hasNonNative:
  766. self.ui.ch_ladspa.setChecked(False)
  767. self.ui.ch_ladspa.setEnabled(False)
  768. self.ui.ch_dssi.setChecked(False)
  769. self.ui.ch_dssi.setEnabled(False)
  770. self.ui.ch_lv2.setChecked(False)
  771. self.ui.ch_lv2.setEnabled(False)
  772. self.ui.ch_vst.setChecked(False)
  773. self.ui.ch_vst.setEnabled(False)
  774. self.ui.ch_au.setChecked(False)
  775. self.ui.ch_au.setEnabled(False)
  776. self.ui.b_start.setEnabled(False)
  777. if not MACOS:
  778. self.ui.ch_au.setChecked(False)
  779. self.ui.ch_au.setEnabled(False)
  780. self.ui.ch_au.setVisible(False)
  781. # -------------------------------------------------------------
  782. # Set-up connections
  783. self.ui.b_start.clicked.connect(self.slot_start)
  784. self.ui.b_skip.clicked.connect(self.slot_skip)
  785. self.ui.ch_native.clicked.connect(self.slot_checkTools)
  786. self.ui.ch_posix32.clicked.connect(self.slot_checkTools)
  787. self.ui.ch_posix64.clicked.connect(self.slot_checkTools)
  788. self.ui.ch_win32.clicked.connect(self.slot_checkTools)
  789. self.ui.ch_win64.clicked.connect(self.slot_checkTools)
  790. self.ui.ch_ladspa.clicked.connect(self.slot_checkTools)
  791. self.ui.ch_dssi.clicked.connect(self.slot_checkTools)
  792. self.ui.ch_lv2.clicked.connect(self.slot_checkTools)
  793. self.ui.ch_vst.clicked.connect(self.slot_checkTools)
  794. self.ui.ch_au.clicked.connect(self.slot_checkTools)
  795. self.ui.ch_csound.clicked.connect(self.slot_checkTools)
  796. self.ui.ch_gig.clicked.connect(self.slot_checkTools)
  797. self.ui.ch_sf2.clicked.connect(self.slot_checkTools)
  798. self.ui.ch_sfz.clicked.connect(self.slot_checkTools)
  799. self.fThread.pluginLook.connect(self.slot_handlePluginLook)
  800. self.fThread.finished.connect(self.slot_handlePluginThreadFinished)
  801. @pyqtSlot()
  802. def slot_start(self):
  803. self.ui.progressBar.setMinimum(0)
  804. self.ui.progressBar.setMaximum(100)
  805. self.ui.progressBar.setValue(0)
  806. self.ui.b_start.setEnabled(False)
  807. self.ui.b_skip.setVisible(True)
  808. self.ui.b_close.setVisible(False)
  809. native, posix32, posix64, win32, win64 = (self.ui.ch_native.isChecked(),
  810. self.ui.ch_posix32.isChecked(), self.ui.ch_posix64.isChecked(),
  811. self.ui.ch_win32.isChecked(), self.ui.ch_win64.isChecked())
  812. ladspa, dssi, lv2, vst, au, csound, gig, sf2, sfz = (self.ui.ch_ladspa.isChecked(), self.ui.ch_dssi.isChecked(),
  813. self.ui.ch_lv2.isChecked(), self.ui.ch_vst.isChecked(),
  814. self.ui.ch_au.isChecked(), self.ui.ch_csound.isChecked(),
  815. self.ui.ch_gig.isChecked(), self.ui.ch_sf2.isChecked(), self.ui.ch_sfz.isChecked())
  816. self.fThread.setSearchBinaryTypes(native, posix32, posix64, win32, win64)
  817. self.fThread.setSearchPluginTypes(ladspa, dssi, lv2, vst, au, csound, gig, sf2, sfz)
  818. self.fThread.start()
  819. @pyqtSlot()
  820. def slot_skip(self):
  821. killDiscovery()
  822. @pyqtSlot()
  823. def slot_checkTools(self):
  824. enabled1 = bool(self.ui.ch_native.isChecked() or self.ui.ch_posix32.isChecked() or self.ui.ch_posix64.isChecked() or self.ui.ch_win32.isChecked() or self.ui.ch_win64.isChecked())
  825. enabled2 = bool(self.ui.ch_ladspa.isChecked() or self.ui.ch_dssi.isChecked() or self.ui.ch_lv2.isChecked() or self.ui.ch_vst.isChecked() or self.ui.ch_au.isChecked() or
  826. self.ui.ch_csound.isChecked() or self.ui.ch_gig.isChecked() or self.ui.ch_sf2.isChecked() or self.ui.ch_sfz.isChecked())
  827. self.ui.b_start.setEnabled(enabled1 and enabled2)
  828. @pyqtSlot(int, str)
  829. def slot_handlePluginLook(self, percent, plugin):
  830. self.ui.progressBar.setFormat("%s" % plugin)
  831. self.ui.progressBar.setValue(percent)
  832. @pyqtSlot()
  833. def slot_handlePluginThreadFinished(self):
  834. self.ui.progressBar.setMinimum(0)
  835. self.ui.progressBar.setMaximum(1)
  836. self.ui.progressBar.setValue(1)
  837. self.ui.progressBar.setFormat(self.tr("Done"))
  838. self.ui.b_start.setEnabled(True)
  839. self.ui.b_skip.setVisible(False)
  840. self.ui.b_close.setVisible(True)
  841. def loadSettings(self):
  842. settings = QSettings()
  843. self.ui.ch_ladspa.setChecked(settings.value("PluginDatabase/SearchLADSPA", True, type=bool))
  844. self.ui.ch_dssi.setChecked(settings.value("PluginDatabase/SearchDSSI", True, type=bool))
  845. self.ui.ch_lv2.setChecked(settings.value("PluginDatabase/SearchLV2", True, type=bool))
  846. self.ui.ch_vst.setChecked(settings.value("PluginDatabase/SearchVST", True, type=bool))
  847. self.ui.ch_au.setChecked(settings.value("PluginDatabase/SearchAU", True, type=bool))
  848. self.ui.ch_csound.setChecked(settings.value("PluginDatabase/SearchCSOUND", False, type=bool))
  849. self.ui.ch_gig.setChecked(settings.value("PluginDatabase/SearchGIG", False, type=bool))
  850. self.ui.ch_sf2.setChecked(settings.value("PluginDatabase/SearchSF2", False, type=bool))
  851. self.ui.ch_sfz.setChecked(settings.value("PluginDatabase/SearchSFZ", False, type=bool))
  852. self.ui.ch_native.setChecked(settings.value("PluginDatabase/SearchNative", True, type=bool))
  853. self.ui.ch_posix32.setChecked(settings.value("PluginDatabase/SearchPOSIX32", False, type=bool))
  854. self.ui.ch_posix64.setChecked(settings.value("PluginDatabase/SearchPOSIX64", False, type=bool))
  855. self.ui.ch_win32.setChecked(settings.value("PluginDatabase/SearchWin32", False, type=bool))
  856. self.ui.ch_win64.setChecked(settings.value("PluginDatabase/SearchWin64", False, type=bool))
  857. def saveSettings(self):
  858. settings = QSettings()
  859. settings.setValue("PluginDatabase/SearchLADSPA", self.ui.ch_ladspa.isChecked())
  860. settings.setValue("PluginDatabase/SearchDSSI", self.ui.ch_dssi.isChecked())
  861. settings.setValue("PluginDatabase/SearchLV2", self.ui.ch_lv2.isChecked())
  862. settings.setValue("PluginDatabase/SearchVST", self.ui.ch_vst.isChecked())
  863. settings.setValue("PluginDatabase/SearchAU", self.ui.ch_au.isChecked())
  864. settings.setValue("PluginDatabase/SearchCSOUND", self.ui.ch_csound.isChecked())
  865. settings.setValue("PluginDatabase/SearchGIG", self.ui.ch_gig.isChecked())
  866. settings.setValue("PluginDatabase/SearchSF2", self.ui.ch_sf2.isChecked())
  867. settings.setValue("PluginDatabase/SearchSFZ", self.ui.ch_sfz.isChecked())
  868. settings.setValue("PluginDatabase/SearchNative", self.ui.ch_native.isChecked())
  869. settings.setValue("PluginDatabase/SearchPOSIX32", self.ui.ch_posix32.isChecked())
  870. settings.setValue("PluginDatabase/SearchPOSIX64", self.ui.ch_posix64.isChecked())
  871. settings.setValue("PluginDatabase/SearchWin32", self.ui.ch_win32.isChecked())
  872. settings.setValue("PluginDatabase/SearchWin64", self.ui.ch_win64.isChecked())
  873. def closeEvent(self, event):
  874. self.saveSettings()
  875. if self.fThread.isRunning():
  876. self.fThread.stop()
  877. killDiscovery()
  878. #self.fThread.terminate()
  879. self.fThread.wait()
  880. if self.fThread.hasSomethingChanged():
  881. self.accept()
  882. else:
  883. self.reject()
  884. QDialog.closeEvent(self, event)
  885. def done(self, r):
  886. QDialog.done(self, r)
  887. self.close()
  888. # ------------------------------------------------------------------------------------------------------------
  889. # Plugin Database Dialog
  890. class PluginDatabaseW(QDialog):
  891. def __init__(self, parent):
  892. QDialog.__init__(self, parent)
  893. self.ui = ui_carla_database.Ui_PluginDatabaseW()
  894. self.ui.setupUi(self)
  895. # -------------------------------------------------------------
  896. # Internal stuff
  897. self.fLastTableIndex = 0
  898. self.fRetPlugin = None
  899. self.fRealParent = parent
  900. # -------------------------------------------------------------
  901. # Load settings
  902. self.loadSettings()
  903. # -------------------------------------------------------------
  904. # Set-up GUI
  905. self.ui.b_add.setEnabled(False)
  906. if BINARY_NATIVE in (BINARY_POSIX32, BINARY_WIN32):
  907. self.ui.ch_bridged.setText(self.tr("Bridged (64bit)"))
  908. else:
  909. self.ui.ch_bridged.setText(self.tr("Bridged (32bit)"))
  910. if not (LINUX or MACOS):
  911. self.ui.ch_bridged_wine.setChecked(False)
  912. self.ui.ch_bridged_wine.setEnabled(False)
  913. # -------------------------------------------------------------
  914. # Set-up connections
  915. self.ui.b_add.clicked.connect(self.slot_addPlugin)
  916. self.ui.b_refresh.clicked.connect(self.slot_refreshPlugins)
  917. self.ui.tb_filters.clicked.connect(self.slot_maybeShowFilters)
  918. self.ui.lineEdit.textChanged.connect(self.slot_checkFilters)
  919. self.ui.tableWidget.currentCellChanged.connect(self.slot_checkPlugin)
  920. self.ui.tableWidget.cellDoubleClicked.connect(self.slot_addPlugin)
  921. self.ui.ch_effects.clicked.connect(self.slot_checkFilters)
  922. self.ui.ch_instruments.clicked.connect(self.slot_checkFilters)
  923. self.ui.ch_midi.clicked.connect(self.slot_checkFilters)
  924. self.ui.ch_other.clicked.connect(self.slot_checkFilters)
  925. self.ui.ch_internal.clicked.connect(self.slot_checkFilters)
  926. self.ui.ch_ladspa.clicked.connect(self.slot_checkFilters)
  927. self.ui.ch_dssi.clicked.connect(self.slot_checkFilters)
  928. self.ui.ch_lv2.clicked.connect(self.slot_checkFilters)
  929. self.ui.ch_vst.clicked.connect(self.slot_checkFilters)
  930. self.ui.ch_au.clicked.connect(self.slot_checkFilters)
  931. self.ui.ch_csound.clicked.connect(self.slot_checkFilters)
  932. self.ui.ch_kits.clicked.connect(self.slot_checkFilters)
  933. self.ui.ch_native.clicked.connect(self.slot_checkFilters)
  934. self.ui.ch_bridged.clicked.connect(self.slot_checkFilters)
  935. self.ui.ch_bridged_wine.clicked.connect(self.slot_checkFilters)
  936. self.ui.ch_rtsafe.clicked.connect(self.slot_checkFilters)
  937. self.ui.ch_gui.clicked.connect(self.slot_checkFilters)
  938. self.ui.ch_stereo.clicked.connect(self.slot_checkFilters)
  939. # -------------------------------------------------------------
  940. @pyqtSlot()
  941. def slot_addPlugin(self):
  942. if self.ui.tableWidget.currentRow() >= 0:
  943. self.fRetPlugin = self.ui.tableWidget.item(self.ui.tableWidget.currentRow(), 0).data(Qt.UserRole)
  944. self.accept()
  945. else:
  946. self.reject()
  947. @pyqtSlot(int)
  948. def slot_checkPlugin(self, row):
  949. self.ui.b_add.setEnabled(row >= 0)
  950. @pyqtSlot()
  951. def slot_checkFilters(self):
  952. self._checkFilters()
  953. @pyqtSlot()
  954. def slot_maybeShowFilters(self):
  955. self._showFilters(not self.ui.frame.isVisible())
  956. @pyqtSlot()
  957. def slot_refreshPlugins(self):
  958. if PluginRefreshW(self).exec_():
  959. self._reAddPlugins()
  960. if self.fRealParent:
  961. self.fRealParent.loadRDFsNeeded()
  962. def _checkFilters(self):
  963. text = self.ui.lineEdit.text().lower()
  964. hideEffects = not self.ui.ch_effects.isChecked()
  965. hideInstruments = not self.ui.ch_instruments.isChecked()
  966. hideMidi = not self.ui.ch_midi.isChecked()
  967. hideOther = not self.ui.ch_other.isChecked()
  968. hideInternal = not self.ui.ch_internal.isChecked()
  969. hideLadspa = not self.ui.ch_ladspa.isChecked()
  970. hideDssi = not self.ui.ch_dssi.isChecked()
  971. hideLV2 = not self.ui.ch_lv2.isChecked()
  972. hideVST = not self.ui.ch_vst.isChecked()
  973. hideAU = not self.ui.ch_au.isChecked()
  974. hideCsound = not self.ui.ch_csound.isChecked()
  975. hideKits = not self.ui.ch_kits.isChecked()
  976. hideNative = not self.ui.ch_native.isChecked()
  977. hideBridged = not self.ui.ch_bridged.isChecked()
  978. hideBridgedWine = not self.ui.ch_bridged_wine.isChecked()
  979. hideNonRtSafe = self.ui.ch_rtsafe.isChecked()
  980. hideNonGui = self.ui.ch_gui.isChecked()
  981. hideNonStereo = self.ui.ch_stereo.isChecked()
  982. if HAIKU or LINUX or MACOS:
  983. nativeBins = [BINARY_POSIX32, BINARY_POSIX64]
  984. wineBins = [BINARY_WIN32, BINARY_WIN64]
  985. elif WINDOWS:
  986. nativeBins = [BINARY_WIN32, BINARY_WIN64]
  987. wineBins = []
  988. else:
  989. nativeBins = []
  990. wineBins = []
  991. rowCount = self.ui.tableWidget.rowCount()
  992. for i in range(rowCount):
  993. self.ui.tableWidget.showRow(i)
  994. plugin = self.ui.tableWidget.item(i, 0).data(Qt.UserRole)
  995. aIns = plugin['audio.ins']
  996. aOuts = plugin['audio.outs']
  997. mIns = plugin['midi.ins']
  998. mOuts = plugin['midi.outs']
  999. ptype = self.ui.tableWidget.item(i, 12).text()
  1000. isSynth = bool(plugin['hints'] & PLUGIN_IS_SYNTH)
  1001. isEffect = bool(aIns > 0 < aOuts and not isSynth)
  1002. isMidi = bool(aIns == 0 and aOuts == 0 and mIns > 0 < mOuts)
  1003. isKit = bool(ptype in ("GIG", "SF2", "SFZ"))
  1004. isOther = bool(not (isEffect or isSynth or isMidi or isKit))
  1005. isNative = bool(plugin['build'] == BINARY_NATIVE)
  1006. isRtSafe = bool(plugin['hints'] & PLUGIN_IS_RTSAFE)
  1007. isStereo = bool(aIns == 2 and aOuts == 2) or (isSynth and aOuts == 2)
  1008. hasGui = bool(plugin['hints'] & PLUGIN_HAS_GUI)
  1009. isBridged = bool(not isNative and plugin['build'] in nativeBins)
  1010. isBridgedWine = bool(not isNative and plugin['build'] in wineBins)
  1011. if hideEffects and isEffect:
  1012. self.ui.tableWidget.hideRow(i)
  1013. elif hideInstruments and isSynth:
  1014. self.ui.tableWidget.hideRow(i)
  1015. elif hideMidi and isMidi:
  1016. self.ui.tableWidget.hideRow(i)
  1017. elif hideOther and isOther:
  1018. self.ui.tableWidget.hideRow(i)
  1019. elif hideKits and isKit:
  1020. self.ui.tableWidget.hideRow(i)
  1021. elif hideInternal and ptype == self.tr("Internal"):
  1022. self.ui.tableWidget.hideRow(i)
  1023. elif hideLadspa and ptype == "LADSPA":
  1024. self.ui.tableWidget.hideRow(i)
  1025. elif hideDssi and ptype == "DSSI":
  1026. self.ui.tableWidget.hideRow(i)
  1027. elif hideLV2 and ptype == "LV2":
  1028. self.ui.tableWidget.hideRow(i)
  1029. elif hideVST and ptype == "VST":
  1030. self.ui.tableWidget.hideRow(i)
  1031. elif hideAU and ptype == "AU":
  1032. self.ui.tableWidget.hideRow(i)
  1033. elif hideCsound and ptype == "CSOUND":
  1034. self.ui.tableWidget.hideRow(i)
  1035. elif hideNative and isNative:
  1036. self.ui.tableWidget.hideRow(i)
  1037. elif hideBridged and isBridged:
  1038. self.ui.tableWidget.hideRow(i)
  1039. elif hideBridgedWine and isBridgedWine:
  1040. self.ui.tableWidget.hideRow(i)
  1041. elif hideNonRtSafe and not isRtSafe:
  1042. self.ui.tableWidget.hideRow(i)
  1043. elif hideNonGui and not hasGui:
  1044. self.ui.tableWidget.hideRow(i)
  1045. elif hideNonStereo and not isStereo:
  1046. self.ui.tableWidget.hideRow(i)
  1047. elif (text and not (
  1048. text in self.ui.tableWidget.item(i, 0).text().lower() or
  1049. text in self.ui.tableWidget.item(i, 1).text().lower() or
  1050. text in self.ui.tableWidget.item(i, 2).text().lower() or
  1051. text in self.ui.tableWidget.item(i, 3).text().lower() or
  1052. text in self.ui.tableWidget.item(i, 13).text().lower())):
  1053. self.ui.tableWidget.hideRow(i)
  1054. def _showFilters(self, yesNo):
  1055. self.ui.tb_filters.setArrowType(Qt.UpArrow if yesNo else Qt.DownArrow)
  1056. self.ui.frame.setVisible(yesNo)
  1057. def _addPluginToTable(self, plugin, ptype):
  1058. index = self.fLastTableIndex
  1059. if plugin['build'] == BINARY_NATIVE:
  1060. bridgeText = self.tr("No")
  1061. else:
  1062. if LINUX or MACOS:
  1063. if plugin['build'] == BINARY_WIN32:
  1064. typeText = "32bit"
  1065. elif plugin['build'] == BINARY_WIN64:
  1066. typeText = "64bit"
  1067. else:
  1068. typeText = self.tr("Unknown")
  1069. else:
  1070. if plugin['build'] == BINARY_POSIX32:
  1071. typeText = "32bit"
  1072. elif plugin['build'] == BINARY_POSIX64:
  1073. typeText = "64bit"
  1074. elif plugin['build'] == BINARY_WIN32:
  1075. typeText = "Windows 32bit"
  1076. elif plugin['build'] == BINARY_WIN64:
  1077. typeText = "Windows 64bit"
  1078. else:
  1079. typeText = self.tr("Unknown")
  1080. bridgeText = self.tr("Yes (%s)" % typeText)
  1081. self.ui.tableWidget.insertRow(index)
  1082. self.ui.tableWidget.setItem(index, 0, QTableWidgetItem(str(plugin['name'])))
  1083. self.ui.tableWidget.setItem(index, 1, QTableWidgetItem(str(plugin['label'])))
  1084. self.ui.tableWidget.setItem(index, 2, QTableWidgetItem(str(plugin['maker'])))
  1085. self.ui.tableWidget.setItem(index, 3, QTableWidgetItem(str(plugin['uniqueId'])))
  1086. self.ui.tableWidget.setItem(index, 4, QTableWidgetItem(str(plugin['audio.ins'])))
  1087. self.ui.tableWidget.setItem(index, 5, QTableWidgetItem(str(plugin['audio.outs'])))
  1088. self.ui.tableWidget.setItem(index, 6, QTableWidgetItem(str(plugin['parameters.ins'])))
  1089. self.ui.tableWidget.setItem(index, 7, QTableWidgetItem(str(plugin['parameters.outs'])))
  1090. self.ui.tableWidget.setItem(index, 8, QTableWidgetItem(str(plugin['programs.total'])))
  1091. self.ui.tableWidget.setItem(index, 9, QTableWidgetItem(self.tr("Yes") if (plugin['hints'] & PLUGIN_HAS_GUI) else self.tr("No")))
  1092. self.ui.tableWidget.setItem(index, 10, QTableWidgetItem(self.tr("Yes") if (plugin['hints'] & PLUGIN_IS_SYNTH) else self.tr("No")))
  1093. self.ui.tableWidget.setItem(index, 11, QTableWidgetItem(bridgeText))
  1094. self.ui.tableWidget.setItem(index, 12, QTableWidgetItem(ptype))
  1095. self.ui.tableWidget.setItem(index, 13, QTableWidgetItem(str(plugin['binary'])))
  1096. self.ui.tableWidget.item(index, 0).setData(Qt.UserRole, plugin)
  1097. self.fLastTableIndex += 1
  1098. def _reAddPlugins(self):
  1099. settingsDB = QSettings("falkTX", "CarlaPlugins")
  1100. for x in range(self.ui.tableWidget.rowCount()):
  1101. self.ui.tableWidget.removeRow(0)
  1102. self.fLastTableIndex = 0
  1103. self.ui.tableWidget.setSortingEnabled(False)
  1104. internalCount = 0
  1105. ladspaCount = 0
  1106. dssiCount = 0
  1107. lv2Count = 0
  1108. vstCount = 0
  1109. auCount = 0
  1110. csoundCount = 0
  1111. kitCount = 0
  1112. # ---------------------------------------------------------------------------
  1113. # Internal
  1114. internalPlugins = toList(settingsDB.value("Plugins/Internal", []))
  1115. for plugins in internalPlugins:
  1116. for plugin in plugins:
  1117. internalCount += 1
  1118. if (not Carla.isControl) and internalCount != Carla.host.get_internal_plugin_count():
  1119. internalCount = Carla.host.get_internal_plugin_count()
  1120. internalPlugins = []
  1121. for i in range(Carla.host.get_internal_plugin_count()):
  1122. descInfo = Carla.host.get_internal_plugin_info(i)
  1123. plugins = checkPluginInternal(descInfo)
  1124. if plugins:
  1125. internalPlugins.append(plugins)
  1126. settingsDB.setValue("Plugins/Internal", internalPlugins)
  1127. for plugins in internalPlugins:
  1128. for plugin in plugins:
  1129. self._addPluginToTable(plugin, self.tr("Internal"))
  1130. # ---------------------------------------------------------------------------
  1131. # LADSPA
  1132. ladspaPlugins = []
  1133. ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_native", []))
  1134. ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_posix32", []))
  1135. ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_posix64", []))
  1136. ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_win32", []))
  1137. ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_win64", []))
  1138. for plugins in ladspaPlugins:
  1139. for plugin in plugins:
  1140. self._addPluginToTable(plugin, "LADSPA")
  1141. ladspaCount += 1
  1142. # ---------------------------------------------------------------------------
  1143. # DSSI
  1144. dssiPlugins = []
  1145. dssiPlugins += toList(settingsDB.value("Plugins/DSSI_native", []))
  1146. dssiPlugins += toList(settingsDB.value("Plugins/DSSI_posix32", []))
  1147. dssiPlugins += toList(settingsDB.value("Plugins/DSSI_posix64", []))
  1148. dssiPlugins += toList(settingsDB.value("Plugins/DSSI_win32", []))
  1149. dssiPlugins += toList(settingsDB.value("Plugins/DSSI_win64", []))
  1150. for plugins in dssiPlugins:
  1151. for plugin in plugins:
  1152. self._addPluginToTable(plugin, "DSSI")
  1153. dssiCount += 1
  1154. # ---------------------------------------------------------------------------
  1155. # LV2
  1156. lv2Plugins = []
  1157. lv2Plugins += toList(settingsDB.value("Plugins/LV2_native", []))
  1158. lv2Plugins += toList(settingsDB.value("Plugins/LV2_posix32", []))
  1159. lv2Plugins += toList(settingsDB.value("Plugins/LV2_posix64", []))
  1160. lv2Plugins += toList(settingsDB.value("Plugins/LV2_win32", []))
  1161. lv2Plugins += toList(settingsDB.value("Plugins/LV2_win64", []))
  1162. for plugins in lv2Plugins:
  1163. for plugin in plugins:
  1164. self._addPluginToTable(plugin, "LV2")
  1165. lv2Count += 1
  1166. # ---------------------------------------------------------------------------
  1167. # VST
  1168. vstPlugins = []
  1169. vstPlugins += toList(settingsDB.value("Plugins/VST_native", []))
  1170. vstPlugins += toList(settingsDB.value("Plugins/VST_posix32", []))
  1171. vstPlugins += toList(settingsDB.value("Plugins/VST_posix64", []))
  1172. vstPlugins += toList(settingsDB.value("Plugins/VST_win32", []))
  1173. vstPlugins += toList(settingsDB.value("Plugins/VST_win64", []))
  1174. for plugins in vstPlugins:
  1175. for plugin in plugins:
  1176. self._addPluginToTable(plugin, "VST")
  1177. vstCount += 1
  1178. # ---------------------------------------------------------------------------
  1179. # AU
  1180. if MACOS:
  1181. auPlugins = []
  1182. auPlugins += toList(settingsDB.value("Plugins/AU_native", []))
  1183. auPlugins += toList(settingsDB.value("Plugins/AU_posix32", []))
  1184. auPlugins += toList(settingsDB.value("Plugins/AU_posix64", []))
  1185. for plugins in auPlugins:
  1186. for plugin in plugins:
  1187. self._addPluginToTable(plugin, "AU")
  1188. auCount += 1
  1189. # ---------------------------------------------------------------------------
  1190. # Csound
  1191. csds = toList(settingsDB.value("Plugins/CSOUND", []))
  1192. for csd in csds:
  1193. for csd_i in csd:
  1194. self._addPluginToTable(csd_i, "CSOUND")
  1195. csoundCount += 1
  1196. # ---------------------------------------------------------------------------
  1197. # Kits
  1198. gigs = toList(settingsDB.value("Plugins/GIG", []))
  1199. sf2s = toList(settingsDB.value("Plugins/SF2", []))
  1200. sfzs = toList(settingsDB.value("Plugins/SFZ", []))
  1201. for gig in gigs:
  1202. for gig_i in gig:
  1203. self._addPluginToTable(gig_i, "GIG")
  1204. kitCount += 1
  1205. for sf2 in sf2s:
  1206. for sf2_i in sf2:
  1207. self._addPluginToTable(sf2_i, "SF2")
  1208. kitCount += 1
  1209. for sfz in sfzs:
  1210. for sfz_i in sfz:
  1211. self._addPluginToTable(sfz_i, "SFZ")
  1212. kitCount += 1
  1213. # ---------------------------------------------------------------------------
  1214. self.ui.tableWidget.setSortingEnabled(True)
  1215. self.ui.tableWidget.sortByColumn(0, Qt.AscendingOrder)
  1216. if MACOS:
  1217. self.ui.label.setText(self.tr("Have %i Internal, %i LADSPA, %i DSSI, %i LV2, %i VST and %i AudioUnit plugins, plus %i CSound modules and %i Sound Kits" % (
  1218. internalCount, ladspaCount, dssiCount, lv2Count, vstCount, auCount, csoundCount, kitCount)))
  1219. else:
  1220. self.ui.label.setText(self.tr("Have %i Internal, %i LADSPA, %i DSSI, %i LV2 and %i VST plugins, plus %i CSound modules and %i Sound Kits" % (
  1221. internalCount, ladspaCount, dssiCount, lv2Count, vstCount, csoundCount, kitCount)))
  1222. self._checkFilters()
  1223. def loadSettings(self):
  1224. settings = QSettings()
  1225. self.restoreGeometry(settings.value("PluginDatabase/Geometry", ""))
  1226. self.ui.tableWidget.horizontalHeader().restoreState(settings.value("PluginDatabase/TableGeometry", ""))
  1227. self.ui.ch_effects.setChecked(settings.value("PluginDatabase/ShowEffects", True, type=bool))
  1228. self.ui.ch_instruments.setChecked(settings.value("PluginDatabase/ShowInstruments", True, type=bool))
  1229. self.ui.ch_midi.setChecked(settings.value("PluginDatabase/ShowMIDI", True, type=bool))
  1230. self.ui.ch_other.setChecked(settings.value("PluginDatabase/ShowOther", True, type=bool))
  1231. self.ui.ch_internal.setChecked(settings.value("PluginDatabase/ShowInternal", True, type=bool))
  1232. self.ui.ch_ladspa.setChecked(settings.value("PluginDatabase/ShowLADSPA", True, type=bool))
  1233. self.ui.ch_dssi.setChecked(settings.value("PluginDatabase/ShowDSSI", True, type=bool))
  1234. self.ui.ch_lv2.setChecked(settings.value("PluginDatabase/ShowLV2", True, type=bool))
  1235. self.ui.ch_vst.setChecked(settings.value("PluginDatabase/ShowVST", True, type=bool))
  1236. self.ui.ch_au.setChecked(settings.value("PluginDatabase/ShowAU", True, type=bool))
  1237. self.ui.ch_csound.setChecked(settings.value("PluginDatabase/ShowCSOUND", True, type=bool))
  1238. self.ui.ch_kits.setChecked(settings.value("PluginDatabase/ShowKits", True, type=bool))
  1239. self.ui.ch_native.setChecked(settings.value("PluginDatabase/ShowNative", True, type=bool))
  1240. self.ui.ch_bridged.setChecked(settings.value("PluginDatabase/ShowBridged", True, type=bool))
  1241. self.ui.ch_bridged_wine.setChecked(settings.value("PluginDatabase/ShowBridgedWine", True, type=bool))
  1242. self.ui.ch_rtsafe.setChecked(settings.value("PluginDatabase/ShowRtSafe", False, type=bool))
  1243. self.ui.ch_gui.setChecked(settings.value("PluginDatabase/ShowHasGUI", False, type=bool))
  1244. self.ui.ch_stereo.setChecked(settings.value("PluginDatabase/ShowStereoOnly", False, type=bool))
  1245. self._showFilters(settings.value("PluginDatabase/ShowFilters", False, type=bool))
  1246. self._reAddPlugins()
  1247. def saveSettings(self):
  1248. settings = QSettings()
  1249. settings.setValue("PluginDatabase/Geometry", self.saveGeometry())
  1250. settings.setValue("PluginDatabase/TableGeometry", self.ui.tableWidget.horizontalHeader().saveState())
  1251. settings.setValue("PluginDatabase/ShowFilters", (self.ui.tb_filters.arrowType() == Qt.UpArrow))
  1252. settings.setValue("PluginDatabase/ShowEffects", self.ui.ch_effects.isChecked())
  1253. settings.setValue("PluginDatabase/ShowInstruments", self.ui.ch_instruments.isChecked())
  1254. settings.setValue("PluginDatabase/ShowMIDI", self.ui.ch_midi.isChecked())
  1255. settings.setValue("PluginDatabase/ShowOther", self.ui.ch_other.isChecked())
  1256. settings.setValue("PluginDatabase/ShowInternal", self.ui.ch_internal.isChecked())
  1257. settings.setValue("PluginDatabase/ShowLADSPA", self.ui.ch_ladspa.isChecked())
  1258. settings.setValue("PluginDatabase/ShowDSSI", self.ui.ch_dssi.isChecked())
  1259. settings.setValue("PluginDatabase/ShowLV2", self.ui.ch_lv2.isChecked())
  1260. settings.setValue("PluginDatabase/ShowVST", self.ui.ch_vst.isChecked())
  1261. settings.setValue("PluginDatabase/ShowAU", self.ui.ch_au.isChecked())
  1262. settings.setValue("PluginDatabase/ShowCSOUND", self.ui.ch_csound.isChecked())
  1263. settings.setValue("PluginDatabase/ShowKits", self.ui.ch_kits.isChecked())
  1264. settings.setValue("PluginDatabase/ShowNative", self.ui.ch_native.isChecked())
  1265. settings.setValue("PluginDatabase/ShowBridged", self.ui.ch_bridged.isChecked())
  1266. settings.setValue("PluginDatabase/ShowBridgedWine", self.ui.ch_bridged_wine.isChecked())
  1267. settings.setValue("PluginDatabase/ShowRtSafe", self.ui.ch_rtsafe.isChecked())
  1268. settings.setValue("PluginDatabase/ShowHasGUI", self.ui.ch_gui.isChecked())
  1269. settings.setValue("PluginDatabase/ShowStereoOnly", self.ui.ch_stereo.isChecked())
  1270. def closeEvent(self, event):
  1271. self.saveSettings()
  1272. QDialog.closeEvent(self, event)
  1273. def done(self, r):
  1274. QDialog.done(self, r)
  1275. self.close()
  1276. # ------------------------------------------------------------------------------------------------------------
  1277. # TESTING
  1278. #Carla.isControl = True
  1279. #from PyQt5.QtWidgets import QApplication
  1280. #app = QApplication(sys.argv)
  1281. #gui = PluginDatabaseW(None)
  1282. #gui.show()
  1283. #app.exec_()