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.

1675 lines
63KB

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