Collection of tools useful for audio production
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3552 lines
144KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla Backend code
  4. # Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the COPYING file
  17. # Imports (Global)
  18. import json, os, sys
  19. from sip import unwrapinstance
  20. from PyQt4.QtCore import pyqtSlot, Qt, QSettings, QTimer, QThread
  21. from PyQt4.QtGui import QApplication, QColor, QCursor, QDialog, QFontMetrics, QInputDialog, QFrame, QMainWindow, QMenu, QPainter, QTableWidgetItem, QVBoxLayout, QWidget
  22. from PyQt4.QtXml import QDomDocument
  23. # Imports (Custom Stuff)
  24. import ui_carla, ui_carla_about, ui_carla_database, ui_carla_edit, ui_carla_parameter, ui_carla_plugin, ui_carla_refresh
  25. from carla_backend import *
  26. from shared_settings import *
  27. ICON_STATE_NULL = 0
  28. ICON_STATE_WAIT = 1
  29. ICON_STATE_OFF = 2
  30. ICON_STATE_ON = 3
  31. PALETTE_COLOR_NONE = 0
  32. PALETTE_COLOR_WHITE = 1
  33. PALETTE_COLOR_RED = 2
  34. PALETTE_COLOR_GREEN = 3
  35. PALETTE_COLOR_BLUE = 4
  36. PALETTE_COLOR_YELLOW = 5
  37. PALETTE_COLOR_ORANGE = 6
  38. PALETTE_COLOR_BROWN = 7
  39. PALETTE_COLOR_PINK = 8
  40. # Save support
  41. save_state_dict = {
  42. 'Type': "",
  43. 'Name': "",
  44. 'Label': "",
  45. 'Binary': "",
  46. 'UniqueID': 0,
  47. 'Active': False,
  48. 'DryWet': 1.0,
  49. 'Volume': 1.0,
  50. 'Balance-Left': -1.0,
  51. 'Balance-Right': 1.0,
  52. 'Parameters': [],
  53. 'CurrentProgramIndex': -1,
  54. 'CurrentProgramName': "",
  55. 'CurrentMidiBank': -1,
  56. 'CurrentMidiProgram': -1,
  57. 'CustomData': [],
  58. 'Chunk': None
  59. }
  60. save_state_parameter = {
  61. 'index': 0,
  62. 'name': "",
  63. 'symbol': "",
  64. 'value': 0.0,
  65. 'midiChannel': 1,
  66. 'midiCC': -1
  67. }
  68. save_state_custom_data = {
  69. 'type': CUSTOM_DATA_INVALID,
  70. 'key': "",
  71. 'value': ""
  72. }
  73. # set defaults
  74. DEFAULT_PROJECT_FOLDER = HOME
  75. setDefaultProjectFolder(DEFAULT_PROJECT_FOLDER)
  76. setDefaultPluginsPaths(LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, GIG_PATH, SF2_PATH, SFZ_PATH)
  77. def CustomDataType2String(dtype):
  78. if dtype == CUSTOM_DATA_STRING:
  79. return "string"
  80. elif dtype == CUSTOM_DATA_PATH:
  81. return "path"
  82. elif dtype == CUSTOM_DATA_CHUNK:
  83. return "chunk"
  84. elif dtype == CUSTOM_DATA_BINARY:
  85. return "binary"
  86. else:
  87. return "null"
  88. def CustomDataString2Type(stype):
  89. if stype == "string":
  90. return CUSTOM_DATA_STRING
  91. elif stype == "path":
  92. return CUSTOM_DATA_PATH
  93. elif stype == "chunk":
  94. return CUSTOM_DATA_CHUNK
  95. elif stype == "binary":
  96. return CUSTOM_DATA_BINARY
  97. else:
  98. return CUSTOM_DATA_INVALID
  99. def xmlSafeString(string, toXml):
  100. if toXml:
  101. return string.replace("&", "&amp;").replace("<","&lt;").replace(">","&gt;").replace("'","&apos;").replace("\"","&quot;")
  102. else:
  103. return string.replace("&amp;", "&").replace("&lt;","<").replace("&gt;",">").replace("&apos;","'").replace("&quot;","\"")
  104. def getStateDictFromXML(xml_node):
  105. x_save_state_dict = deepcopy(save_state_dict)
  106. node = xml_node.firstChild()
  107. while not node.isNull():
  108. if (node.toElement().tagName() == "Info"):
  109. xml_info = node.toElement().firstChild()
  110. while not xml_info.isNull():
  111. tag = xml_info.toElement().tagName()
  112. text = xml_info.toElement().text().strip()
  113. if tag == "Type":
  114. x_save_state_dict['Type'] = text
  115. elif tag == "Name":
  116. x_save_state_dict['Name'] = xmlSafeString(text, False)
  117. elif tag in ("Label", "URI"):
  118. x_save_state_dict['Label'] = xmlSafeString(text, False)
  119. elif tag == "Binary":
  120. x_save_state_dict['Binary'] = xmlSafeString(text, False)
  121. elif tag == "UniqueID":
  122. if text.isdigit():
  123. x_save_state_dict['UniqueID'] = int(text)
  124. xml_info = xml_info.nextSibling()
  125. elif (node.toElement().tagName() == "Data"):
  126. xml_data = node.toElement().firstChild()
  127. while not xml_data.isNull():
  128. tag = xml_data.toElement().tagName()
  129. text = xml_data.toElement().text().strip()
  130. if tag == "Active":
  131. x_save_state_dict['Active'] = bool(text == "Yes")
  132. elif tag == "DryWet":
  133. if isNumber(text):
  134. x_save_state_dict['DryWet'] = float(text)
  135. elif (tag == "Vol"):
  136. if isNumber(text):
  137. x_save_state_dict['Volume'] = float(text)
  138. elif (tag == "Balance-Left"):
  139. if isNumber(text):
  140. x_save_state_dict['Balance-Left'] = float(text)
  141. elif (tag == "Balance-Right"):
  142. if isNumber(text):
  143. x_save_state_dict['Balance-Right'] = float(text)
  144. elif tag == "CurrentProgramIndex":
  145. if text.isdigit():
  146. x_save_state_dict['CurrentProgramIndex'] = int(text)
  147. elif tag == "CurrentProgramName":
  148. x_save_state_dict['CurrentProgramName'] = xmlSafeString(text, False)
  149. elif tag == "CurrentMidiBank":
  150. if text.isdigit():
  151. x_save_state_dict['CurrentMidiBank'] = int(text)
  152. elif tag == "CurrentMidiProgram":
  153. if text.isdigit():
  154. x_save_state_dict['CurrentMidiProgram'] = int(text)
  155. elif tag == "Parameter":
  156. x_save_state_parameter = deepcopy(save_state_parameter)
  157. xml_subdata = xml_data.toElement().firstChild()
  158. while not xml_subdata.isNull():
  159. ptag = xml_subdata.toElement().tagName()
  160. ptext = xml_subdata.toElement().text().strip()
  161. if ptag == "index":
  162. if ptext.isdigit():
  163. x_save_state_parameter['index'] = int(ptext)
  164. elif ptag == "name":
  165. x_save_state_parameter['name'] = xmlSafeString(ptext, False)
  166. elif ptag == "symbol":
  167. x_save_state_parameter['symbol'] = xmlSafeString(ptext, False)
  168. elif ptag == "value":
  169. if isNumber(ptext):
  170. x_save_state_parameter['value'] = float(ptext)
  171. elif ptag == "midiChannel":
  172. if ptext.isdigit():
  173. x_save_state_parameter['midiChannel'] = int(ptext)
  174. elif ptag == "midiCC":
  175. if ptext.isdigit():
  176. x_save_state_parameter['midiCC'] = int(ptext)
  177. xml_subdata = xml_subdata.nextSibling()
  178. x_save_state_dict['Parameters'].append(x_save_state_parameter)
  179. elif (tag == "CustomData"):
  180. x_save_state_custom_data = deepcopy(save_state_custom_data)
  181. xml_subdata = xml_data.toElement().firstChild()
  182. while not xml_subdata.isNull():
  183. ctag = xml_subdata.toElement().tagName()
  184. ctext = xml_subdata.toElement().text().strip()
  185. if ctag == "type":
  186. x_save_state_custom_data['type'] = CustomDataString2Type(ctext)
  187. elif ctag == "key":
  188. x_save_state_custom_data['key'] = xmlSafeString(ctext, False)
  189. elif ctag == "value":
  190. x_save_state_custom_data['value'] = xmlSafeString(ctext, False)
  191. xml_subdata = xml_subdata.nextSibling()
  192. x_save_state_dict['CustomData'].append(x_save_state_custom_data)
  193. elif tag == "Chunk":
  194. x_save_state_dict['Chunk'] = text
  195. xml_data = xml_data.nextSibling()
  196. node = node.nextSibling()
  197. return x_save_state_dict
  198. # Separate Thread for Plugin Search
  199. class SearchPluginsThread(QThread):
  200. def __init__(self, parent):
  201. QThread.__init__(self, parent)
  202. self.settings_db = self.parent().settings_db
  203. self.tool_native = None
  204. self.check_unix32 = False
  205. self.check_unix64 = False
  206. self.check_win32 = False
  207. self.check_win64 = False
  208. self.check_ladspa = False
  209. self.check_dssi = False
  210. self.check_lv2 = False
  211. self.check_vst = False
  212. self.check_gig = False
  213. self.check_sf2 = False
  214. self.check_sfz = False
  215. def skipPlugin(self):
  216. # TODO - windows and mac support
  217. apps = ""
  218. apps += " carla-discovery"
  219. apps += " carla-discovery-unix32"
  220. apps += " carla-discovery-unix64"
  221. apps += " carla-discovery-win32.exe"
  222. apps += " carla-discovery-win64.exe"
  223. if LINUX:
  224. os.system("killall -KILL %s" % apps)
  225. def pluginLook(self, percent, plugin):
  226. self.emit(SIGNAL("PluginLook(int, QString)"), percent, plugin)
  227. def setSearchBinaryTypes(self, unix32, unix64, win32, win64):
  228. self.check_unix32 = unix32
  229. self.check_unix64 = unix64
  230. self.check_win32 = win32
  231. self.check_win64 = win64
  232. def setSearchPluginTypes(self, ladspa, dssi, lv2, vst, gig, sf2, sfz):
  233. self.check_ladspa = ladspa
  234. self.check_dssi = dssi
  235. self.check_lv2 = lv2
  236. self.check_vst = vst
  237. self.check_gig = gig
  238. self.check_sf2 = sf2
  239. self.check_sfz = sfz
  240. def setSearchToolNative(self, tool):
  241. self.tool_native = tool
  242. def setLastLoadedBinary(self, binary):
  243. self.settings_db.setValue("Plugins/LastLoadedBinary", binary)
  244. def checkLADSPA(self, OS, tool, isWine=False):
  245. global LADSPA_PATH
  246. ladspa_binaries = []
  247. self.ladspa_plugins = []
  248. for iPATH in LADSPA_PATH:
  249. binaries = findBinaries(iPATH, OS)
  250. for binary in binaries:
  251. if binary not in ladspa_binaries:
  252. ladspa_binaries.append(binary)
  253. ladspa_binaries.sort()
  254. for i in range(len(ladspa_binaries)):
  255. ladspa = ladspa_binaries[i]
  256. if os.path.basename(ladspa) in self.blacklist:
  257. print("plugin %s is blacklisted, skip it" % ladspa)
  258. continue
  259. else:
  260. percent = ( float(i) / len(ladspa_binaries) ) * self.m_percent_value
  261. self.pluginLook((self.m_last_value + percent) * 0.9, ladspa)
  262. self.setLastLoadedBinary(ladspa)
  263. plugins = checkPluginLADSPA(ladspa, tool, isWine)
  264. if plugins:
  265. self.ladspa_plugins.append(plugins)
  266. self.m_last_value += self.m_percent_value
  267. self.setLastLoadedBinary("")
  268. def checkDSSI(self, OS, tool, isWine=False):
  269. global DSSI_PATH
  270. dssi_binaries = []
  271. self.dssi_plugins = []
  272. for iPATH in DSSI_PATH:
  273. binaries = findBinaries(iPATH, OS)
  274. for binary in binaries:
  275. if binary not in dssi_binaries:
  276. dssi_binaries.append(binary)
  277. dssi_binaries.sort()
  278. for i in range(len(dssi_binaries)):
  279. dssi = dssi_binaries[i]
  280. if os.path.basename(dssi) in self.blacklist:
  281. print("plugin %s is blacklisted, skip it" % dssi)
  282. continue
  283. else:
  284. percent = ( float(i) / len(dssi_binaries) ) * self.m_percent_value
  285. self.pluginLook(self.m_last_value + percent, dssi)
  286. self.setLastLoadedBinary(dssi)
  287. plugins = checkPluginDSSI(dssi, tool, isWine)
  288. if plugins:
  289. self.dssi_plugins.append(plugins)
  290. self.m_last_value += self.m_percent_value
  291. self.setLastLoadedBinary("")
  292. def checkLV2(self, tool, isWine=False):
  293. global LV2_PATH
  294. lv2_bundles = []
  295. self.lv2_plugins = []
  296. self.pluginLook(self.m_last_value, "LV2 bundles...")
  297. for iPATH in LV2_PATH:
  298. bundles = findLV2Bundles(iPATH)
  299. for bundle in bundles:
  300. if bundle not in lv2_bundles:
  301. lv2_bundles.append(bundle)
  302. lv2_bundles.sort()
  303. for i in range(len(lv2_bundles)):
  304. lv2 = lv2_bundles[i]
  305. if (os.path.basename(lv2) in self.blacklist):
  306. print("bundle %s is blacklisted, skip it" % lv2)
  307. continue
  308. else:
  309. percent = ( float(i) / len(lv2_bundles) ) * self.m_percent_value
  310. self.pluginLook(self.m_last_value + percent, lv2)
  311. self.setLastLoadedBinary(lv2)
  312. plugins = checkPluginLV2(lv2, tool, isWine)
  313. if plugins:
  314. self.lv2_plugins.append(plugins)
  315. self.m_last_value += self.m_percent_value
  316. self.setLastLoadedBinary("")
  317. def checkVST(self, OS, tool, isWine=False):
  318. global VST_PATH
  319. vst_binaries = []
  320. self.vst_plugins = []
  321. for iPATH in VST_PATH:
  322. binaries = findBinaries(iPATH, OS)
  323. for binary in binaries:
  324. if binary not in vst_binaries:
  325. vst_binaries.append(binary)
  326. vst_binaries.sort()
  327. for i in range(len(vst_binaries)):
  328. vst = vst_binaries[i]
  329. if os.path.basename(vst) in self.blacklist:
  330. print("plugin %s is blacklisted, skip it" % vst)
  331. continue
  332. else:
  333. percent = ( float(i) / len(vst_binaries) ) * self.m_percent_value
  334. self.pluginLook(self.m_last_value + percent, vst)
  335. self.setLastLoadedBinary(vst)
  336. plugins = checkPluginVST(vst, tool, isWine)
  337. if plugins:
  338. self.vst_plugins.append(plugins)
  339. self.m_last_value += self.m_percent_value
  340. self.setLastLoadedBinary("")
  341. def checkKIT(self, kPATH, kType):
  342. kit_files = []
  343. self.kit_plugins = []
  344. for iPATH in kPATH:
  345. files = findSoundKits(iPATH, kType)
  346. for file_ in files:
  347. if file_ not in kit_files:
  348. kit_files.append(file_)
  349. kit_files.sort()
  350. for i in range(len(kit_files)):
  351. kit = kit_files[i]
  352. if os.path.basename(kit) in self.blacklist:
  353. print("plugin %s is blacklisted, skip it" % kit)
  354. continue
  355. else:
  356. percent = ( float(i) / len(kit_files) ) * self.m_percent_value
  357. self.pluginLook(self.m_last_value + percent, kit)
  358. self.setLastLoadedBinary(kit)
  359. if kType == "gig":
  360. plugins = checkPluginGIG(kit, self.tool_native)
  361. elif kType == "sf2":
  362. plugins = checkPluginSF2(kit, self.tool_native)
  363. elif kType == "sfz":
  364. plugins = checkPluginSFZ(kit, self.tool_native)
  365. else:
  366. plugins = None
  367. if plugins:
  368. self.kit_plugins.append(plugins)
  369. self.m_last_value += self.m_percent_value
  370. self.setLastLoadedBinary("")
  371. def run(self):
  372. global LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, GIG_PATH, SF2_PATH, SFZ_PATH
  373. os.environ['LADSPA_PATH'] = splitter.join(LADSPA_PATH)
  374. os.environ['DSSI_PATH'] = splitter.join(DSSI_PATH)
  375. os.environ['LV2_PATH'] = splitter.join(LV2_PATH)
  376. os.environ['VST_PATH'] = splitter.join(VST_PATH)
  377. os.environ['GIG_PATH'] = splitter.join(GIG_PATH)
  378. os.environ['SF2_PATH'] = splitter.join(SF2_PATH)
  379. os.environ['SFZ_PATH'] = splitter.join(SFZ_PATH)
  380. self.blacklist = toList(self.settings_db.value("Plugins/Blacklisted", []))
  381. self.m_count = 0
  382. plugin_count = 0
  383. if self.check_ladspa: plugin_count += 1
  384. if self.check_dssi: plugin_count += 1
  385. if self.check_lv2: plugin_count += 1
  386. if self.check_vst: plugin_count += 1
  387. if self.check_unix32:
  388. self.m_count += plugin_count
  389. if self.check_unix64:
  390. self.m_count += plugin_count
  391. if self.check_win32:
  392. self.m_count += plugin_count
  393. if self.check_win64:
  394. self.m_count += plugin_count
  395. if self.tool_native:
  396. if self.check_gig: self.m_count += 1
  397. if self.check_sf2: self.m_count += 1
  398. if self.check_sfz: self.m_count += 1
  399. else:
  400. self.check_gig = False
  401. self.check_sf2 = False
  402. self.check_sfz = False
  403. if self.m_count == 0:
  404. return
  405. self.m_last_value = 0
  406. self.m_percent_value = 100 / self.m_count
  407. if LINUX:
  408. OS = "LINUX"
  409. elif MACOS:
  410. OS = "MACOS"
  411. elif WINDOWS:
  412. OS = "WINDOWS"
  413. else:
  414. OS = "UNKNOWN"
  415. if self.check_ladspa:
  416. m_value = 0
  417. if haveLRDF:
  418. if self.check_unix32: m_value += 0.1
  419. if self.check_unix64: m_value += 0.1
  420. if self.check_win32: m_value += 0.1
  421. if self.check_win64: m_value += 0.1
  422. rdf_pad_value = self.m_percent_value * m_value
  423. if self.check_unix32:
  424. self.checkLADSPA(OS, carla_discovery_unix32)
  425. self.settings_db.setValue("Plugins/LADSPA_unix32", self.ladspa_plugins)
  426. self.settings_db.sync()
  427. if self.check_unix64:
  428. self.checkLADSPA(OS, carla_discovery_unix64)
  429. self.settings_db.setValue("Plugins/LADSPA_unix64", self.ladspa_plugins)
  430. self.settings_db.sync()
  431. if self.check_win32:
  432. self.checkLADSPA("WINDOWS", carla_discovery_win32, not WINDOWS)
  433. self.settings_db.setValue("Plugins/LADSPA_win32", self.ladspa_plugins)
  434. self.settings_db.sync()
  435. if self.check_win64:
  436. self.checkLADSPA("WINDOWS", carla_discovery_win64, not WINDOWS)
  437. self.settings_db.setValue("Plugins/LADSPA_win64", self.ladspa_plugins)
  438. self.settings_db.sync()
  439. if haveLRDF:
  440. if m_value > 0:
  441. start_value = self.m_last_value - rdf_pad_value
  442. self.pluginLook(start_value, "LADSPA RDFs...")
  443. ladspa_rdf_info = ladspa_rdf.recheck_all_plugins(self, start_value, self.m_percent_value, m_value)
  444. SettingsDir = os.path.join(HOME, ".config", "Cadence")
  445. f_ladspa = open(os.path.join(SettingsDir, "ladspa_rdf.db"), 'w')
  446. if f_ladspa:
  447. json.dump(ladspa_rdf_info, f_ladspa)
  448. f_ladspa.close()
  449. if self.check_dssi:
  450. if self.check_unix32:
  451. self.checkDSSI(OS, carla_discovery_unix32)
  452. self.settings_db.setValue("Plugins/DSSI_unix32", self.dssi_plugins)
  453. self.settings_db.sync()
  454. if self.check_unix64:
  455. self.checkDSSI(OS, carla_discovery_unix64)
  456. self.settings_db.setValue("Plugins/DSSI_unix64", self.dssi_plugins)
  457. self.settings_db.sync()
  458. if self.check_win32:
  459. self.checkDSSI("WINDOWS", carla_discovery_win32, not WINDOWS)
  460. self.settings_db.setValue("Plugins/DSSI_win32", self.dssi_plugins)
  461. self.settings_db.sync()
  462. if self.check_win64:
  463. self.checkDSSI("WINDOWS", carla_discovery_win64, not WINDOWS)
  464. self.settings_db.setValue("Plugins/DSSI_win64", self.dssi_plugins)
  465. self.settings_db.sync()
  466. if self.check_lv2:
  467. if self.check_unix32:
  468. self.checkLV2(carla_discovery_unix32)
  469. self.settings_db.setValue("Plugins/LV2_unix32", self.lv2_plugins)
  470. self.settings_db.sync()
  471. if self.check_unix64:
  472. self.checkLV2(carla_discovery_unix64)
  473. self.settings_db.setValue("Plugins/LV2_unix64", self.lv2_plugins)
  474. self.settings_db.sync()
  475. if self.check_win32:
  476. self.checkLV2(carla_discovery_win32, not WINDOWS)
  477. self.settings_db.setValue("Plugins/LV2_win32", self.lv2_plugins)
  478. self.settings_db.sync()
  479. if self.check_win64:
  480. self.checkLV2(carla_discovery_win64, not WINDOWS)
  481. self.settings_db.setValue("Plugins/LV2_win64", self.lv2_plugins)
  482. self.settings_db.sync()
  483. if self.check_vst:
  484. if self.check_unix32:
  485. self.checkVST(OS, carla_discovery_unix32)
  486. self.settings_db.setValue("Plugins/VST_unix32", self.vst_plugins)
  487. self.settings_db.sync()
  488. if self.check_unix64:
  489. self.checkVST(OS, carla_discovery_unix64)
  490. self.settings_db.setValue("Plugins/VST_unix64", self.vst_plugins)
  491. self.settings_db.sync()
  492. if self.check_win32:
  493. self.checkVST("WINDOWS", carla_discovery_win32, not WINDOWS)
  494. self.settings_db.setValue("Plugins/VST_win32", self.vst_plugins)
  495. self.settings_db.sync()
  496. if self.check_win64:
  497. self.checkVST("WINDOWS", carla_discovery_win64, not WINDOWS)
  498. self.settings_db.setValue("Plugins/VST_win64", self.vst_plugins)
  499. self.settings_db.sync()
  500. if self.check_gig:
  501. self.checkKIT(GIG_PATH, "gig")
  502. self.settings_db.setValue("Plugins/GIG", self.kit_plugins)
  503. self.settings_db.sync()
  504. if self.check_sf2:
  505. self.checkKIT(SF2_PATH, "sf2")
  506. self.settings_db.setValue("Plugins/SF2", self.kit_plugins)
  507. self.settings_db.sync()
  508. if self.check_sfz:
  509. self.checkKIT(SFZ_PATH, "sfz")
  510. self.settings_db.setValue("Plugins/SFZ", self.kit_plugins)
  511. self.settings_db.sync()
  512. # Plugin Refresh Dialog
  513. class PluginRefreshW(QDialog, ui_carla_refresh.Ui_PluginRefreshW):
  514. def __init__(self, parent):
  515. QDialog.__init__(self, parent)
  516. self.setupUi(self)
  517. self.b_skip.setVisible(False)
  518. if LINUX:
  519. self.ch_unix32.setText("Linux 32bit")
  520. self.ch_unix64.setText("Linux 64bit")
  521. elif MACOS:
  522. self.ch_unix32.setText("MacOS 32bit")
  523. self.ch_unix64.setText("MacOS 64bit")
  524. self.settings = self.parent().settings
  525. self.settings_db = self.parent().settings_db
  526. self.loadSettings()
  527. self.pThread = SearchPluginsThread(self)
  528. if carla_discovery_unix32 and not WINDOWS:
  529. self.ico_unix32.setPixmap(getIcon("dialog-ok-apply").pixmap(16, 16))
  530. else:
  531. self.ico_unix32.setPixmap(getIcon("dialog-error").pixmap(16, 16))
  532. self.ch_unix32.setChecked(False)
  533. self.ch_unix32.setEnabled(False)
  534. if carla_discovery_unix64 and not WINDOWS:
  535. self.ico_unix64.setPixmap(getIcon("dialog-ok-apply").pixmap(16, 16))
  536. else:
  537. self.ico_unix64.setPixmap(getIcon("dialog-error").pixmap(16, 16))
  538. self.ch_unix64.setChecked(False)
  539. self.ch_unix64.setEnabled(False)
  540. if carla_discovery_win32:
  541. self.ico_win32.setPixmap(getIcon("dialog-ok-apply").pixmap(16, 16))
  542. else:
  543. self.ico_win32.setPixmap(getIcon("dialog-error").pixmap(16, 16))
  544. self.ch_win32.setChecked(False)
  545. self.ch_win32.setEnabled(False)
  546. if carla_discovery_win64:
  547. self.ico_win64.setPixmap(getIcon("dialog-ok-apply").pixmap(16, 16))
  548. else:
  549. self.ico_win64.setPixmap(getIcon("dialog-error").pixmap(16, 16))
  550. self.ch_win64.setChecked(False)
  551. self.ch_win64.setEnabled(False)
  552. if haveLRDF:
  553. self.ico_rdflib.setPixmap(getIcon("dialog-ok-apply").pixmap(16, 16))
  554. else:
  555. self.ico_rdflib.setPixmap(getIcon("dialog-error").pixmap(16, 16))
  556. hasNative = False
  557. hasNonNative = False
  558. if LINUX or MACOS:
  559. if is64bit:
  560. hasNative = bool(carla_discovery_unix64)
  561. hasNonNative = bool(carla_discovery_unix32 or carla_discovery_win32 or carla_discovery_win64)
  562. self.pThread.setSearchToolNative(carla_discovery_unix64)
  563. else:
  564. hasNative = bool(carla_discovery_unix32)
  565. hasNonNative = bool(carla_discovery_unix64 or carla_discovery_win32 or carla_discovery_win64)
  566. self.pThread.setSearchToolNative(carla_discovery_unix32)
  567. elif WINDOWS:
  568. if is64bit:
  569. hasNative = bool(carla_discovery_win64)
  570. hasNonNative = bool(carla_discovery_win32)
  571. self.pThread.setSearchToolNative(carla_discovery_win64)
  572. else:
  573. hasNative = bool(carla_discovery_win32)
  574. hasNonNative = bool(carla_discovery_win64)
  575. self.pThread.setSearchToolNative(carla_discovery_win32)
  576. if not hasNative:
  577. self.ch_gig.setChecked(False)
  578. self.ch_gig.setEnabled(False)
  579. self.ch_sf2.setChecked(False)
  580. self.ch_sf2.setEnabled(False)
  581. self.ch_sfz.setChecked(False)
  582. self.ch_sfz.setEnabled(False)
  583. if not hasNonNative:
  584. self.ch_ladspa.setChecked(False)
  585. self.ch_ladspa.setEnabled(False)
  586. self.ch_dssi.setChecked(False)
  587. self.ch_dssi.setEnabled(False)
  588. self.ch_vst.setChecked(False)
  589. self.ch_vst.setEnabled(False)
  590. self.b_refresh.setEnabled(False)
  591. self.connect(self.b_refresh, SIGNAL("clicked()"), SLOT("slot_refresh_plugins()"))
  592. self.connect(self.b_skip, SIGNAL("clicked()"), SLOT("slot_skip()"))
  593. self.connect(self.pThread, SIGNAL("PluginLook(int, QString)"), SLOT("slot_handlePluginLook(int, QString)"))
  594. self.connect(self.pThread, SIGNAL("finished()"), SLOT("slot_handlePluginThreadFinished()"))
  595. @pyqtSlot()
  596. def slot_refresh_plugins(self):
  597. self.progressBar.setMinimum(0)
  598. self.progressBar.setMaximum(100)
  599. self.progressBar.setValue(0)
  600. self.b_refresh.setEnabled(False)
  601. self.b_skip.setVisible(True)
  602. self.b_close.setVisible(False)
  603. unix32, unix64, win32, win64 = (self.ch_unix32.isChecked(), self.ch_unix64.isChecked(), self.ch_win32.isChecked(), self.ch_win64.isChecked())
  604. ladspa, dssi, lv2, vst, gig, sf2, sfz = (self.ch_ladspa.isChecked(), self.ch_dssi.isChecked(), self.ch_lv2.isChecked(), self.ch_vst.isChecked(),
  605. self.ch_gig.isChecked(), self.ch_sf2.isChecked(), self.ch_sfz.isChecked())
  606. self.pThread.setSearchBinaryTypes(unix32, unix64, win32, win64)
  607. self.pThread.setSearchPluginTypes(ladspa, dssi, lv2, vst, gig, sf2, sfz)
  608. self.pThread.start()
  609. @pyqtSlot()
  610. def slot_skip(self):
  611. self.pThread.skipPlugin()
  612. @pyqtSlot(int, str)
  613. def slot_handlePluginLook(self, percent, plugin):
  614. self.progressBar.setFormat("%s" % (plugin))
  615. self.progressBar.setValue(percent)
  616. @pyqtSlot()
  617. def slot_handlePluginThreadFinished(self):
  618. self.progressBar.setMinimum(0)
  619. self.progressBar.setMaximum(1)
  620. self.progressBar.setValue(1)
  621. self.progressBar.setFormat(self.tr("Done"))
  622. self.b_refresh.setEnabled(True)
  623. self.b_skip.setVisible(False)
  624. self.b_close.setVisible(True)
  625. def saveSettings(self):
  626. self.settings.setValue("PluginDatabase/SearchLADSPA", self.ch_ladspa.isChecked())
  627. self.settings.setValue("PluginDatabase/SearchDSSI", self.ch_dssi.isChecked())
  628. self.settings.setValue("PluginDatabase/SearchLV2", self.ch_lv2.isChecked())
  629. self.settings.setValue("PluginDatabase/SearchVST", self.ch_vst.isChecked())
  630. self.settings.setValue("PluginDatabase/SearchGIG", self.ch_gig.isChecked())
  631. self.settings.setValue("PluginDatabase/SearchSF2", self.ch_sf2.isChecked())
  632. self.settings.setValue("PluginDatabase/SearchSFZ", self.ch_sfz.isChecked())
  633. self.settings.setValue("PluginDatabase/SearchUnix32", self.ch_unix32.isChecked())
  634. self.settings.setValue("PluginDatabase/SearchUnix64", self.ch_unix64.isChecked())
  635. self.settings.setValue("PluginDatabase/SearchWin32", self.ch_win32.isChecked())
  636. self.settings.setValue("PluginDatabase/SearchWin64", self.ch_win64.isChecked())
  637. self.settings_db.setValue("Plugins/LastLoadedBinary", "")
  638. def loadSettings(self):
  639. self.ch_ladspa.setChecked(self.settings.value("PluginDatabase/SearchLADSPA", True, type=bool))
  640. self.ch_dssi.setChecked(self.settings.value("PluginDatabase/SearchDSSI", True, type=bool))
  641. self.ch_lv2.setChecked(self.settings.value("PluginDatabase/SearchLV2", True, type=bool))
  642. self.ch_vst.setChecked(self.settings.value("PluginDatabase/SearchVST", True, type=bool))
  643. self.ch_gig.setChecked(self.settings.value("PluginDatabase/SearchGIG", True, type=bool))
  644. self.ch_sf2.setChecked(self.settings.value("PluginDatabase/SearchSF2", True, type=bool))
  645. self.ch_sfz.setChecked(self.settings.value("PluginDatabase/SearchSFZ", True, type=bool))
  646. self.ch_unix32.setChecked(self.settings.value("PluginDatabase/SearchUnix32", True, type=bool))
  647. self.ch_unix64.setChecked(self.settings.value("PluginDatabase/SearchUnix64", True, type=bool))
  648. self.ch_win32.setChecked(self.settings.value("PluginDatabase/SearchWin32", True, type=bool))
  649. self.ch_win64.setChecked(self.settings.value("PluginDatabase/SearchWin64", True, type=bool))
  650. def closeEvent(self, event):
  651. if self.pThread.isRunning():
  652. self.pThread.terminate()
  653. self.pThread.wait()
  654. self.saveSettings()
  655. QDialog.closeEvent(self, event)
  656. def done(self, r):
  657. QDialog.done(self, r)
  658. self.close()
  659. # Plugin Database Dialog
  660. class PluginDatabaseW(QDialog, ui_carla_database.Ui_PluginDatabaseW):
  661. def __init__(self, parent):
  662. QDialog.__init__(self, parent)
  663. self.setupUi(self)
  664. self.warning_old_shown = False
  665. self.b_add.setEnabled(False)
  666. if BINARY_NATIVE in (BINARY_UNIX32, BINARY_WIN32):
  667. self.ch_bridged.setText(self.tr("Bridged (64bit)"))
  668. else:
  669. self.ch_bridged.setText(self.tr("Bridged (32bit)"))
  670. self.settings = self.parent().settings
  671. self.settings_db = self.parent().settings_db
  672. self.loadSettings()
  673. if not (LINUX or MACOS):
  674. self.ch_bridged_wine.setChecked(False)
  675. self.ch_bridged_wine.setEnabled(False)
  676. # Blacklist plugins
  677. if not self.settings_db.contains("Plugins/Blacklisted"):
  678. blacklist = [] # FIXME
  679. # Broken or useless plugins
  680. #blacklist.append("dssi-vst.so")
  681. blacklist.append("liteon_biquad-vst.so")
  682. blacklist.append("liteon_biquad-vst_64bit.so")
  683. blacklist.append("fx_blur-vst.so")
  684. blacklist.append("fx_blur-vst_64bit.so")
  685. blacklist.append("fx_tempodelay-vst.so")
  686. blacklist.append("Scrubby_64bit.so")
  687. blacklist.append("Skidder_64bit.so")
  688. blacklist.append("libwormhole2_64bit.so")
  689. blacklist.append("vexvst.so")
  690. #blacklist.append("deckadance.dll")
  691. self.settings_db.setValue("Plugins/Blacklisted", blacklist)
  692. self.connect(self.b_add, SIGNAL("clicked()"), SLOT("slot_add_plugin()"))
  693. self.connect(self.b_refresh, SIGNAL("clicked()"), SLOT("slot_refresh_plugins()"))
  694. self.connect(self.tb_filters, SIGNAL("clicked()"), SLOT("slot_maybe_show_filters()"))
  695. self.connect(self.tableWidget, SIGNAL("currentCellChanged(int, int, int, int)"), SLOT("slot_checkPlugin(int)"))
  696. self.connect(self.tableWidget, SIGNAL("cellDoubleClicked(int, int)"), SLOT("slot_add_plugin()"))
  697. self.connect(self.lineEdit, SIGNAL("textChanged(QString)"), SLOT("slot_checkFilters()"))
  698. self.connect(self.ch_effects, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  699. self.connect(self.ch_instruments, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  700. self.connect(self.ch_midi, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  701. self.connect(self.ch_other, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  702. self.connect(self.ch_kits, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  703. self.connect(self.ch_ladspa, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  704. self.connect(self.ch_dssi, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  705. self.connect(self.ch_lv2, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  706. self.connect(self.ch_vst, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  707. self.connect(self.ch_native, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  708. self.connect(self.ch_bridged, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  709. self.connect(self.ch_bridged_wine, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  710. self.connect(self.ch_gui, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  711. self.connect(self.ch_stereo, SIGNAL("clicked()"), SLOT("slot_checkFilters()"))
  712. self.ret_plugin = None
  713. def showFilters(self, yesno):
  714. self.tb_filters.setArrowType(Qt.UpArrow if yesno else Qt.DownArrow)
  715. self.frame.setVisible(yesno)
  716. def reAddPlugins(self):
  717. row_count = self.tableWidget.rowCount()
  718. for x in range(row_count):
  719. self.tableWidget.removeRow(0)
  720. self.last_table_index = 0
  721. self.tableWidget.setSortingEnabled(False)
  722. ladspa_plugins = []
  723. ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_unix32", []))
  724. ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_unix64", []))
  725. ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_win32", []))
  726. ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_win64", []))
  727. dssi_plugins = []
  728. dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_unix32", []))
  729. dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_unix64", []))
  730. dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_win32", []))
  731. dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_win64", []))
  732. lv2_plugins = []
  733. lv2_plugins += toList(self.settings_db.value("Plugins/LV2_unix32", []))
  734. lv2_plugins += toList(self.settings_db.value("Plugins/LV2_unix64", []))
  735. lv2_plugins += toList(self.settings_db.value("Plugins/LV2_win32", []))
  736. lv2_plugins += toList(self.settings_db.value("Plugins/LV2_win64", []))
  737. vst_plugins = []
  738. vst_plugins += toList(self.settings_db.value("Plugins/VST_unix32", []))
  739. vst_plugins += toList(self.settings_db.value("Plugins/VST_unix64", []))
  740. vst_plugins += toList(self.settings_db.value("Plugins/VST_win32", []))
  741. vst_plugins += toList(self.settings_db.value("Plugins/VST_win64", []))
  742. gigs = toList(self.settings_db.value("Plugins/GIG", []))
  743. sf2s = toList(self.settings_db.value("Plugins/SF2", []))
  744. sfzs = toList(self.settings_db.value("Plugins/SFZ", []))
  745. ladspa_count = 0
  746. dssi_count = 0
  747. lv2_count = 0
  748. vst_count = 0
  749. kit_count = 0
  750. for plugins in ladspa_plugins:
  751. for plugin in plugins:
  752. self.addPluginToTable(plugin, "LADSPA")
  753. ladspa_count += 1
  754. for plugins in dssi_plugins:
  755. for plugin in plugins:
  756. self.addPluginToTable(plugin, "DSSI")
  757. dssi_count += 1
  758. for plugins in lv2_plugins:
  759. for plugin in plugins:
  760. self.addPluginToTable(plugin, "LV2")
  761. lv2_count += 1
  762. for plugins in vst_plugins:
  763. for plugin in plugins:
  764. self.addPluginToTable(plugin, "VST")
  765. vst_count += 1
  766. for gig in gigs:
  767. for gig_i in gig:
  768. self.addPluginToTable(gig_i, "GIG")
  769. kit_count += 1
  770. for sf2 in sf2s:
  771. for sf2_i in sf2:
  772. self.addPluginToTable(sf2_i, "SF2")
  773. kit_count += 1
  774. for sfz in sfzs:
  775. for sfz_i in sfz:
  776. self.addPluginToTable(sfz_i, "SFZ")
  777. kit_count += 1
  778. self.slot_checkFilters()
  779. self.tableWidget.setSortingEnabled(True)
  780. self.tableWidget.sortByColumn(0, Qt.AscendingOrder)
  781. self.label.setText(self.tr("Have %i LADSPA, %i DSSI, %i LV2, %i VST and %i Sound Kits" % (ladspa_count, dssi_count, lv2_count, vst_count, kit_count)))
  782. def addPluginToTable(self, plugin, ptype):
  783. index = self.last_table_index
  784. if "build" not in plugin.keys():
  785. if not self.warning_old_shown:
  786. QMessageBox.warning(self, self.tr("Warning"), self.tr("You're using a Carla-Database from an old version of Carla, please update the plugins"))
  787. self.warning_old_shown = True
  788. return
  789. if plugin['build'] == BINARY_NATIVE:
  790. bridge_text = self.tr("No")
  791. else:
  792. type_text = self.tr("Unknown")
  793. if LINUX or MACOS:
  794. if plugin['build'] == BINARY_UNIX32:
  795. type_text = "32bit"
  796. elif plugin['build'] == BINARY_UNIX64:
  797. type_text = "64bit"
  798. elif plugin['build'] == BINARY_WIN32:
  799. type_text = "Windows 32bit"
  800. elif plugin['build'] == BINARY_WIN64:
  801. type_text = "Windows 64bit"
  802. elif WINDOWS:
  803. if plugin['build'] == BINARY_WIN32:
  804. type_text = "32bit"
  805. elif plugin['build'] == BINARY_WIN64:
  806. type_text = "64bit"
  807. bridge_text = self.tr("Yes (%s)" % type_text)
  808. self.tableWidget.insertRow(index)
  809. self.tableWidget.setItem(index, 0, QTableWidgetItem(plugin['name']))
  810. self.tableWidget.setItem(index, 1, QTableWidgetItem(plugin['label']))
  811. self.tableWidget.setItem(index, 2, QTableWidgetItem(plugin['maker']))
  812. self.tableWidget.setItem(index, 3, QTableWidgetItem(str(plugin['unique_id'])))
  813. self.tableWidget.setItem(index, 4, QTableWidgetItem(str(plugin['audio.ins'])))
  814. self.tableWidget.setItem(index, 5, QTableWidgetItem(str(plugin['audio.outs'])))
  815. self.tableWidget.setItem(index, 6, QTableWidgetItem(str(plugin['parameters.ins'])))
  816. self.tableWidget.setItem(index, 7, QTableWidgetItem(str(plugin['parameters.outs'])))
  817. self.tableWidget.setItem(index, 8, QTableWidgetItem(str(plugin['programs.total'])))
  818. self.tableWidget.setItem(index, 9, QTableWidgetItem(self.tr("Yes") if (plugin['hints'] & PLUGIN_HAS_GUI) else self.tr("No")))
  819. self.tableWidget.setItem(index, 10, QTableWidgetItem(self.tr("Yes") if (plugin['hints'] & PLUGIN_IS_SYNTH) else self.tr("No")))
  820. self.tableWidget.setItem(index, 11, QTableWidgetItem(bridge_text))
  821. self.tableWidget.setItem(index, 12, QTableWidgetItem(ptype))
  822. self.tableWidget.setItem(index, 13, QTableWidgetItem(plugin['binary']))
  823. self.tableWidget.item(self.last_table_index, 0).plugin_data = plugin
  824. self.last_table_index += 1
  825. @pyqtSlot()
  826. def slot_add_plugin(self):
  827. if self.tableWidget.currentRow() >= 0:
  828. self.ret_plugin = self.tableWidget.item(self.tableWidget.currentRow(), 0).plugin_data
  829. self.accept()
  830. else:
  831. self.reject()
  832. @pyqtSlot()
  833. def slot_refresh_plugins(self):
  834. lastLoadedPlugin = self.settings_db.value("Plugins/LastLoadedBinary", "", type=str)
  835. if lastLoadedPlugin:
  836. lastLoadedPlugin = os.path.basename(lastLoadedPlugin)
  837. ask = QMessageBox.question(self, self.tr("Warning"), self.tr("There was an error while checking the plugin %s.\n"
  838. "Do you want to blacklist it?" % (lastLoadedPlugin)),
  839. QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
  840. if ask == QMessageBox.Yes:
  841. blacklist = toList(self.settings_db.value("Plugins/Blacklisted", []))
  842. blacklist.append(lastLoadedPlugin)
  843. self.settings_db.setValue("Plugins/Blacklisted", blacklist)
  844. #self.label.setText(self.tr("Looking for plugins..."))
  845. PluginRefreshW(self).exec_()
  846. self.reAddPlugins()
  847. self.parent().loadRDFs()
  848. @pyqtSlot()
  849. def slot_maybe_show_filters(self):
  850. self.showFilters(not self.frame.isVisible())
  851. @pyqtSlot(int)
  852. def slot_checkPlugin(self, row):
  853. self.b_add.setEnabled(row >= 0)
  854. @pyqtSlot()
  855. def slot_checkFilters(self):
  856. text = self.lineEdit.text().lower()
  857. hide_effects = not self.ch_effects.isChecked()
  858. hide_instruments = not self.ch_instruments.isChecked()
  859. hide_midi = not self.ch_midi.isChecked()
  860. hide_other = not self.ch_other.isChecked()
  861. hide_ladspa = not self.ch_ladspa.isChecked()
  862. hide_dssi = not self.ch_dssi.isChecked()
  863. hide_lv2 = not self.ch_lv2.isChecked()
  864. hide_vst = not self.ch_vst.isChecked()
  865. hide_kits = not self.ch_kits.isChecked()
  866. hide_native = not self.ch_native.isChecked()
  867. hide_bridged = not self.ch_bridged.isChecked()
  868. hide_bridged_wine = not self.ch_bridged_wine.isChecked()
  869. hide_non_gui = self.ch_gui.isChecked()
  870. hide_non_stereo = self.ch_stereo.isChecked()
  871. if LINUX or MACOS:
  872. native_bins = [BINARY_UNIX32, BINARY_UNIX64]
  873. wine_bins = [BINARY_WIN32, BINARY_WIN64]
  874. elif WINDOWS:
  875. native_bins = [BINARY_WIN32, BINARY_WIN64]
  876. wine_bins = []
  877. else:
  878. native_bins = []
  879. wine_bins = []
  880. row_count = self.tableWidget.rowCount()
  881. for i in range(row_count):
  882. self.tableWidget.showRow(i)
  883. plugin = self.tableWidget.item(i, 0).plugin_data
  884. ains = plugin['audio.ins']
  885. aouts = plugin['audio.outs']
  886. mins = plugin['midi.ins']
  887. mouts = plugin['midi.outs']
  888. ptype = self.tableWidget.item(i, 12).text()
  889. is_synth = bool(plugin['hints'] & PLUGIN_IS_SYNTH)
  890. is_effect = bool(ains > 0 < aouts and not is_synth)
  891. is_midi = bool(ains == 0 and aouts == 0 and mins > 0 < mouts)
  892. is_kit = bool(ptype in ("GIG", "SF2", "SFZ"))
  893. is_other = bool(not (is_effect or is_synth or is_midi or is_kit))
  894. is_native = bool(plugin['build'] == BINARY_NATIVE)
  895. is_stereo = bool(ains == 2 and aouts == 2) or (is_synth and aouts == 2)
  896. has_gui = bool(plugin['hints'] & PLUGIN_HAS_GUI)
  897. is_bridged = bool(not is_native and plugin['build'] in native_bins)
  898. is_bridged_wine = bool(not is_native and plugin['build'] in wine_bins)
  899. if (hide_effects and is_effect):
  900. self.tableWidget.hideRow(i)
  901. elif (hide_instruments and is_synth):
  902. self.tableWidget.hideRow(i)
  903. elif (hide_midi and is_midi):
  904. self.tableWidget.hideRow(i)
  905. elif (hide_other and is_other):
  906. self.tableWidget.hideRow(i)
  907. elif (hide_kits and is_kit):
  908. self.tableWidget.hideRow(i)
  909. elif (hide_ladspa and ptype == "LADSPA"):
  910. self.tableWidget.hideRow(i)
  911. elif (hide_dssi and ptype == "DSSI"):
  912. self.tableWidget.hideRow(i)
  913. elif (hide_lv2 and ptype == "LV2"):
  914. self.tableWidget.hideRow(i)
  915. elif (hide_vst and ptype == "VST"):
  916. self.tableWidget.hideRow(i)
  917. elif (hide_native and is_native):
  918. self.tableWidget.hideRow(i)
  919. elif (hide_bridged and is_bridged):
  920. self.tableWidget.hideRow(i)
  921. elif (hide_bridged_wine and is_bridged_wine):
  922. self.tableWidget.hideRow(i)
  923. elif (hide_non_gui and not has_gui):
  924. self.tableWidget.hideRow(i)
  925. elif (hide_non_stereo and not is_stereo):
  926. self.tableWidget.hideRow(i)
  927. elif (text and not (
  928. text in self.tableWidget.item(i, 0).text().lower() or
  929. text in self.tableWidget.item(i, 1).text().lower() or
  930. text in self.tableWidget.item(i, 2).text().lower() or
  931. text in self.tableWidget.item(i, 3).text().lower() or
  932. text in self.tableWidget.item(i, 13).text().lower())):
  933. self.tableWidget.hideRow(i)
  934. def saveSettings(self):
  935. self.settings.setValue("PluginDatabase/Geometry", self.saveGeometry())
  936. self.settings.setValue("PluginDatabase/TableGeometry", self.tableWidget.horizontalHeader().saveState())
  937. self.settings.setValue("PluginDatabase/ShowFilters", (self.tb_filters.arrowType() == Qt.UpArrow))
  938. self.settings.setValue("PluginDatabase/ShowEffects", self.ch_effects.isChecked())
  939. self.settings.setValue("PluginDatabase/ShowInstruments", self.ch_instruments.isChecked())
  940. self.settings.setValue("PluginDatabase/ShowMIDI", self.ch_midi.isChecked())
  941. self.settings.setValue("PluginDatabase/ShowOther", self.ch_other.isChecked())
  942. self.settings.setValue("PluginDatabase/ShowLADSPA", self.ch_ladspa.isChecked())
  943. self.settings.setValue("PluginDatabase/ShowDSSI", self.ch_dssi.isChecked())
  944. self.settings.setValue("PluginDatabase/ShowLV2", self.ch_lv2.isChecked())
  945. self.settings.setValue("PluginDatabase/ShowVST", self.ch_vst.isChecked())
  946. self.settings.setValue("PluginDatabase/ShowKits", self.ch_kits.isChecked())
  947. self.settings.setValue("PluginDatabase/ShowNative", self.ch_native.isChecked())
  948. self.settings.setValue("PluginDatabase/ShowBridged", self.ch_bridged.isChecked())
  949. self.settings.setValue("PluginDatabase/ShowBridgedWine", self.ch_bridged_wine.isChecked())
  950. self.settings.setValue("PluginDatabase/ShowHasGUI", self.ch_gui.isChecked())
  951. self.settings.setValue("PluginDatabase/ShowStereoOnly", self.ch_stereo.isChecked())
  952. def loadSettings(self):
  953. self.restoreGeometry(self.settings.value("PluginDatabase/Geometry", ""))
  954. self.tableWidget.horizontalHeader().restoreState(self.settings.value("PluginDatabase/TableGeometry", ""))
  955. self.showFilters(self.settings.value("PluginDatabase/ShowFilters", False, type=bool))
  956. self.ch_effects.setChecked(self.settings.value("PluginDatabase/ShowEffects", True, type=bool))
  957. self.ch_instruments.setChecked(self.settings.value("PluginDatabase/ShowInstruments", True, type=bool))
  958. self.ch_midi.setChecked(self.settings.value("PluginDatabase/ShowMIDI", True, type=bool))
  959. self.ch_other.setChecked(self.settings.value("PluginDatabase/ShowOther", True, type=bool))
  960. self.ch_ladspa.setChecked(self.settings.value("PluginDatabase/ShowLADSPA", True, type=bool))
  961. self.ch_dssi.setChecked(self.settings.value("PluginDatabase/ShowDSSI", True, type=bool))
  962. self.ch_lv2.setChecked(self.settings.value("PluginDatabase/ShowLV2", True, type=bool))
  963. self.ch_vst.setChecked(self.settings.value("PluginDatabase/ShowVST", True, type=bool))
  964. self.ch_kits.setChecked(self.settings.value("PluginDatabase/ShowKits", True, type=bool))
  965. self.ch_native.setChecked(self.settings.value("PluginDatabase/ShowNative", True, type=bool))
  966. self.ch_bridged.setChecked(self.settings.value("PluginDatabase/ShowBridged", True, type=bool))
  967. self.ch_bridged_wine.setChecked(self.settings.value("PluginDatabase/ShowBridgedWine", True, type=bool))
  968. self.ch_gui.setChecked(self.settings.value("PluginDatabase/ShowHasGUI", False, type=bool))
  969. self.ch_stereo.setChecked(self.settings.value("PluginDatabase/ShowStereoOnly", False, type=bool))
  970. self.reAddPlugins()
  971. def closeEvent(self, event):
  972. self.saveSettings()
  973. QDialog.closeEvent(self, event)
  974. def done(self, r):
  975. QDialog.done(self, r)
  976. self.close()
  977. # About Carla Dialog
  978. class CarlaAboutW(QDialog, ui_carla_about.Ui_CarlaAboutW):
  979. def __init__(self, parent=None):
  980. super(CarlaAboutW, self).__init__(parent)
  981. self.setupUi(self)
  982. self.l_about.setText(self.tr(""
  983. "<br>Version %s"
  984. "<br>Carla is a Multi-Plugin Host for JACK.<br>"
  985. "<br>Copyright (C) 2011-2012 falkTX<br>"
  986. "<br><i>VST is a trademark of Steinberg Media Technologies GmbH.</i>"
  987. "" % VERSION))
  988. host_osc_url = cString(CarlaHost.get_host_osc_url())
  989. self.le_osc_url.setText(host_osc_url)
  990. self.l_osc_cmds.setText(""
  991. " /set_active <i-value>\n"
  992. " /set_drywet <f-value>\n"
  993. " /set_vol <f-value>\n"
  994. " /set_balance_left <f-value>\n"
  995. " /set_balance_right <f-value>\n"
  996. " /set_parameter <i-index> <f-value>\n"
  997. " /set_program <i-index>\n"
  998. " /set_midi_program <i-index>\n"
  999. " /note_on <i-note> <i-velo>\n"
  1000. " /note_off <i-note> <i-velo>\n"
  1001. )
  1002. self.l_example.setText("/Carla/2/set_parameter_value 2 0.5")
  1003. self.l_example_help.setText("<i>(as in this example, \"2\" is the plugin number)</i>")
  1004. self.l_ladspa.setText(self.tr("Everything! (Including LRDF)"))
  1005. self.l_dssi.setText(self.tr("Everything! (Including CustomData/Chunks)"))
  1006. self.l_lv2.setText(self.tr("About 95&#37; complete (only missing minor features).<br/>"
  1007. "Implemented Feature/Extensions:"
  1008. "<ul>"
  1009. "<li>http://lv2plug.in/ns/ext/atom</li>"
  1010. "<li>http://lv2plug.in/ns/ext/data-access</li>"
  1011. "<li>http://lv2plug.in/ns/ext/event</li>"
  1012. "<li>http://lv2plug.in/ns/ext/instance-access</li>"
  1013. "<li>http://lv2plug.in/ns/ext/log</li>"
  1014. "<li>http://lv2plug.in/ns/ext/midi</li>"
  1015. #"<li>http://lv2plug.in/ns/ext/patch</li>"
  1016. "<li>http://lv2plug.in/ns/ext/port-props</li>"
  1017. #"<li>http://lv2plug.in/ns/ext/presets</li>"
  1018. "<li>http://lv2plug.in/ns/ext/state</li>"
  1019. #"<li>http://lv2plug.in/ns/ext/time</li>"
  1020. "<li>http://lv2plug.in/ns/ext/uri-map</li>"
  1021. "<li>http://lv2plug.in/ns/ext/urid</li>"
  1022. "<li>http://lv2plug.in/ns/ext/worker</li>"
  1023. "<li>http://lv2plug.in/ns/extensions/ui</li>"
  1024. "<li>http://lv2plug.in/ns/extensions/units</li>"
  1025. #"<li>http://home.gna.org/lv2dynparam/v1</li>"
  1026. "<li>http://home.gna.org/lv2dynparam/rtmempool/v1</li>"
  1027. "<li>http://kxstudio.sf.net/ns/lv2ext/programs</li>"
  1028. #"<li>http://ll-plugins.nongnu.org/lv2/ext/midimap</li>"
  1029. "<li>http://ll-plugins.nongnu.org/lv2/ext/miditype</li>"
  1030. "<li>http://nedko.arnaudov.name/lv2/external_ui/</li>"
  1031. "</ul>"))
  1032. self.l_vst.setText(self.tr("<p>About 85&#37; complete (missing vst bank/presets and some minor stuff)</p>"))
  1033. # Single Plugin Parameter
  1034. class PluginParameter(QWidget, ui_carla_parameter.Ui_PluginParameter):
  1035. def __init__(self, parent, pinfo, plugin_id):
  1036. QWidget.__init__(self, parent)
  1037. self.setupUi(self)
  1038. self.ptype = pinfo['type']
  1039. self.parameter_id = pinfo['index']
  1040. self.hints = pinfo['hints']
  1041. self.midi_cc = -1
  1042. self.midi_channel = 1
  1043. self.plugin_id = plugin_id
  1044. self.add_MIDI_CCs_to_ComboBox()
  1045. self.label.setText(pinfo['name'])
  1046. if (self.ptype == PARAMETER_INPUT):
  1047. self.widget.set_minimum(pinfo['minimum'])
  1048. self.widget.set_maximum(pinfo['maximum'])
  1049. self.widget.set_default(pinfo['default'])
  1050. self.widget.set_value(pinfo['current'], False)
  1051. self.widget.set_label(pinfo['unit'])
  1052. self.widget.set_step(pinfo['step'])
  1053. self.widget.set_step_small(pinfo['stepSmall'])
  1054. self.widget.set_step_large(pinfo['stepLarge'])
  1055. self.widget.set_scalepoints(pinfo['scalepoints'], (pinfo['hints'] & PARAMETER_USES_SCALEPOINTS))
  1056. if (not self.hints & PARAMETER_IS_ENABLED):
  1057. self.widget.set_read_only(True)
  1058. self.combo.setEnabled(False)
  1059. self.sb_channel.setEnabled(False)
  1060. elif (not self.hints & PARAMETER_IS_AUTOMABLE):
  1061. self.combo.setEnabled(False)
  1062. self.sb_channel.setEnabled(False)
  1063. elif (self.ptype == PARAMETER_OUTPUT):
  1064. self.widget.set_minimum(pinfo['minimum'])
  1065. self.widget.set_maximum(pinfo['maximum'])
  1066. self.widget.set_value(pinfo['current'], False)
  1067. self.widget.set_label(pinfo['unit'])
  1068. self.widget.set_read_only(True)
  1069. if (not self.hints & PARAMETER_IS_AUTOMABLE):
  1070. self.combo.setEnabled(False)
  1071. self.sb_channel.setEnabled(False)
  1072. else:
  1073. self.widget.setVisible(False)
  1074. self.combo.setVisible(False)
  1075. self.sb_channel.setVisible(False)
  1076. self.set_parameter_midi_channel(pinfo['midiChannel'])
  1077. self.set_parameter_midi_cc(pinfo['midiCC'])
  1078. self.connect(self.widget, SIGNAL("valueChanged(double)"), SLOT("slot_valueChanged(double)"))
  1079. self.connect(self.sb_channel, SIGNAL("valueChanged(int)"), SLOT("slot_midiChannelChanged(int)"))
  1080. self.connect(self.combo, SIGNAL("currentIndexChanged(int)"), SLOT("slot_midiCcChanged(int)"))
  1081. #if force_parameters_style:
  1082. #self.widget.force_plastique_style()
  1083. if (self.hints & PARAMETER_USES_CUSTOM_TEXT):
  1084. self.widget.set_text_call(self.textCallFunction)
  1085. self.widget.updateAll()
  1086. def set_default_value(self, value):
  1087. self.widget.set_default(value)
  1088. def set_parameter_value(self, value, send=True):
  1089. self.widget.set_value(value, send)
  1090. def set_parameter_midi_channel(self, channel):
  1091. self.midi_channel = channel
  1092. self.sb_channel.setValue(channel - 1)
  1093. def set_parameter_midi_cc(self, cc_index):
  1094. self.midi_cc = cc_index
  1095. self.set_MIDI_CC_in_ComboBox(cc_index)
  1096. def add_MIDI_CCs_to_ComboBox(self):
  1097. for MIDI_CC in MIDI_CC_LIST:
  1098. self.combo.addItem(MIDI_CC)
  1099. def set_MIDI_CC_in_ComboBox(self, midi_cc):
  1100. for i in range(len(MIDI_CC_LIST)):
  1101. midi_cc_text = MIDI_CC_LIST[i].split(" ")[0]
  1102. if (int(midi_cc_text, 16) == midi_cc):
  1103. cc_index = i
  1104. break
  1105. else:
  1106. cc_index = -1
  1107. cc_index += 1
  1108. self.combo.setCurrentIndex(cc_index)
  1109. def textCallFunction(self):
  1110. return cString(CarlaHost.get_parameter_text(self.plugin_id, self.parameter_id))
  1111. @pyqtSlot(float)
  1112. def slot_valueChanged(self, value):
  1113. self.emit(SIGNAL("valueChanged(int, double)"), self.parameter_id, value)
  1114. @pyqtSlot(int)
  1115. def slot_midiChannelChanged(self, channel):
  1116. if (self.midi_channel != channel):
  1117. self.emit(SIGNAL("midiChannelChanged(int, int)"), self.parameter_id, channel)
  1118. self.midi_channel = channel
  1119. @pyqtSlot(int)
  1120. def slot_midiCcChanged(self, cc_index):
  1121. if (cc_index <= 0):
  1122. midi_cc = -1
  1123. else:
  1124. midi_cc_text = MIDI_CC_LIST[cc_index - 1].split(" ")[0]
  1125. midi_cc = int(midi_cc_text, 16)
  1126. if (self.midi_cc != midi_cc):
  1127. self.emit(SIGNAL("midiCcChanged(int, int)"), self.parameter_id, midi_cc)
  1128. self.midi_cc = midi_cc
  1129. # Plugin GUI
  1130. class PluginGUI(QDialog):
  1131. def __init__(self, parent, plugin_name, resizable):
  1132. QDialog.__init__(self, parent)
  1133. self.myLayout = QVBoxLayout(self)
  1134. self.myLayout.setContentsMargins(0, 0, 0, 0)
  1135. self.setLayout(self.myLayout)
  1136. self.resizable = resizable
  1137. self.setNewSize(50, 50)
  1138. self.setWindowTitle("%s (GUI)" % (plugin_name))
  1139. def setNewSize(self, width, height):
  1140. if (width < 30):
  1141. width = 30
  1142. if (height < 30):
  1143. height = 30
  1144. if (self.resizable):
  1145. self.resize(width, height)
  1146. else:
  1147. self.setFixedSize(width, height)
  1148. def hideEvent(self, event):
  1149. # FIXME
  1150. event.accept()
  1151. self.close()
  1152. def done(self, r):
  1153. QDialog.done(self, r)
  1154. self.close()
  1155. # Plugin Editor (Built-in)
  1156. class PluginEdit(QDialog, ui_carla_edit.Ui_PluginEdit):
  1157. def __init__(self, parent, plugin_id):
  1158. QDialog.__init__(self, parent)
  1159. self.setupUi(self)
  1160. self.pinfo = None
  1161. self.ptype = PLUGIN_NONE
  1162. self.plugin_id = plugin_id
  1163. self.parameter_count = 0
  1164. self.parameter_list = [] # type, id, widget
  1165. self.parameter_list_to_update = [] # ids
  1166. self.state_filename = None
  1167. self.cur_program_index = -1
  1168. self.cur_midi_program_index = -1
  1169. self.tab_icon_off = QIcon(":/bitmaps/led_off.png")
  1170. self.tab_icon_on = QIcon(":/bitmaps/led_yellow.png")
  1171. self.tab_icon_count = 0
  1172. self.tab_icon_timers = []
  1173. self.connect(self.b_save_state, SIGNAL("clicked()"), SLOT("slot_saveState()"))
  1174. self.connect(self.b_load_state, SIGNAL("clicked()"), SLOT("slot_loadState()"))
  1175. self.connect(self.keyboard, SIGNAL("noteOn(int)"), SLOT("slot_noteOn(int)"))
  1176. self.connect(self.keyboard, SIGNAL("noteOff(int)"), SLOT("slot_noteOff(int)"))
  1177. self.connect(self.keyboard, SIGNAL("notesOn()"), SLOT("slot_notesOn()"))
  1178. self.connect(self.keyboard, SIGNAL("notesOff()"), SLOT("slot_notesOff()"))
  1179. self.connect(self.cb_programs, SIGNAL("currentIndexChanged(int)"), SLOT("slot_programIndexChanged(int)"))
  1180. self.connect(self.cb_midi_programs, SIGNAL("currentIndexChanged(int)"), SLOT("slot_midiProgramIndexChanged(int)"))
  1181. self.keyboard.setMode(self.keyboard.HORIZONTAL)
  1182. self.keyboard.setOctaves(6)
  1183. self.scrollArea.ensureVisible(self.keyboard.width() * 1 / 5, 0)
  1184. self.scrollArea.setVisible(False)
  1185. # TODO - not implemented yet
  1186. self.b_reload_program.setEnabled(False)
  1187. self.b_reload_midi_program.setEnabled(False)
  1188. self.do_reload_all()
  1189. def set_parameter_to_update(self, parameter_id):
  1190. if (parameter_id not in self.parameter_list_to_update):
  1191. self.parameter_list_to_update.append(parameter_id)
  1192. def set_parameter_midi_channel(self, parameter_id, channel):
  1193. for ptype, pid, pwidget in self.parameter_list:
  1194. if (pid == parameter_id):
  1195. pwidget.set_parameter_midi_channel(channel)
  1196. break
  1197. def set_parameter_midi_cc(self, parameter_id, midi_cc):
  1198. for ptype, pid, pwidget in self.parameter_list:
  1199. if (pid == parameter_id):
  1200. pwidget.set_parameter_midi_cc(midi_cc)
  1201. break
  1202. def set_program(self, program_id):
  1203. self.cur_program_index = program_id
  1204. self.cb_programs.setCurrentIndex(program_id)
  1205. QTimer.singleShot(0, self, SLOT("slot_checkInputControlParameters()"))
  1206. def set_midi_program(self, midi_program_id):
  1207. self.cur_midi_program_index = midi_program_id
  1208. self.cb_midi_programs.setCurrentIndex(midi_program_id)
  1209. QTimer.singleShot(0, self, SLOT("slot_checkInputControlParameters()"))
  1210. def do_update(self):
  1211. # Update current program text
  1212. if (self.cb_programs.count() > 0):
  1213. pindex = self.cb_programs.currentIndex()
  1214. pname = cString(CarlaHost.get_program_name(self.plugin_id, pindex))
  1215. self.cb_programs.setItemText(pindex, pname)
  1216. # Update current midi program text
  1217. if (self.cb_midi_programs.count() > 0):
  1218. mpindex = self.cb_midi_programs.currentIndex()
  1219. mpname = "%s %s" % (self.cb_midi_programs.currentText().split(" ", 1)[0], cString(CarlaHost.get_midi_program_name(self.plugin_id, mpindex)))
  1220. self.cb_midi_programs.setItemText(mpindex, mpname)
  1221. QTimer.singleShot(0, self, SLOT("slot_checkInputControlParameters()"))
  1222. QTimer.singleShot(0, self, SLOT("slot_checkOutputControlParameters()"))
  1223. def do_reload_all(self):
  1224. self.pinfo = CarlaHost.get_plugin_info(self.plugin_id)
  1225. if (self.pinfo['valid']):
  1226. self.pinfo["binary"] = cString(self.pinfo["binary"])
  1227. self.pinfo["name"] = cString(self.pinfo["name"])
  1228. self.pinfo["label"] = cString(self.pinfo["label"])
  1229. self.pinfo["maker"] = cString(self.pinfo["maker"])
  1230. self.pinfo["copyright"] = cString(self.pinfo["copyright"])
  1231. else:
  1232. self.pinfo["type"] = PLUGIN_NONE
  1233. self.pinfo["category"] = PLUGIN_CATEGORY_NONE
  1234. self.pinfo["hints"] = 0x0
  1235. self.pinfo["binary"] = ""
  1236. self.pinfo["name"] = "(Unknown)"
  1237. self.pinfo["label"] = ""
  1238. self.pinfo["maker"] = ""
  1239. self.pinfo["copyright"] = ""
  1240. self.pinfo["uniqueId"] = 0
  1241. self.do_reload_info()
  1242. self.do_reload_parameters()
  1243. self.do_reload_programs()
  1244. def do_reload_info(self):
  1245. if self.ptype == PLUGIN_NONE and self.pinfo['type'] in (PLUGIN_DSSI, PLUGIN_LV2, PLUGIN_GIG, PLUGIN_SF2, PLUGIN_SFZ):
  1246. self.tab_programs.setCurrentIndex(1)
  1247. self.ptype = self.pinfo['type']
  1248. real_plugin_name = cString(CarlaHost.get_real_plugin_name(self.plugin_id))
  1249. self.le_name.setText(real_plugin_name)
  1250. self.le_name.setToolTip(real_plugin_name)
  1251. self.le_label.setText(self.pinfo['label'])
  1252. self.le_label.setToolTip(self.pinfo['label'])
  1253. self.le_maker.setText(self.pinfo['maker'])
  1254. self.le_maker.setToolTip(self.pinfo['maker'])
  1255. self.le_copyright.setText(self.pinfo['copyright'])
  1256. self.le_copyright.setToolTip(self.pinfo['copyright'])
  1257. self.le_unique_id.setText(str(self.pinfo['uniqueId']))
  1258. self.le_unique_id.setToolTip(str(self.pinfo['uniqueId']))
  1259. self.label_plugin.setText("\n%s\n" % (self.pinfo['name']))
  1260. self.setWindowTitle(self.pinfo['name'])
  1261. if self.ptype == PLUGIN_LADSPA:
  1262. self.le_type.setText("LADSPA")
  1263. elif self.ptype == PLUGIN_DSSI:
  1264. self.le_type.setText("DSSI")
  1265. elif self.ptype == PLUGIN_LV2:
  1266. self.le_type.setText("LV2")
  1267. elif self.ptype == PLUGIN_VST:
  1268. self.le_type.setText("VST")
  1269. elif self.ptype == PLUGIN_GIG:
  1270. self.le_type.setText("GIG")
  1271. elif self.ptype == PLUGIN_SF2:
  1272. self.le_type.setText("SF2")
  1273. elif self.ptype == PLUGIN_SFZ:
  1274. self.le_type.setText("SFZ")
  1275. else:
  1276. self.le_type.setText(self.tr("Unknown"))
  1277. audio_count = CarlaHost.get_audio_port_count_info(self.plugin_id)
  1278. if (not audio_count['valid']):
  1279. audio_count['ins'] = 0
  1280. audio_count['outs'] = 0
  1281. audio_count['total'] = 0
  1282. midi_count = CarlaHost.get_midi_port_count_info(self.plugin_id)
  1283. if (not midi_count['valid']):
  1284. midi_count['ins'] = 0
  1285. midi_count['outs'] = 0
  1286. midi_count['total'] = 0
  1287. param_count = CarlaHost.get_parameter_count_info(self.plugin_id)
  1288. if (not param_count['valid']):
  1289. param_count['ins'] = 0
  1290. param_count['outs'] = 0
  1291. param_count['total'] = 0
  1292. self.le_ains.setText(str(audio_count['ins']))
  1293. self.le_aouts.setText(str(audio_count['outs']))
  1294. self.le_params.setText(str(param_count['ins']))
  1295. self.le_couts.setText(str(param_count['outs']))
  1296. self.le_is_synth.setText(self.tr("Yes") if (self.pinfo['hints'] & PLUGIN_IS_SYNTH) else (self.tr("No")))
  1297. self.le_has_gui.setText(self.tr("Yes") if (self.pinfo['hints'] & PLUGIN_HAS_GUI) else (self.tr("No")))
  1298. self.scrollArea.setVisible(self.pinfo['hints'] & PLUGIN_IS_SYNTH or (midi_count['ins'] > 0 < midi_count['outs']))
  1299. self.parent().recheck_hints(self.pinfo['hints'])
  1300. def do_reload_parameters(self):
  1301. parameters_count = CarlaHost.get_parameter_count(self.plugin_id)
  1302. self.parameter_list = []
  1303. self.parameter_list_to_update = []
  1304. self.tab_icon_count = 0
  1305. self.tab_icon_timers = []
  1306. for i in range(self.tabWidget.count()):
  1307. if (i == 0): continue
  1308. self.tabWidget.widget(1).deleteLater()
  1309. self.tabWidget.removeTab(1)
  1310. if (parameters_count <= 0):
  1311. pass
  1312. elif (parameters_count <= MAX_PARAMETERS):
  1313. p_in = []
  1314. p_in_tmp = []
  1315. p_in_index = 0
  1316. p_in_width = 0
  1317. p_out = []
  1318. p_out_tmp = []
  1319. p_out_index = 0
  1320. p_out_width = 0
  1321. for i in range(parameters_count):
  1322. param_info = CarlaHost.get_parameter_info(self.plugin_id, i)
  1323. param_data = CarlaHost.get_parameter_data(self.plugin_id, i)
  1324. param_ranges = CarlaHost.get_parameter_ranges(self.plugin_id, i)
  1325. if not param_info['valid']:
  1326. continue
  1327. parameter = {
  1328. 'type': param_data['type'],
  1329. 'hints': param_data['hints'],
  1330. 'name': cString(param_info['name']),
  1331. 'unit': cString(param_info['unit']),
  1332. 'scalepoints': [],
  1333. 'index': param_data['index'],
  1334. 'default': param_ranges['def'],
  1335. 'minimum': param_ranges['min'],
  1336. 'maximum': param_ranges['max'],
  1337. 'step': param_ranges['step'],
  1338. 'stepSmall': param_ranges['stepSmall'],
  1339. 'stepLarge': param_ranges['stepLarge'],
  1340. 'midiChannel': param_data['midiChannel'],
  1341. 'midiCC': param_data['midiCC'],
  1342. 'current': CarlaHost.get_current_parameter_value(self.plugin_id, i)
  1343. }
  1344. for j in range(param_info['scalePointCount']):
  1345. scalepoint = CarlaHost.get_scalepoint_info(self.plugin_id, i, j)
  1346. parameter['scalepoints'].append({
  1347. 'value': scalepoint['value'],
  1348. 'label': cString(scalepoint['label'])
  1349. })
  1350. # -----------------------------------------------------------------
  1351. # Get width values, in packs of 10
  1352. if (parameter['type'] == PARAMETER_INPUT):
  1353. p_in_tmp.append(parameter)
  1354. p_in_width_tmp = QFontMetrics(self.font()).width(parameter['name'])
  1355. if (p_in_width_tmp > p_in_width):
  1356. p_in_width = p_in_width_tmp
  1357. if (len(p_in_tmp) == 10):
  1358. p_in.append((p_in_tmp, p_in_width))
  1359. p_in_tmp = []
  1360. p_in_index = 0
  1361. p_in_width = 0
  1362. else:
  1363. p_in_index += 1
  1364. elif (parameter['type'] == PARAMETER_OUTPUT):
  1365. p_out_tmp.append(parameter)
  1366. p_out_width_tmp = QFontMetrics(self.font()).width(parameter['name'])
  1367. if (p_out_width_tmp > p_out_width):
  1368. p_out_width = p_out_width_tmp
  1369. if (len(p_out_tmp) == 10):
  1370. p_out.append((p_out_tmp, p_out_width))
  1371. p_out_tmp = []
  1372. p_out_index = 0
  1373. p_out_width = 0
  1374. else:
  1375. p_out_index += 1
  1376. else:
  1377. # Final page width values
  1378. if (0 < len(p_in_tmp) < 10):
  1379. p_in.append((p_in_tmp, p_in_width))
  1380. if (0 < len(p_out_tmp) < 10):
  1381. p_out.append((p_out_tmp, p_out_width))
  1382. # -----------------------------------------------------------------
  1383. # Create parameter widgets
  1384. if (len(p_in) > 0):
  1385. self.createParameterWidgets(p_in, self.tr("Parameters"), PARAMETER_INPUT)
  1386. if (len(p_out) > 0):
  1387. self.createParameterWidgets(p_out, self.tr("Outputs"), PARAMETER_OUTPUT)
  1388. else: # > MAX_PARAMETERS
  1389. fake_name = "This plugin has too many parameters to display here!"
  1390. p_fake = []
  1391. p_fake_tmp = []
  1392. p_fake_width = QFontMetrics(self.font()).width(fake_name)
  1393. parameter = {
  1394. 'type': PARAMETER_UNKNOWN,
  1395. 'hints': 0,
  1396. 'name': fake_name,
  1397. 'unit': "",
  1398. 'scalepoints': [],
  1399. 'index': 0,
  1400. 'default': 0,
  1401. 'minimum': 0,
  1402. 'maximum': 0,
  1403. 'step': 0,
  1404. 'stepSmall': 0,
  1405. 'stepLarge': 0,
  1406. 'midiChannel': 0,
  1407. 'midiCC': -1,
  1408. 'current': 0.0
  1409. }
  1410. p_fake_tmp.append(parameter)
  1411. p_fake.append((p_fake_tmp, p_fake_width))
  1412. self.createParameterWidgets(p_fake, self.tr("Information"), PARAMETER_UNKNOWN)
  1413. def do_reload_programs(self):
  1414. # Programs
  1415. self.cb_programs.blockSignals(True)
  1416. self.cb_programs.clear()
  1417. program_count = CarlaHost.get_program_count(self.plugin_id)
  1418. if (program_count > 0):
  1419. self.cb_programs.setEnabled(True)
  1420. for i in range(program_count):
  1421. pname = cString(CarlaHost.get_program_name(self.plugin_id, i))
  1422. self.cb_programs.addItem(pname)
  1423. self.cur_program_index = CarlaHost.get_current_program_index(self.plugin_id)
  1424. self.cb_programs.setCurrentIndex(self.cur_program_index)
  1425. else:
  1426. self.cb_programs.setEnabled(False)
  1427. self.cb_programs.blockSignals(False)
  1428. # MIDI Programs
  1429. self.cb_midi_programs.blockSignals(True)
  1430. self.cb_midi_programs.clear()
  1431. midi_program_count = CarlaHost.get_midi_program_count(self.plugin_id)
  1432. if (midi_program_count > 0):
  1433. self.cb_midi_programs.setEnabled(True)
  1434. for i in range(midi_program_count):
  1435. midip = CarlaHost.get_midi_program_info(self.plugin_id, i)
  1436. bank = int(midip['bank'])
  1437. prog = int(midip['program'])
  1438. label = cString(midip['label'])
  1439. self.cb_midi_programs.addItem("%03i:%03i - %s" % (bank, prog, label))
  1440. self.cur_midi_program_index = CarlaHost.get_current_midi_program_index(self.plugin_id)
  1441. self.cb_midi_programs.setCurrentIndex(self.cur_midi_program_index)
  1442. else:
  1443. self.cb_midi_programs.setEnabled(False)
  1444. self.cb_midi_programs.blockSignals(False)
  1445. def saveState_InternalFormat(self):
  1446. content = ("<?xml version='1.0' encoding='UTF-8'?>\n"
  1447. "<!DOCTYPE CARLA-PRESET>\n"
  1448. "<CARLA-PRESET VERSION='%s'>\n") % (VERSION)
  1449. content += self.parent().getSaveXMLContent()
  1450. content += "</CARLA-PRESET>\n"
  1451. try:
  1452. open(self.state_filename, "w").write(content)
  1453. except:
  1454. QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to save state file"))
  1455. def saveState_Lv2Format(self):
  1456. pass
  1457. def saveState_VstFormat(self):
  1458. pass
  1459. def loadState_InternalFormat(self):
  1460. try:
  1461. state_read = open(self.state_filename, "r").read()
  1462. except:
  1463. QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to load state file"))
  1464. return
  1465. xml = QDomDocument()
  1466. xml.setContent(state_read)
  1467. xml_node = xml.documentElement()
  1468. if (xml_node.tagName() != "CARLA-PRESET"):
  1469. QMessageBox.critical(self, self.tr("Error"), self.tr("Not a valid Carla state file"))
  1470. return
  1471. x_save_state_dict = getStateDictFromXML(xml_node)
  1472. self.parent().loadStateDict(x_save_state_dict)
  1473. def createParameterWidgets(self, p_list_full, tab_name, ptype):
  1474. for i in range(len(p_list_full)):
  1475. p_list = p_list_full[i][0]
  1476. width = p_list_full[i][1]
  1477. if (len(p_list) > 0):
  1478. container = QWidget(self.tabWidget)
  1479. layout = QVBoxLayout(container)
  1480. container.setLayout(layout)
  1481. for j in range(len(p_list)):
  1482. pwidget = PluginParameter(container, p_list[j], self.plugin_id)
  1483. pwidget.label.setMinimumWidth(width)
  1484. pwidget.label.setMaximumWidth(width)
  1485. pwidget.tab_index = self.tabWidget.count()
  1486. layout.addWidget(pwidget)
  1487. self.parameter_list.append((ptype, p_list[j]['index'], pwidget))
  1488. if (ptype == PARAMETER_INPUT):
  1489. self.connect(pwidget, SIGNAL("valueChanged(int, double)"), SLOT("slot_parameterValueChanged(int, double)"))
  1490. self.connect(pwidget, SIGNAL("midiChannelChanged(int, int)"), SLOT("slot_parameterMidiChannelChanged(int, int)"))
  1491. self.connect(pwidget, SIGNAL("midiCcChanged(int, int)"), SLOT("slot_parameterMidiCcChanged(int, int)"))
  1492. # FIXME
  1493. layout.addStretch()
  1494. self.tabWidget.addTab(container, "%s (%i)" % (tab_name, i + 1))
  1495. if (ptype == PARAMETER_INPUT):
  1496. self.tabWidget.setTabIcon(pwidget.tab_index, self.tab_icon_off)
  1497. self.tab_icon_timers.append(ICON_STATE_NULL)
  1498. def animateTab(self, index):
  1499. if (self.tab_icon_timers[index - 1] == ICON_STATE_NULL):
  1500. self.tabWidget.setTabIcon(index, self.tab_icon_on)
  1501. self.tab_icon_timers[index - 1] = ICON_STATE_ON
  1502. def check_gui_stuff(self):
  1503. # Check Tab icons
  1504. for i in range(len(self.tab_icon_timers)):
  1505. if (self.tab_icon_timers[i] == ICON_STATE_ON):
  1506. self.tab_icon_timers[i] = ICON_STATE_WAIT
  1507. elif (self.tab_icon_timers[i] == ICON_STATE_WAIT):
  1508. self.tab_icon_timers[i] = ICON_STATE_OFF
  1509. elif (self.tab_icon_timers[i] == ICON_STATE_OFF):
  1510. self.tabWidget.setTabIcon(i + 1, self.tab_icon_off)
  1511. self.tab_icon_timers[i] = ICON_STATE_NULL
  1512. # Check parameters needing update
  1513. for parameter_id in self.parameter_list_to_update:
  1514. value = CarlaHost.get_current_parameter_value(self.plugin_id, parameter_id)
  1515. for ptype, pid, pwidget in self.parameter_list:
  1516. if (pid == parameter_id):
  1517. pwidget.set_parameter_value(value, False)
  1518. if (ptype == PARAMETER_INPUT):
  1519. self.animateTab(pwidget.tab_index)
  1520. break
  1521. # Clear all parameters
  1522. self.parameter_list_to_update = []
  1523. # Update output parameters
  1524. QTimer.singleShot(0, self, SLOT("slot_checkOutputControlParameters()"))
  1525. @pyqtSlot()
  1526. def slot_saveState(self):
  1527. # TODO - LV2 and VST native formats
  1528. if (self.state_filename):
  1529. ask_try = QMessageBox.question(self, self.tr("Overwrite?"), self.tr("Overwrite previously created file?"), QMessageBox.Ok|QMessageBox.Cancel)
  1530. if (ask_try == QMessageBox.Ok):
  1531. self.saveState_InternalFormat()
  1532. else:
  1533. self.state_filename = None
  1534. self.slot_saveState()
  1535. else:
  1536. file_filter = self.tr("Carla State File (*.carxs)")
  1537. filename_try = QFileDialog.getSaveFileName(self, self.tr("Save Carla State File"), filter=file_filter)
  1538. if (filename_try):
  1539. self.state_filename = filename_try
  1540. self.saveState_InternalFormat()
  1541. @pyqtSlot()
  1542. def slot_loadState(self):
  1543. # TODO - LV2 and VST native formats
  1544. file_filter = self.tr("Carla State File (*.carxs)")
  1545. filename_try = QFileDialog.getOpenFileName(self, self.tr("Open Carla State File"), filter=file_filter)
  1546. if (filename_try):
  1547. self.state_filename = filename_try
  1548. self.loadState_InternalFormat()
  1549. @pyqtSlot(int, float)
  1550. def slot_parameterValueChanged(self, parameter_id, value):
  1551. CarlaHost.set_parameter_value(self.plugin_id, parameter_id, value)
  1552. @pyqtSlot(int, int)
  1553. def slot_parameterMidiChannelChanged(self, parameter_id, channel):
  1554. CarlaHost.set_parameter_midi_channel(self.plugin_id, parameter_id, channel - 1)
  1555. @pyqtSlot(int, int)
  1556. def slot_parameterMidiCcChanged(self, parameter_id, cc_index):
  1557. CarlaHost.set_parameter_midi_cc(self.plugin_id, parameter_id, cc_index)
  1558. @pyqtSlot(int)
  1559. def slot_programIndexChanged(self, index):
  1560. if (self.cur_program_index != index):
  1561. CarlaHost.set_program(self.plugin_id, index)
  1562. QTimer.singleShot(0, self, SLOT("slot_checkInputControlParameters()"))
  1563. self.cur_program_index = index
  1564. @pyqtSlot(int)
  1565. def slot_midiProgramIndexChanged(self, index):
  1566. if (self.cur_midi_program_index != index):
  1567. CarlaHost.set_midi_program(self.plugin_id, index)
  1568. QTimer.singleShot(0, self, SLOT("slot_checkInputControlParameters()"))
  1569. self.cur_midi_program_index = index
  1570. @pyqtSlot(int)
  1571. def slot_noteOn(self, note):
  1572. CarlaHost.send_midi_note(self.plugin_id, note, 100)
  1573. @pyqtSlot(int)
  1574. def slot_noteOff(self, note):
  1575. CarlaHost.send_midi_note(self.plugin_id, note, 0)
  1576. @pyqtSlot()
  1577. def slot_notesOn(self):
  1578. self.parent().led_midi.setChecked(True)
  1579. @pyqtSlot()
  1580. def slot_notesOff(self):
  1581. self.parent().led_midi.setChecked(False)
  1582. @pyqtSlot()
  1583. def slot_checkInputControlParameters(self):
  1584. for ptype, pid, pwidget in self.parameter_list:
  1585. if ptype == PARAMETER_INPUT:
  1586. if self.pinfo["type"] not in (PLUGIN_GIG, PLUGIN_SF2, PLUGIN_SFZ):
  1587. pwidget.set_default_value(CarlaHost.get_default_parameter_value(self.plugin_id, pid))
  1588. pwidget.set_parameter_value(CarlaHost.get_current_parameter_value(self.plugin_id, pid), False)
  1589. @pyqtSlot()
  1590. def slot_checkOutputControlParameters(self):
  1591. for ptype, pid, pwidget in self.parameter_list:
  1592. if (ptype == PARAMETER_OUTPUT):
  1593. pwidget.set_parameter_value(CarlaHost.get_current_parameter_value(self.plugin_id, pid), False)
  1594. # (New) Plugin Widget
  1595. class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget):
  1596. def __init__(self, parent, plugin_id):
  1597. QFrame.__init__(self, parent)
  1598. self.setupUi(self)
  1599. self.plugin_id = plugin_id
  1600. self.params_total = 0
  1601. self.parameter_activity_timer = None
  1602. self.last_led_ain_state = False
  1603. self.last_led_aout_state = False
  1604. # Fake effect
  1605. self.color_1 = QColor(0, 0, 0, 220)
  1606. self.color_2 = QColor(0, 0, 0, 170)
  1607. self.color_3 = QColor(7, 7, 7, 250)
  1608. self.color_4 = QColor(14, 14, 14, 255)
  1609. self.led_enable.setColor(self.led_enable.BIG_RED)
  1610. self.led_enable.setChecked(False)
  1611. self.led_control.setColor(self.led_control.YELLOW)
  1612. self.led_control.setEnabled(False)
  1613. self.led_midi.setColor(self.led_midi.RED)
  1614. self.led_midi.setEnabled(False)
  1615. self.led_audio_in.setColor(self.led_audio_in.GREEN)
  1616. self.led_audio_in.setEnabled(False)
  1617. self.led_audio_out.setColor(self.led_audio_out.BLUE)
  1618. self.led_audio_out.setEnabled(False)
  1619. self.dial_drywet.setPixmap(3)
  1620. self.dial_vol.setPixmap(3)
  1621. self.dial_b_left.setPixmap(4)
  1622. self.dial_b_right.setPixmap(4)
  1623. #self.dial_drywet.setLabel("Wet")
  1624. #self.dial_vol.setLabel("Vol")
  1625. #self.dial_b_left.setLabel("L")
  1626. #self.dial_b_right.setLabel("R")
  1627. self.dial_drywet.setCustomPaint(self.dial_b_left.CUSTOM_PAINT_CARLA_WET)
  1628. self.dial_vol.setCustomPaint(self.dial_b_right.CUSTOM_PAINT_CARLA_VOL)
  1629. self.dial_b_left.setCustomPaint(self.dial_b_left.CUSTOM_PAINT_CARLA_L)
  1630. self.dial_b_right.setCustomPaint(self.dial_b_right.CUSTOM_PAINT_CARLA_R)
  1631. self.peak_in.setColor(self.peak_in.GREEN)
  1632. self.peak_in.setOrientation(self.peak_in.HORIZONTAL)
  1633. self.peak_out.setColor(self.peak_in.BLUE)
  1634. self.peak_out.setOrientation(self.peak_out.HORIZONTAL)
  1635. audio_count = CarlaHost.get_audio_port_count_info(self.plugin_id)
  1636. if not audio_count['valid']:
  1637. audio_count['ins'] = 0
  1638. audio_count['outs'] = 0
  1639. audio_count['total'] = 0
  1640. midi_count = CarlaHost.get_midi_port_count_info(self.plugin_id)
  1641. if not midi_count['valid']:
  1642. midi_count['ins'] = 0
  1643. midi_count['outs'] = 0
  1644. midi_count['total'] = 0
  1645. self.peaks_in = int(audio_count['ins'])
  1646. self.peaks_out = int(audio_count['outs'])
  1647. if self.peaks_in > 2:
  1648. self.peaks_in = 2
  1649. if self.peaks_out > 2:
  1650. self.peaks_out = 2
  1651. self.peak_in.setChannels(self.peaks_in)
  1652. self.peak_out.setChannels(self.peaks_out)
  1653. self.pinfo = CarlaHost.get_plugin_info(self.plugin_id)
  1654. if self.pinfo['valid']:
  1655. self.pinfo["binary"] = cString(self.pinfo["binary"])
  1656. self.pinfo["name"] = cString(self.pinfo["name"])
  1657. self.pinfo["label"] = cString(self.pinfo["label"])
  1658. self.pinfo["maker"] = cString(self.pinfo["maker"])
  1659. self.pinfo["copyright"] = cString(self.pinfo["copyright"])
  1660. else:
  1661. self.pinfo["type"] = PLUGIN_NONE
  1662. self.pinfo["category"] = PLUGIN_CATEGORY_NONE
  1663. self.pinfo["hints"] = 0
  1664. self.pinfo["binary"] = ""
  1665. self.pinfo["name"] = "(Unknown)"
  1666. self.pinfo["label"] = ""
  1667. self.pinfo["maker"] = ""
  1668. self.pinfo["copyright"] = ""
  1669. self.pinfo["uniqueId"] = 0
  1670. # Set widget page
  1671. if self.pinfo['type'] == PLUGIN_NONE or audio_count['total'] == 0:
  1672. self.stackedWidget.setCurrentIndex(1)
  1673. else:
  1674. self.stackedWidget.setCurrentIndex(0)
  1675. self.label_name.setText(self.pinfo['name'])
  1676. # Enable/disable features
  1677. self.recheck_hints(self.pinfo['hints'])
  1678. # Colorify
  1679. if (self.pinfo['category'] == PLUGIN_CATEGORY_SYNTH):
  1680. self.setWidgetColor(PALETTE_COLOR_WHITE)
  1681. elif (self.pinfo['category'] == PLUGIN_CATEGORY_DELAY):
  1682. self.setWidgetColor(PALETTE_COLOR_ORANGE)
  1683. elif (self.pinfo['category'] == PLUGIN_CATEGORY_EQ):
  1684. self.setWidgetColor(PALETTE_COLOR_GREEN)
  1685. elif (self.pinfo['category'] == PLUGIN_CATEGORY_FILTER):
  1686. self.setWidgetColor(PALETTE_COLOR_BLUE)
  1687. elif (self.pinfo['category'] == PLUGIN_CATEGORY_DYNAMICS):
  1688. self.setWidgetColor(PALETTE_COLOR_PINK)
  1689. elif (self.pinfo['category'] == PLUGIN_CATEGORY_MODULATOR):
  1690. self.setWidgetColor(PALETTE_COLOR_RED)
  1691. elif (self.pinfo['category'] == PLUGIN_CATEGORY_UTILITY):
  1692. self.setWidgetColor(PALETTE_COLOR_YELLOW)
  1693. elif (self.pinfo['category'] == PLUGIN_CATEGORY_OTHER):
  1694. self.setWidgetColor(PALETTE_COLOR_BROWN)
  1695. else:
  1696. self.setWidgetColor(PALETTE_COLOR_NONE)
  1697. if (self.pinfo['hints'] & PLUGIN_IS_SYNTH) > 0 or (midi_count['ins'] > 0 < midi_count['outs']):
  1698. self.led_audio_in.setVisible(False)
  1699. else:
  1700. self.led_midi.setVisible(False)
  1701. self.edit_dialog = PluginEdit(self, self.plugin_id)
  1702. self.edit_dialog.hide()
  1703. self.edit_dialog_geometry = None
  1704. if self.pinfo['hints'] & PLUGIN_HAS_GUI:
  1705. gui_info = CarlaHost.get_gui_info(self.plugin_id)
  1706. self.gui_dialog_type = gui_info['type']
  1707. if (self.gui_dialog_type in (GUI_INTERNAL_QT4, GUI_INTERNAL_HWND, GUI_INTERNAL_X11)):
  1708. self.gui_dialog = None
  1709. self.gui_dialog = PluginGUI(self, self.pinfo['name'], gui_info['resizable'])
  1710. self.gui_dialog.hide()
  1711. self.gui_dialog_geometry = None
  1712. self.connect(self.gui_dialog, SIGNAL("finished(int)"), SLOT("slot_guiClosed()"))
  1713. # TODO - display
  1714. CarlaHost.set_gui_data(self.plugin_id, 0, unwrapinstance(self.gui_dialog))
  1715. elif self.gui_dialog_type in (GUI_EXTERNAL_OSC, GUI_EXTERNAL_LV2):
  1716. self.gui_dialog = None
  1717. else:
  1718. self.gui_dialog = None
  1719. self.gui_dialog_type = GUI_NONE
  1720. self.b_gui.setEnabled(False)
  1721. else:
  1722. self.gui_dialog = None
  1723. self.gui_dialog_type = GUI_NONE
  1724. self.connect(self.led_enable, SIGNAL("clicked(bool)"), SLOT("slot_setActive(bool)"))
  1725. self.connect(self.dial_drywet, SIGNAL("sliderMoved(int)"), SLOT("slot_setDryWet(int)"))
  1726. self.connect(self.dial_vol, SIGNAL("sliderMoved(int)"), SLOT("slot_setVolume(int)"))
  1727. self.connect(self.dial_b_left, SIGNAL("sliderMoved(int)"), SLOT("slot_setBalanceLeft(int)"))
  1728. self.connect(self.dial_b_right, SIGNAL("sliderMoved(int)"), SLOT("slot_setBalanceRight(int)"))
  1729. self.connect(self.b_gui, SIGNAL("clicked(bool)"), SLOT("slot_guiClicked(bool)"))
  1730. self.connect(self.b_edit, SIGNAL("clicked(bool)"), SLOT("slot_editClicked(bool)"))
  1731. self.connect(self.b_remove, SIGNAL("clicked()"), SLOT("slot_removeClicked()"))
  1732. self.connect(self.dial_drywet, SIGNAL("customContextMenuRequested(QPoint)"), SLOT("slot_showCustomDialMenu()"))
  1733. self.connect(self.dial_vol, SIGNAL("customContextMenuRequested(QPoint)"), SLOT("slot_showCustomDialMenu()"))
  1734. self.connect(self.dial_b_left, SIGNAL("customContextMenuRequested(QPoint)"), SLOT("slot_showCustomDialMenu()"))
  1735. self.connect(self.dial_b_right, SIGNAL("customContextMenuRequested(QPoint)"), SLOT("slot_showCustomDialMenu()"))
  1736. self.connect(self.edit_dialog, SIGNAL("finished(int)"), SLOT("slot_editClosed()"))
  1737. self.check_gui_stuff()
  1738. def set_active(self, active, gui_send=False, callback_send=True):
  1739. if gui_send: self.led_enable.setChecked(active)
  1740. if callback_send: CarlaHost.set_active(self.plugin_id, active)
  1741. def set_drywet(self, value, gui_send=False, callback_send=True):
  1742. if gui_send: self.dial_drywet.setValue(value)
  1743. if callback_send: CarlaHost.set_drywet(self.plugin_id, float(value) / 1000)
  1744. message = self.tr("Output dry/wet (%s%%)" % (value / 10))
  1745. self.dial_drywet.setStatusTip(message)
  1746. gui.statusBar().showMessage(message)
  1747. def set_volume(self, value, gui_send=False, callback_send=True):
  1748. if gui_send: self.dial_vol.setValue(value)
  1749. if callback_send: CarlaHost.set_volume(self.plugin_id, float(value) / 1000)
  1750. message = self.tr("Output volume (%s%%)" % (value / 10))
  1751. self.dial_vol.setStatusTip(message)
  1752. gui.statusBar().showMessage(message)
  1753. def set_balance_left(self, value, gui_send=False, callback_send=True):
  1754. if gui_send: self.dial_b_left.setValue(value)
  1755. if callback_send: CarlaHost.set_balance_left(self.plugin_id, float(value) / 1000)
  1756. if value == 0:
  1757. message = self.tr("Left Panning (Center)")
  1758. elif value < 0:
  1759. message = self.tr("Left Panning (%s%% Left)" % (-value / 10))
  1760. else:
  1761. message = self.tr("Left Panning (%s%% Right)" % (value / 10))
  1762. self.dial_b_left.setStatusTip(message)
  1763. gui.statusBar().showMessage(message)
  1764. def set_balance_right(self, value, gui_send=False, callback_send=True):
  1765. if gui_send: self.dial_b_right.setValue(value)
  1766. if callback_send: CarlaHost.set_balance_right(self.plugin_id, float(value) / 1000)
  1767. if value == 0:
  1768. message = self.tr("Right Panning (Center)")
  1769. elif value < 0:
  1770. message = self.tr("Right Panning (%s%% Left)" % (-value / 10))
  1771. else:
  1772. message = self.tr("Right Panning (%s%% Right)" % (value / 10))
  1773. self.dial_b_right.setStatusTip(message)
  1774. gui.statusBar().showMessage(message)
  1775. def setWidgetColor(self, color):
  1776. if (color == PALETTE_COLOR_WHITE):
  1777. r = 110
  1778. g = 110
  1779. b = 110
  1780. elif (color == PALETTE_COLOR_RED):
  1781. r = 110
  1782. g = 15
  1783. b = 15
  1784. elif (color == PALETTE_COLOR_GREEN):
  1785. r = 15
  1786. g = 110
  1787. b = 15
  1788. elif (color == PALETTE_COLOR_BLUE):
  1789. r = 15
  1790. g = 15
  1791. b = 110
  1792. elif (color == PALETTE_COLOR_YELLOW):
  1793. r = 110
  1794. g = 110
  1795. b = 15
  1796. elif (color == PALETTE_COLOR_ORANGE):
  1797. r = 180
  1798. g = 110
  1799. b = 15
  1800. elif (color == PALETTE_COLOR_BROWN):
  1801. r = 110
  1802. g = 35
  1803. b = 15
  1804. elif (color == PALETTE_COLOR_PINK):
  1805. r = 110
  1806. g = 15
  1807. b = 110
  1808. else:
  1809. r = 35
  1810. g = 35
  1811. b = 35
  1812. border_r = (r*2/3)+36
  1813. border_g = (g*2/3)+36
  1814. border_b = (b*2/3)+36
  1815. self.setStyleSheet("""
  1816. QFrame#PluginWidget {
  1817. background-image: url(:/bitmaps/textures/metal_9-512px.jpg);
  1818. background-color: rgb(17, 17, 17);
  1819. background-repeat: repeat-x;
  1820. background-position: top left;
  1821. }
  1822. QLabel#label_name {
  1823. color: white;
  1824. }
  1825. QWidget#widget_buttons {
  1826. background-color: rgb(%i, %i, %i);
  1827. border-left: 1px solid rgb(%i, %i, %i);
  1828. border-right: 1px solid rgb(%i, %i, %i);
  1829. border-bottom: 1px solid rgb(%i, %i, %i);
  1830. border-bottom-left-radius: 3px;
  1831. border-bottom-right-radius: 3px;
  1832. }
  1833. QPushButton#b_gui:hover, QPushButton#b_edit:hover, QPushButton#b_remove:hover {
  1834. background-color: rgb(%i, %i, %i);
  1835. border: 1px solid rgb(%i, %i, %i);
  1836. border-radius: 3px;
  1837. }
  1838. QFrame#frame_name {
  1839. background-color: rgb(%i, %i, %i);
  1840. border: 1px solid rgb(%i, %i, %i);
  1841. border-radius: 4px;
  1842. }
  1843. QFrame#frame_controls {
  1844. background-image: url(:/bitmaps/carla_knobs1.png);
  1845. background-color: rgb(35, 35, 35);
  1846. border: 1px solid rgb(35, 35, 35);
  1847. border-radius: 4px;
  1848. }
  1849. QFrame#frame_peaks {
  1850. background-color: rgb(35, 35, 35);
  1851. border: 1px solid rgb(35, 35, 35);
  1852. border-radius: 4px;
  1853. }
  1854. """ % (border_r, border_g, border_b,
  1855. border_r, border_g, border_b,
  1856. border_r, border_g, border_b,
  1857. border_r, border_g, border_b,
  1858. r, g, b,
  1859. border_r, border_g, border_b,
  1860. r, g, b, # frame_name background-color
  1861. border_r, border_g, border_b # frame_name border
  1862. ))
  1863. def recheck_hints(self, hints):
  1864. self.pinfo['hints'] = hints
  1865. self.dial_drywet.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_DRYWET)
  1866. self.dial_vol.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_VOLUME)
  1867. self.dial_b_left.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_BALANCE)
  1868. self.dial_b_right.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_BALANCE)
  1869. self.b_gui.setEnabled(self.pinfo['hints'] & PLUGIN_HAS_GUI)
  1870. def getSaveXMLContent(self):
  1871. CarlaHost.prepare_for_save(self.plugin_id)
  1872. if self.pinfo['type'] == PLUGIN_LADSPA:
  1873. type_str = "LADSPA"
  1874. elif self.pinfo['type'] == PLUGIN_DSSI:
  1875. type_str = "DSSI"
  1876. elif self.pinfo['type'] == PLUGIN_LV2:
  1877. type_str = "LV2"
  1878. elif self.pinfo['type'] == PLUGIN_VST:
  1879. type_str = "VST"
  1880. elif self.pinfo['type'] == PLUGIN_GIG:
  1881. type_str = "GIG"
  1882. elif self.pinfo['type'] == PLUGIN_SF2:
  1883. type_str = "SF2"
  1884. elif self.pinfo['type'] == PLUGIN_SFZ:
  1885. type_str = "SFZ"
  1886. else:
  1887. type_str = "Unknown"
  1888. x_save_state_dict = deepcopy(save_state_dict)
  1889. # ----------------------------
  1890. # Basic info
  1891. x_save_state_dict['Type'] = type_str
  1892. x_save_state_dict['Name'] = self.pinfo['name']
  1893. x_save_state_dict['Label'] = self.pinfo['label']
  1894. x_save_state_dict['Binary'] = self.pinfo['binary']
  1895. x_save_state_dict['UniqueID'] = self.pinfo['uniqueId']
  1896. # ----------------------------
  1897. # Internals
  1898. x_save_state_dict['Active'] = self.led_enable.isChecked()
  1899. x_save_state_dict['DryWet'] = float(self.dial_drywet.value()) / 1000
  1900. x_save_state_dict['Volume'] = float(self.dial_vol.value()) / 1000
  1901. x_save_state_dict['Balance-Left'] = float(self.dial_b_left.value()) / 1000
  1902. x_save_state_dict['Balance-Right'] = float(self.dial_b_right.value()) / 1000
  1903. # ----------------------------
  1904. # Current Program
  1905. if (self.edit_dialog.cb_programs.currentIndex() >= 0):
  1906. x_save_state_dict['CurrentProgramIndex'] = self.edit_dialog.cb_programs.currentIndex()
  1907. x_save_state_dict['CurrentProgramName'] = self.edit_dialog.cb_programs.currentText()
  1908. # ----------------------------
  1909. # Current MIDI Program
  1910. if (self.edit_dialog.cb_midi_programs.currentIndex() >= 0):
  1911. midi_program_info = CarlaHost.get_midi_program_info(self.plugin_id, self.edit_dialog.cb_midi_programs.currentIndex())
  1912. x_save_state_dict['CurrentMidiBank'] = midi_program_info['bank']
  1913. x_save_state_dict['CurrentMidiProgram'] = midi_program_info['program']
  1914. # ----------------------------
  1915. # Parameters
  1916. parameter_count = CarlaHost.get_parameter_count(self.plugin_id)
  1917. for i in range(parameter_count):
  1918. parameter_info = CarlaHost.get_parameter_info(self.plugin_id, i)
  1919. parameter_data = CarlaHost.get_parameter_data(self.plugin_id, i)
  1920. if (not parameter_info['valid']) or parameter_data['type'] != PARAMETER_INPUT:
  1921. continue
  1922. x_save_state_parameter = deepcopy(save_state_parameter)
  1923. x_save_state_parameter['index'] = parameter_data['index']
  1924. x_save_state_parameter['name'] = cString(parameter_info['name'])
  1925. x_save_state_parameter['symbol'] = cString(parameter_info['symbol'])
  1926. x_save_state_parameter['value'] = CarlaHost.get_current_parameter_value(self.plugin_id, parameter_data['index'])
  1927. x_save_state_parameter['midiChannel'] = parameter_data['midiChannel'] + 1
  1928. x_save_state_parameter['midiCC'] = parameter_data['midiCC']
  1929. if (parameter_data['hints'] & PARAMETER_USES_SAMPLERATE):
  1930. x_save_state_parameter['value'] /= CarlaHost.get_sample_rate()
  1931. x_save_state_dict['Parameters'].append(x_save_state_parameter)
  1932. # ----------------------------
  1933. # Custom Data
  1934. custom_data_count = CarlaHost.get_custom_data_count(self.plugin_id)
  1935. for i in range(custom_data_count):
  1936. custom_data = CarlaHost.get_custom_data(self.plugin_id, i)
  1937. if custom_data['type'] == CUSTOM_DATA_INVALID:
  1938. continue
  1939. x_save_state_custom_data = deepcopy(save_state_custom_data)
  1940. x_save_state_custom_data['type'] = CustomDataType2String(custom_data['type'])
  1941. x_save_state_custom_data['key'] = cString(custom_data['key'])
  1942. x_save_state_custom_data['value'] = cString(custom_data['value'])
  1943. x_save_state_dict['CustomData'].append(x_save_state_custom_data)
  1944. # ----------------------------
  1945. # Chunk
  1946. if self.pinfo['hints'] & PLUGIN_USES_CHUNKS:
  1947. x_save_state_dict['Chunk'] = cString(CarlaHost.get_chunk_data(self.plugin_id))
  1948. # ----------------------------
  1949. # Generate XML for this plugin
  1950. content = ""
  1951. content += " <Info>\n"
  1952. content += " <Type>%s</Type>\n" % x_save_state_dict['Type']
  1953. content += " <Name>%s</Name>\n" % xmlSafeString(x_save_state_dict['Name'], True)
  1954. if self.pinfo['type'] == PLUGIN_LV2:
  1955. content += " <URI>%s</URI>\n" % xmlSafeString(x_save_state_dict['Label'], True)
  1956. else:
  1957. if x_save_state_dict['Label']:
  1958. content += " <Label>%s</Label>\n" % xmlSafeString(x_save_state_dict['Label'], True)
  1959. content += " <Binary>%s</Binary>\n" % xmlSafeString(x_save_state_dict['Binary'], True)
  1960. if x_save_state_dict['UniqueID'] != 0:
  1961. content += " <UniqueID>%li</UniqueID>\n" % x_save_state_dict['UniqueID']
  1962. content += " </Info>\n"
  1963. content += "\n"
  1964. content += " <Data>\n"
  1965. content += " <Active>%s</Active>\n" % "Yes" if x_save_state_dict['Active'] else "No"
  1966. content += " <DryWet>%f</DryWet>\n" % x_save_state_dict['DryWet']
  1967. content += " <Volume>%f</Volume>\n" % x_save_state_dict['Volume']
  1968. content += " <Balance-Left>%f</Balance-Left>\n" % x_save_state_dict['Balance-Left']
  1969. content += " <Balance-Right>%f</Balance-Right>\n" % x_save_state_dict['Balance-Right']
  1970. for parameter in x_save_state_dict['Parameters']:
  1971. content += "\n"
  1972. content += " <Parameter>\n"
  1973. content += " <index>%i</index>\n" % parameter['index']
  1974. content += " <name>%s</name>\n" % xmlSafeString(parameter['name'], True)
  1975. if (parameter['symbol']):
  1976. content += " <symbol>%s</symbol>\n" % parameter['symbol']
  1977. content += " <value>%f</value>\n" % parameter['value']
  1978. if (parameter['midiCC'] > 0):
  1979. content += " <midiChannel>%i</midiChannel>\n" % parameter['midiChannel']
  1980. content += " <midiCC>%i</midiCC>\n" % parameter['midiCC']
  1981. content += " </Parameter>\n"
  1982. if (x_save_state_dict['CurrentProgramIndex'] >= 0):
  1983. content += "\n"
  1984. content += " <CurrentProgramIndex>%i</CurrentProgramIndex>\n" % x_save_state_dict['CurrentProgramIndex']
  1985. content += " <CurrentProgramName>%s</CurrentProgramName>\n" % xmlSafeString(x_save_state_dict['CurrentProgramName'], True)
  1986. if (x_save_state_dict['CurrentMidiBank'] >= 0 and x_save_state_dict['CurrentMidiProgram'] >= 0):
  1987. content += "\n"
  1988. content += " <CurrentMidiBank>%i</CurrentMidiBank>\n" % x_save_state_dict['CurrentMidiBank']
  1989. content += " <CurrentMidiProgram>%i</CurrentMidiProgram>\n" % x_save_state_dict['CurrentMidiProgram']
  1990. for custom_data in x_save_state_dict['CustomData']:
  1991. content += "\n"
  1992. content += " <CustomData>\n"
  1993. content += " <type>%s</type>\n" % custom_data['type']
  1994. content += " <key>%s</key>\n" % xmlSafeString(custom_data['key'], True)
  1995. if (custom_data['type'] in ("string", "chunk", "binary")):
  1996. content += " <value>\n"
  1997. content += "%s\n" % xmlSafeString(custom_data['value'], True)
  1998. content += " </value>\n"
  1999. else:
  2000. content += " <value>%s</value>\n" % xmlSafeString(custom_data['value'], True)
  2001. content += " </CustomData>\n"
  2002. if (x_save_state_dict['Chunk']):
  2003. content += "\n"
  2004. content += " <Chunk>\n"
  2005. content += "%s\n" % x_save_state_dict['Chunk']
  2006. content += " </Chunk>\n"
  2007. content += " </Data>\n"
  2008. return content
  2009. def loadStateDict(self, content):
  2010. # ---------------------------------------------------------------------
  2011. # Part 1 - set custom data
  2012. for custom_data in content['CustomData']:
  2013. CarlaHost.set_custom_data(self.plugin_id, custom_data['type'], custom_data['key'], custom_data['value'])
  2014. # ---------------------------------------------------------------------
  2015. # Part 2 - set program
  2016. program_id = -1
  2017. program_count = CarlaHost.get_program_count(self.plugin_id)
  2018. if (content['CurrentProgramName']):
  2019. test_pname = cString(CarlaHost.get_program_name(self.plugin_id, content['CurrentProgramIndex']))
  2020. # Program index and name matches
  2021. if (content['CurrentProgramName'] == test_pname):
  2022. program_id = content['CurrentProgramIndex']
  2023. # index < count
  2024. elif (content['CurrentProgramIndex'] < program_count):
  2025. program_id = content['CurrentProgramIndex']
  2026. # index not valid, try to find by name
  2027. else:
  2028. for i in range(program_count):
  2029. test_pname = cString(CarlaHost.get_program_name(self.plugin_id, i))
  2030. if (content['CurrentProgramName'] == test_pname):
  2031. program_id = i
  2032. break
  2033. # set program now, if valid
  2034. if (program_id >= 0):
  2035. CarlaHost.set_program(self.plugin_id, program_id)
  2036. self.edit_dialog.set_program(program_id)
  2037. # ---------------------------------------------------------------------
  2038. # Part 3 - set midi program
  2039. if (content['CurrentMidiBank'] >= 0 and content['CurrentMidiProgram'] >= 0):
  2040. midi_program_count = CarlaHost.get_midi_program_count(self.plugin_id)
  2041. for i in range(midi_program_count):
  2042. program_info = CarlaHost.get_midi_program_info(self.plugin_id, i)
  2043. if (program_info['bank'] == content['CurrentMidiBank'] and program_info['program'] == content[
  2044. 'CurrentMidiProgram']):
  2045. CarlaHost.set_midi_program(self.plugin_id, i)
  2046. self.edit_dialog.set_midi_program(i)
  2047. break
  2048. # ---------------------------------------------------------------------
  2049. # Part 4a - get plugin parameter symbols
  2050. param_symbols = [] # (index, symbol)
  2051. for parameter in content['Parameters']:
  2052. if (parameter['symbol']):
  2053. param_info = CarlaHost.get_parameter_info(self.plugin_id, parameter['index'])
  2054. if (param_info['valid'] and param_info['symbol']):
  2055. param_symbols.append((parameter['index'], cString(param_info['symbol'])))
  2056. # ---------------------------------------------------------------------
  2057. # Part 4b - set parameter values (carefully)
  2058. for parameter in content['Parameters']:
  2059. index = -1
  2060. if (content['Type'] == "LADSPA"):
  2061. # Try to set by symbol, otherwise use index
  2062. if (parameter['symbol']):
  2063. for param_symbol in param_symbols:
  2064. if (param_symbol[1] == parameter['symbol']):
  2065. index = param_symbol[0]
  2066. break
  2067. else:
  2068. index = parameter['index']
  2069. else:
  2070. index = parameter['index']
  2071. elif (content['Type'] == "LV2"):
  2072. # Symbol only
  2073. if (parameter['symbol']):
  2074. for param_symbol in param_symbols:
  2075. if (param_symbol[1] == parameter['symbol']):
  2076. index = param_symbol[0]
  2077. break
  2078. else:
  2079. print("Failed to find LV2 parameter symbol for %i -> %s" % (
  2080. parameter['index'], parameter['symbol']))
  2081. else:
  2082. print("LV2 Plugin parameter #%i, '%s', has no symbol" % (parameter['index'], parameter['name']))
  2083. else:
  2084. # Index only
  2085. index = parameter['index']
  2086. # Now set parameter
  2087. if (index >= 0):
  2088. param_data = CarlaHost.get_parameter_data(self.plugin_id, parameter['index'])
  2089. if (param_data['hints'] & PARAMETER_USES_SAMPLERATE):
  2090. parameter['value'] *= CarlaHost.get_sample_rate()
  2091. CarlaHost.set_parameter_value(self.plugin_id, index, parameter['value'])
  2092. CarlaHost.set_parameter_midi_channel(self.plugin_id, index, parameter['midiChannel'] - 1)
  2093. CarlaHost.set_parameter_midi_cc(self.plugin_id, index, parameter['midiCC'])
  2094. else:
  2095. print("Could not set parameter data for %i -> %s" % (parameter['index'], parameter['name']))
  2096. # ---------------------------------------------------------------------
  2097. # Part 5 - set chunk data
  2098. if (content['Chunk']):
  2099. CarlaHost.set_chunk_data(self.plugin_id, content['Chunk'])
  2100. # ---------------------------------------------------------------------
  2101. # Part 6 - set internal stuff
  2102. self.set_drywet(content['DryWet'] * 1000, True, True)
  2103. self.set_volume(content['Volume'] * 1000, True, True)
  2104. self.set_balance_left(content['Balance-Left'] * 1000, True, True)
  2105. self.set_balance_right(content['Balance-Right'] * 1000, True, True)
  2106. self.edit_dialog.do_reload_all()
  2107. self.set_active(content['Active'], True, True)
  2108. def check_gui_stuff(self):
  2109. # Input peaks
  2110. if (self.peaks_in > 0):
  2111. if (self.peaks_in > 1):
  2112. peak1 = CarlaHost.get_input_peak_value(self.plugin_id, 1)
  2113. peak2 = CarlaHost.get_input_peak_value(self.plugin_id, 2)
  2114. led_ain_state = bool(peak1 != 0.0 or peak2 != 0.0)
  2115. self.peak_in.displayMeter(1, peak1)
  2116. self.peak_in.displayMeter(2, peak2)
  2117. else:
  2118. peak = CarlaHost.get_input_peak_value(self.plugin_id, 1)
  2119. led_ain_state = bool(peak != 0.0)
  2120. self.peak_in.displayMeter(1, peak)
  2121. if (led_ain_state != self.last_led_ain_state):
  2122. self.led_audio_in.setChecked(led_ain_state)
  2123. self.last_led_ain_state = led_ain_state
  2124. # Output peaks
  2125. if (self.peaks_out > 0):
  2126. if (self.peaks_out > 1):
  2127. peak1 = CarlaHost.get_output_peak_value(self.plugin_id, 1)
  2128. peak2 = CarlaHost.get_output_peak_value(self.plugin_id, 2)
  2129. led_aout_state = bool(peak1 != 0.0 or peak2 != 0.0)
  2130. self.peak_out.displayMeter(1, peak1)
  2131. self.peak_out.displayMeter(2, peak2)
  2132. else:
  2133. peak = CarlaHost.get_output_peak_value(self.plugin_id, 1)
  2134. led_aout_state = bool(peak != 0.0)
  2135. self.peak_out.displayMeter(1, peak)
  2136. if (led_aout_state != self.last_led_aout_state):
  2137. self.led_audio_out.setChecked(led_aout_state)
  2138. self.last_led_aout_state = led_aout_state
  2139. def check_gui_stuff2(self):
  2140. # Parameter Activity LED
  2141. if (self.parameter_activity_timer == ICON_STATE_ON):
  2142. self.led_control.setChecked(True)
  2143. self.parameter_activity_timer = ICON_STATE_WAIT
  2144. elif (self.parameter_activity_timer == ICON_STATE_WAIT):
  2145. self.parameter_activity_timer = ICON_STATE_OFF
  2146. elif (self.parameter_activity_timer == ICON_STATE_OFF):
  2147. self.led_control.setChecked(False)
  2148. self.parameter_activity_timer = None
  2149. # Update edit dialog
  2150. self.edit_dialog.check_gui_stuff()
  2151. @pyqtSlot(bool)
  2152. def slot_setActive(self, yesno):
  2153. self.set_active(yesno, False, True)
  2154. @pyqtSlot(int)
  2155. def slot_setDryWet(self, value):
  2156. self.set_drywet(value, False, True)
  2157. @pyqtSlot(int)
  2158. def slot_setVolume(self, value):
  2159. self.set_volume(value, False, True)
  2160. @pyqtSlot(int)
  2161. def slot_setBalanceLeft(self, value):
  2162. self.set_balance_left(value, False, True)
  2163. @pyqtSlot(int)
  2164. def slot_setBalanceRight(self, value):
  2165. self.set_balance_right(value, False, True)
  2166. @pyqtSlot(bool)
  2167. def slot_guiClicked(self, show):
  2168. if (self.gui_dialog_type in (GUI_INTERNAL_QT4, GUI_INTERNAL_HWND, GUI_INTERNAL_X11)):
  2169. if (show):
  2170. if (self.gui_dialog_geometry):
  2171. self.gui_dialog.restoreGeometry(self.gui_dialog_geometry)
  2172. else:
  2173. self.gui_dialog_geometry = self.gui_dialog.saveGeometry()
  2174. self.gui_dialog.setVisible(show)
  2175. CarlaHost.show_gui(self.plugin_id, show)
  2176. @pyqtSlot()
  2177. def slot_guiClosed(self):
  2178. self.b_gui.setChecked(False)
  2179. @pyqtSlot(bool)
  2180. def slot_editClicked(self, show):
  2181. if (show):
  2182. if (self.edit_dialog_geometry):
  2183. self.edit_dialog.restoreGeometry(self.edit_dialog_geometry)
  2184. else:
  2185. self.edit_dialog_geometry = self.edit_dialog.saveGeometry()
  2186. self.edit_dialog.setVisible(show)
  2187. @pyqtSlot()
  2188. def slot_editClosed(self):
  2189. self.b_edit.setChecked(False)
  2190. @pyqtSlot()
  2191. def slot_removeClicked(self):
  2192. gui.remove_plugin(self.plugin_id, True)
  2193. @pyqtSlot()
  2194. def slot_showCustomDialMenu(self):
  2195. dial_name = self.sender().objectName()
  2196. if (dial_name == "dial_drywet"):
  2197. minimum = 0
  2198. maximum = 100
  2199. default = 100
  2200. label = "Dry/Wet"
  2201. elif (dial_name == "dial_vol"):
  2202. minimum = 0
  2203. maximum = 127
  2204. default = 100
  2205. label = "Volume"
  2206. elif (dial_name == "dial_b_left"):
  2207. minimum = -100
  2208. maximum = 100
  2209. default = -100
  2210. label = "Balance-Left"
  2211. elif (dial_name == "dial_b_right"):
  2212. minimum = -100
  2213. maximum = 100
  2214. default = 100
  2215. label = "Balance-Right"
  2216. else:
  2217. minimum = 0
  2218. maximum = 100
  2219. default = 100
  2220. label = "Unknown"
  2221. current = self.sender().value() / 10
  2222. menu = QMenu(self)
  2223. act_x_reset = menu.addAction(self.tr("Reset (%i%%)" % (default)))
  2224. menu.addSeparator()
  2225. act_x_min = menu.addAction(self.tr("Set to Minimum (%i%%)" % (minimum)))
  2226. act_x_cen = menu.addAction(self.tr("Set to Center"))
  2227. act_x_max = menu.addAction(self.tr("Set to Maximum (%i%%)" % (maximum)))
  2228. menu.addSeparator()
  2229. act_x_set = menu.addAction(self.tr("Set value..."))
  2230. if (label not in ("Balance-Left", "Balance-Right")):
  2231. menu.removeAction(act_x_cen)
  2232. act_x_sel = menu.exec_(QCursor.pos())
  2233. if (act_x_sel == act_x_set):
  2234. value_try = QInputDialog.getInteger(self, self.tr("Set value"), label, current, minimum, maximum, 1)
  2235. if (value_try[1]):
  2236. value = value_try[0] * 10
  2237. else:
  2238. value = None
  2239. elif (act_x_sel == act_x_min):
  2240. value = minimum * 10
  2241. elif (act_x_sel == act_x_max):
  2242. value = maximum * 10
  2243. elif (act_x_sel == act_x_reset):
  2244. value = default * 10
  2245. elif (act_x_sel == act_x_cen):
  2246. value = 0
  2247. else:
  2248. value = None
  2249. if (value != None):
  2250. if (label == "Dry/Wet"):
  2251. self.set_drywet(value, True, True)
  2252. elif (label == "Volume"):
  2253. self.set_volume(value, True, True)
  2254. elif (label == "Balance-Left"):
  2255. self.set_balance_left(value, True, True)
  2256. elif (label == "Balance-Right"):
  2257. self.set_balance_right(value, True, True)
  2258. def paintEvent(self, event):
  2259. painter = QPainter(self)
  2260. painter.setPen(self.color_1)
  2261. painter.drawLine(0, 3, self.width(), 3)
  2262. painter.drawLine(0, self.height() - 4, self.width(), self.height() - 4)
  2263. painter.setPen(self.color_2)
  2264. painter.drawLine(0, 2, self.width(), 2)
  2265. painter.drawLine(0, self.height() - 3, self.width(), self.height() - 3)
  2266. painter.setPen(self.color_3)
  2267. painter.drawLine(0, 1, self.width(), 1)
  2268. painter.drawLine(0, self.height() - 2, self.width(), self.height() - 2)
  2269. painter.setPen(self.color_4)
  2270. painter.drawLine(0, 0, self.width(), 0)
  2271. painter.drawLine(0, self.height() - 1, self.width(), self.height() - 1)
  2272. QFrame.paintEvent(self, event)
  2273. # Main Window
  2274. class CarlaMainW(QMainWindow, ui_carla.Ui_CarlaMainW):
  2275. def __init__(self, parent=None):
  2276. QMainWindow.__init__(self, parent)
  2277. self.setupUi(self)
  2278. # -------------------------------------------------------------
  2279. # Load Settings
  2280. self.settings = QSettings("Cadence", "Carla")
  2281. self.settings_db = QSettings("Cadence", "Carla-Database")
  2282. self.loadSettings(True)
  2283. self.loadRDFs()
  2284. self.setStyleSheet("""
  2285. QWidget#centralwidget {
  2286. background-color: qlineargradient(spread:pad,
  2287. x1:0.0, y1:0.0,
  2288. x2:0.2, y2:1.0,
  2289. stop:0 rgb( 7, 7, 7),
  2290. stop:1 rgb(28, 28, 28)
  2291. );
  2292. }
  2293. """)
  2294. # -------------------------------------------------------------
  2295. # Internal stuff
  2296. self.m_bridge_info = None
  2297. self.m_project_filename = None
  2298. self.m_plugin_list = []
  2299. for x in range(MAX_PLUGINS):
  2300. self.m_plugin_list.append(None)
  2301. CarlaHost.set_callback_function(self.callback_function)
  2302. # -------------------------------------------------------------
  2303. # Set-up GUI stuff
  2304. self.act_plugin_remove_all.setEnabled(False)
  2305. self.resize(self.width(), 0)
  2306. # -------------------------------------------------------------
  2307. # Connect actions to functions
  2308. self.connect(self.act_file_new, SIGNAL("triggered()"), SLOT("slot_file_new()"))
  2309. self.connect(self.act_file_open, SIGNAL("triggered()"), SLOT("slot_file_open()"))
  2310. self.connect(self.act_file_save, SIGNAL("triggered()"), SLOT("slot_file_save()"))
  2311. self.connect(self.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_file_save_as()"))
  2312. self.connect(self.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_plugin_add()"))
  2313. self.connect(self.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_remove_all()"))
  2314. self.connect(self.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()"))
  2315. self.connect(self.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarla()"))
  2316. self.connect(self.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  2317. self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_handleSIGUSR1()"))
  2318. self.connect(self, SIGNAL("DebugCallback(int, int, int, double)"), SLOT("slot_handleDebugCallback(int, int, int, double)"))
  2319. self.connect(self, SIGNAL("ParameterCallback(int, int, double)"), SLOT("slot_handleParameterCallback(int, int, double)"))
  2320. self.connect(self, SIGNAL("ProgramCallback(int, int)"), SLOT("slot_handleProgramCallback(int, int)"))
  2321. self.connect(self, SIGNAL("MidiProgramCallback(int, int)"), SLOT("slot_handleMidiProgramCallback(int, int)"))
  2322. self.connect(self, SIGNAL("NoteOnCallback(int, int, int)"), SLOT("slot_handleNoteOnCallback(int, int)"))
  2323. self.connect(self, SIGNAL("NoteOffCallback(int, int)"), SLOT("slot_handleNoteOffCallback(int, int)"))
  2324. self.connect(self, SIGNAL("ShowGuiCallback(int, int)"), SLOT("slot_handleShowGuiCallback(int, int)"))
  2325. self.connect(self, SIGNAL("ResizeGuiCallback(int, int, int)"), SLOT("slot_handleResizeGuiCallback(int, int, int)"))
  2326. self.connect(self, SIGNAL("UpdateCallback(int)"), SLOT("slot_handleUpdateCallback(int)"))
  2327. self.connect(self, SIGNAL("ReloadInfoCallback(int)"), SLOT("slot_handleReloadInfoCallback(int)"))
  2328. self.connect(self, SIGNAL("ReloadParametersCallback(int)"), SLOT("slot_handleReloadParametersCallback(int)"))
  2329. self.connect(self, SIGNAL("ReloadProgramsCallback(int)"), SLOT("slot_handleReloadProgramsCallback(int)"))
  2330. self.connect(self, SIGNAL("ReloadAllCallback(int)"), SLOT("slot_handleReloadAllCallback(int)"))
  2331. self.connect(self, SIGNAL("QuitCallback()"), SLOT("slot_handleQuitCallback()"))
  2332. self.TIMER_GUI_STUFF = self.startTimer(self.m_savedSettings["Main/RefreshInterval"]) # Peaks
  2333. self.TIMER_GUI_STUFF2 = self.startTimer(self.m_savedSettings["Main/RefreshInterval"] * 2) # LEDs and edit dialog
  2334. def callback_function(self, action, plugin_id, value1, value2, value3):
  2335. if (plugin_id < 0 or plugin_id >= MAX_PLUGINS):
  2336. return
  2337. if (action == CALLBACK_DEBUG):
  2338. self.emit(SIGNAL("DebugCallback(int, int, int, double)"), plugin_id, value1, value2, value3)
  2339. elif (action == CALLBACK_PARAMETER_CHANGED):
  2340. self.emit(SIGNAL("ParameterCallback(int, int, double)"), plugin_id, value1, value3)
  2341. elif (action == CALLBACK_PROGRAM_CHANGED):
  2342. self.emit(SIGNAL("ProgramCallback(int, int)"), plugin_id, value1)
  2343. elif (action == CALLBACK_MIDI_PROGRAM_CHANGED):
  2344. self.emit(SIGNAL("MidiProgramCallback(int, int)"), plugin_id, value1)
  2345. elif (action == CALLBACK_NOTE_ON):
  2346. self.emit(SIGNAL("NoteOnCallback(int, int, int)"), plugin_id, value1, value2)
  2347. elif (action == CALLBACK_NOTE_OFF):
  2348. self.emit(SIGNAL("NoteOffCallback(int, int)"), plugin_id, value1)
  2349. elif (action == CALLBACK_SHOW_GUI):
  2350. self.emit(SIGNAL("ShowGuiCallback(int, int)"), plugin_id, value1)
  2351. elif (action == CALLBACK_RESIZE_GUI):
  2352. self.emit(SIGNAL("ResizeGuiCallback(int, int, int)"), plugin_id, value1, value2)
  2353. elif (action == CALLBACK_UPDATE):
  2354. self.emit(SIGNAL("UpdateCallback(int)"), plugin_id)
  2355. elif (action == CALLBACK_RELOAD_INFO):
  2356. self.emit(SIGNAL("ReloadInfoCallback(int)"), plugin_id)
  2357. elif (action == CALLBACK_RELOAD_PARAMETERS):
  2358. self.emit(SIGNAL("ReloadParametersCallback(int)"), plugin_id)
  2359. elif (action == CALLBACK_RELOAD_PROGRAMS):
  2360. self.emit(SIGNAL("ReloadProgramsCallback(int)"), plugin_id)
  2361. elif (action == CALLBACK_RELOAD_ALL):
  2362. self.emit(SIGNAL("ReloadAllCallback(int)"), plugin_id)
  2363. elif (action == CALLBACK_QUIT):
  2364. self.emit(SIGNAL("QuitCallback()"))
  2365. @pyqtSlot()
  2366. def slot_handleSIGUSR1(self):
  2367. print("Got SIGUSR1 -> Saving project now")
  2368. QTimer.singleShot(0, self, SLOT("slot_file_save()"))
  2369. @pyqtSlot(int, int, int, float)
  2370. def slot_handleDebugCallback(self, plugin_id, value1, value2, value3):
  2371. print("DEBUG :: %i, %i, %i, %f)" % (plugin_id, value1, value2, value3))
  2372. @pyqtSlot(int, int, float)
  2373. def slot_handleParameterCallback(self, plugin_id, parameter_id, value):
  2374. pwidget = self.m_plugin_list[plugin_id]
  2375. if (pwidget):
  2376. pwidget.parameter_activity_timer = ICON_STATE_ON
  2377. if (parameter_id == PARAMETER_ACTIVE):
  2378. pwidget.set_active((value > 0.0), True, False)
  2379. elif (parameter_id == PARAMETER_DRYWET):
  2380. pwidget.set_drywet(value * 1000, True, False)
  2381. elif (parameter_id == PARAMETER_VOLUME):
  2382. pwidget.set_volume(value * 1000, True, False)
  2383. elif (parameter_id == PARAMETER_BALANCE_LEFT):
  2384. pwidget.set_balance_left(value * 1000, True, False)
  2385. elif (parameter_id == PARAMETER_BALANCE_RIGHT):
  2386. pwidget.set_balance_right(value * 1000, True, False)
  2387. elif (parameter_id >= 0):
  2388. pwidget.edit_dialog.set_parameter_to_update(parameter_id)
  2389. @pyqtSlot(int, int)
  2390. def slot_handleProgramCallback(self, plugin_id, program_id):
  2391. pwidget = self.m_plugin_list[plugin_id]
  2392. if (pwidget):
  2393. pwidget.edit_dialog.set_program(program_id)
  2394. @pyqtSlot(int, int)
  2395. def slot_handleMidiProgramCallback(self, plugin_id, midi_program_id):
  2396. pwidget = self.m_plugin_list[plugin_id]
  2397. if (pwidget):
  2398. pwidget.edit_dialog.set_midi_program(midi_program_id)
  2399. @pyqtSlot(int, int)
  2400. def slot_handleNoteOnCallback(self, plugin_id, note):
  2401. pwidget = self.m_plugin_list[plugin_id]
  2402. if (pwidget):
  2403. pwidget.edit_dialog.keyboard.sendNoteOn(note, False)
  2404. @pyqtSlot(int, int)
  2405. def slot_handleNoteOffCallback(self, plugin_id, note):
  2406. pwidget = self.m_plugin_list[plugin_id]
  2407. if (pwidget):
  2408. pwidget.edit_dialog.keyboard.sendNoteOff(note, False)
  2409. @pyqtSlot(int, int)
  2410. def slot_handleShowGuiCallback(self, plugin_id, show):
  2411. pwidget = self.m_plugin_list[plugin_id]
  2412. if (pwidget):
  2413. if (show == 0):
  2414. pwidget.b_gui.setChecked(False)
  2415. pwidget.b_gui.setEnabled(True)
  2416. elif (show == 1):
  2417. pwidget.b_gui.setChecked(True)
  2418. pwidget.b_gui.setEnabled(True)
  2419. elif (show == -1):
  2420. pwidget.b_gui.setChecked(False)
  2421. pwidget.b_gui.setEnabled(False)
  2422. @pyqtSlot(int, int, int)
  2423. def slot_handleResizeGuiCallback(self, plugin_id, width, height):
  2424. pwidget = self.m_plugin_list[plugin_id]
  2425. if (pwidget):
  2426. gui_dialog = pwidget.gui_dialog
  2427. if (gui_dialog):
  2428. gui_dialog.setNewSize(width, height)
  2429. @pyqtSlot(int)
  2430. def slot_handleUpdateCallback(self, plugin_id):
  2431. pwidget = self.m_plugin_list[plugin_id]
  2432. if (pwidget):
  2433. pwidget.edit_dialog.do_update()
  2434. @pyqtSlot(int)
  2435. def slot_handleReloadInfoCallback(self, plugin_id):
  2436. pwidget = self.m_plugin_list[plugin_id]
  2437. if (pwidget):
  2438. pwidget.edit_dialog.do_reload_info()
  2439. @pyqtSlot(int)
  2440. def slot_handleReloadParametersCallback(self, plugin_id):
  2441. pwidget = self.m_plugin_list[plugin_id]
  2442. if (pwidget):
  2443. pwidget.edit_dialog.do_reload_parameters()
  2444. @pyqtSlot(int)
  2445. def slot_handleReloadProgramsCallback(self, plugin_id):
  2446. pwidget = self.m_plugin_list[plugin_id]
  2447. if (pwidget):
  2448. pwidget.edit_dialog.do_reload_programs()
  2449. @pyqtSlot(int)
  2450. def slot_handleReloadAllCallback(self, plugin_id):
  2451. pwidget = self.m_plugin_list[plugin_id]
  2452. if (pwidget):
  2453. pwidget.edit_dialog.do_reload_all()
  2454. @pyqtSlot()
  2455. def slot_handleQuitCallback(self):
  2456. CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  2457. self.tr("JACK has been stopped or crashed.\nPlease start JACK and restart Carla"),
  2458. "You may want to save your session now...", QMessageBox.Ok, QMessageBox.Ok)
  2459. def add_plugin(self, btype, ptype, filename, label, extra_stuff, activate):
  2460. new_plugin_id = CarlaHost.add_plugin(btype, ptype, filename, label, extra_stuff)
  2461. if (new_plugin_id < 0):
  2462. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"),
  2463. cString(CarlaHost.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  2464. else:
  2465. pwidget = PluginWidget(self, new_plugin_id)
  2466. self.w_plugins.layout().addWidget(pwidget)
  2467. self.m_plugin_list[new_plugin_id] = pwidget
  2468. self.act_plugin_remove_all.setEnabled(True)
  2469. pwidget.peak_in.setRefreshRate(self.m_savedSettings["Main/RefreshInterval"])
  2470. pwidget.peak_out.setRefreshRate(self.m_savedSettings["Main/RefreshInterval"])
  2471. if (activate):
  2472. pwidget.set_active(True, True, True)
  2473. return new_plugin_id
  2474. def remove_plugin(self, plugin_id, showError):
  2475. pwidget = self.m_plugin_list[plugin_id]
  2476. pwidget.edit_dialog.close()
  2477. if (pwidget.gui_dialog):
  2478. pwidget.gui_dialog.close()
  2479. if (CarlaHost.remove_plugin(plugin_id)):
  2480. pwidget.close()
  2481. pwidget.deleteLater()
  2482. self.w_plugins.layout().removeWidget(pwidget)
  2483. self.m_plugin_list[plugin_id] = None
  2484. else:
  2485. if (showError):
  2486. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to remove plugin"),
  2487. cString(CarlaHost.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  2488. for i in range(MAX_PLUGINS):
  2489. if (self.m_plugin_list[i] != None):
  2490. self.act_plugin_remove_all.setEnabled(True)
  2491. break
  2492. else:
  2493. self.act_plugin_remove_all.setEnabled(False)
  2494. def get_extra_stuff(self, plugin):
  2495. build = plugin['build']
  2496. ptype = plugin['type']
  2497. if (ptype == PLUGIN_LADSPA):
  2498. unique_id = plugin['unique_id']
  2499. for rdf_item in self.ladspa_rdf_list:
  2500. if rdf_item.UniqueID == unique_id:
  2501. return pointer(rdf_item)
  2502. else:
  2503. return c_nullptr
  2504. elif (ptype == PLUGIN_DSSI):
  2505. if plugin['hints'] & PLUGIN_HAS_GUI:
  2506. gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label'])
  2507. if gui:
  2508. return gui.encode("utf-8")
  2509. return c_nullptr
  2510. else:
  2511. return c_nullptr
  2512. def save_project(self):
  2513. content = ("<?xml version='1.0' encoding='UTF-8'?>\n"
  2514. "<!DOCTYPE CARLA-PROJECT>\n"
  2515. "<CARLA-PROJECT VERSION='%s'>\n") % (VERSION)
  2516. first_plugin = True
  2517. for pwidget in self.m_plugin_list:
  2518. if pwidget:
  2519. if not first_plugin:
  2520. content += "\n"
  2521. real_plugin_name = cString(CarlaHost.get_real_plugin_name(pwidget.plugin_id))
  2522. if real_plugin_name:
  2523. content += " <!-- %s -->\n" % xmlSafeString(real_plugin_name, True)
  2524. content += " <Plugin>\n"
  2525. content += pwidget.getSaveXMLContent()
  2526. content += " </Plugin>\n"
  2527. first_plugin = False
  2528. content += "</CARLA-PROJECT>\n"
  2529. try:
  2530. open(self.m_project_filename, "w").write(content)
  2531. except:
  2532. QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to save project file"))
  2533. def load_project(self):
  2534. try:
  2535. project_read = open(self.m_project_filename, "r").read()
  2536. except:
  2537. project_read = None
  2538. if not project_read:
  2539. QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to load project file"))
  2540. return
  2541. xml = QDomDocument()
  2542. xml.setContent(project_read)
  2543. xml_node = xml.documentElement()
  2544. if xml_node.tagName() != "CARLA-PROJECT":
  2545. QMessageBox.critical(self, self.tr("Error"), self.tr("Not a valid Carla project file"))
  2546. return
  2547. x_ladspa_plugins = None
  2548. x_dssi_plugins = None
  2549. x_lv2_plugins = None
  2550. x_vst_plugins = None
  2551. x_gig_plugins = None
  2552. x_sf2_plugins = None
  2553. x_sfz_plugins = None
  2554. x_failed_plugins = []
  2555. x_save_state_dicts = []
  2556. node = xml_node.firstChild()
  2557. while not node.isNull():
  2558. if node.toElement().tagName() == "Plugin":
  2559. x_save_state_dict = getStateDictFromXML(node)
  2560. x_save_state_dicts.append(x_save_state_dict)
  2561. node = node.nextSibling()
  2562. for x_save_state_dict in x_save_state_dicts:
  2563. ptype = x_save_state_dict['Type']
  2564. label = x_save_state_dict['Label']
  2565. binary = x_save_state_dict['Binary']
  2566. binaryS = os.path.basename(binary)
  2567. unique_id = x_save_state_dict['UniqueID']
  2568. if ptype == "LADSPA":
  2569. if not x_ladspa_plugins:
  2570. x_ladspa_plugins = []
  2571. x_ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_unix32", []))
  2572. x_ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_unix64", []))
  2573. x_ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_win32", []))
  2574. x_ladspa_plugins += toList(self.settings_db.value("Plugins/LADSPA_win64", []))
  2575. x_plugins = x_ladspa_plugins
  2576. elif ptype == "DSSI":
  2577. if not x_dssi_plugins:
  2578. x_dssi_plugins = []
  2579. x_dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_unix32", []))
  2580. x_dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_unix64", []))
  2581. x_dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_win32", []))
  2582. x_dssi_plugins += toList(self.settings_db.value("Plugins/DSSI_win64", []))
  2583. x_plugins = x_dssi_plugins
  2584. elif ptype == "LV2":
  2585. if not x_lv2_plugins:
  2586. x_lv2_plugins = []
  2587. x_lv2_plugins += toList(self.settings_db.value("Plugins/LV2_unix32", []))
  2588. x_lv2_plugins += toList(self.settings_db.value("Plugins/LV2_unix64", []))
  2589. x_lv2_plugins += toList(self.settings_db.value("Plugins/LV2_win32", []))
  2590. x_lv2_plugins += toList(self.settings_db.value("Plugins/LV2_win64", []))
  2591. x_plugins = x_lv2_plugins
  2592. elif ptype == "VST":
  2593. if not x_vst_plugins:
  2594. x_vst_plugins = []
  2595. x_vst_plugins += toList(self.settings_db.value("Plugins/VST_unix32", []))
  2596. x_vst_plugins += toList(self.settings_db.value("Plugins/VST_unix64", []))
  2597. x_vst_plugins += toList(self.settings_db.value("Plugins/VST_win32", []))
  2598. x_vst_plugins += toList(self.settings_db.value("Plugins/VST_win64", []))
  2599. x_plugins = x_vst_plugins
  2600. elif ptype == "GIG":
  2601. if not x_gig_plugins: x_gig_plugins = toList(self.settings_db.value("Plugins/GIG", []))
  2602. x_plugins = x_gig_plugins
  2603. elif ptype == "SF2":
  2604. if not x_sf2_plugins: x_sf2_plugins = toList(self.settings_db.value("Plugins/SF2", []))
  2605. x_plugins = x_sf2_plugins
  2606. elif ptype == "SFZ":
  2607. if not x_sfz_plugins: x_sfz_plugins = toList(self.settings_db.value("Plugins/SFZ", []))
  2608. x_plugins = x_sfz_plugins
  2609. else:
  2610. print("load_project() - ptype '%s' not recognized", ptype)
  2611. x_failed_plugins.append(x_save_state_dict['Name'])
  2612. continue
  2613. # Try UniqueID -> Label -> Binary (full) -> Binary (short)
  2614. plugin_ulB = None
  2615. plugin_ulb = None
  2616. plugin_ul = None
  2617. plugin_uB = None
  2618. plugin_ub = None
  2619. plugin_lB = None
  2620. plugin_lb = None
  2621. plugin_u = None
  2622. plugin_l = None
  2623. plugin_B = None
  2624. for _plugins in x_plugins:
  2625. for x_plugin in _plugins:
  2626. if unique_id == x_plugin['unique_id'] and label == x_plugin['label'] and binary == x_plugin['binary']:
  2627. plugin_ulB = x_plugin
  2628. break
  2629. elif unique_id == x_plugin['unique_id'] and label == x_plugin['label'] and binaryS == os.path.basename(x_plugin['binary']):
  2630. plugin_ulb = x_plugin
  2631. elif unique_id == x_plugin['unique_id'] and label == x_plugin['label']:
  2632. plugin_ul = x_plugin
  2633. elif unique_id == x_plugin['unique_id'] and binary == x_plugin['binary']:
  2634. plugin_uB = x_plugin
  2635. elif unique_id == x_plugin['unique_id'] and binaryS == os.path.basename(x_plugin['binary']):
  2636. plugin_ub = x_plugin
  2637. elif label == x_plugin['label'] and binary == x_plugin['binary']:
  2638. plugin_lB = x_plugin
  2639. elif label == x_plugin['label'] and binaryS == os.path.basename(x_plugin['binary']):
  2640. plugin_lb = x_plugin
  2641. elif unique_id == x_plugin['unique_id']:
  2642. plugin_u = x_plugin
  2643. elif label == x_plugin['label']:
  2644. plugin_l = x_plugin
  2645. elif binary == x_plugin['binary']:
  2646. plugin_B = x_plugin
  2647. # LADSPA uses UniqueID or binary+label
  2648. if ptype == "LADSPA":
  2649. plugin_l = None
  2650. plugin_B = None
  2651. # DSSI uses binary+label (UniqueID ignored)
  2652. elif ptype == "DSSI":
  2653. plugin_ul = None
  2654. plugin_uB = None
  2655. plugin_ub = None
  2656. plugin_u = None
  2657. plugin_l = None
  2658. plugin_B = None
  2659. # LV2 uses URIs (label in this case)
  2660. elif ptype == "LV2":
  2661. plugin_uB = None
  2662. plugin_ub = None
  2663. plugin_u = None
  2664. plugin_B = None
  2665. # VST uses UniqueID
  2666. elif ptype == "VST":
  2667. plugin_lB = None
  2668. plugin_lb = None
  2669. plugin_l = None
  2670. plugin_B = None
  2671. # Sound Kits use binaries
  2672. elif ptype in ("GIG", "SF2", "SFZ"):
  2673. plugin_ul = None
  2674. plugin_u = None
  2675. plugin_l = None
  2676. if (plugin_ulB):
  2677. plugin = plugin_ulB
  2678. elif (plugin_ulb):
  2679. plugin = plugin_ulb
  2680. elif (plugin_ul):
  2681. plugin = plugin_ul
  2682. elif (plugin_uB):
  2683. plugin = plugin_uB
  2684. elif (plugin_ub):
  2685. plugin = plugin_ub
  2686. elif (plugin_lB):
  2687. plugin = plugin_lB
  2688. elif (plugin_lb):
  2689. plugin = plugin_lb
  2690. elif (plugin_u):
  2691. plugin = plugin_u
  2692. elif (plugin_l):
  2693. plugin = plugin_l
  2694. elif (plugin_B):
  2695. plugin = plugin_B
  2696. else:
  2697. plugin = None
  2698. if plugin:
  2699. btype = plugin['build']
  2700. ptype = plugin['type']
  2701. filename = plugin['binary']
  2702. label = plugin['label']
  2703. extra_stuff = self.get_extra_stuff(plugin)
  2704. new_plugin_id = self.add_plugin(btype, ptype, filename, label, extra_stuff, False)
  2705. if new_plugin_id >= 0:
  2706. pwidget = self.m_plugin_list[new_plugin_id]
  2707. pwidget.loadStateDict(x_save_state_dict)
  2708. else:
  2709. x_failed_plugins.append(x_save_state_dict['Name'])
  2710. else:
  2711. x_failed_plugins.append(x_save_state_dict['Name'])
  2712. if len(x_failed_plugins) > 0:
  2713. text = self.tr("The following plugins were not found or failed to initialize:\n")
  2714. for plugin in x_failed_plugins:
  2715. text += " - %s\n" % plugin
  2716. self.statusBar().showMessage("State file loaded with errors")
  2717. QMessageBox.critical(self, self.tr("Error"), text)
  2718. else:
  2719. self.statusBar().showMessage("State file loaded sucessfully!")
  2720. def loadRDFs(self):
  2721. # Save RDF info for later
  2722. if haveLRDF:
  2723. SettingsDir = os.path.join(HOME, ".config", "Cadence")
  2724. fr_ladspa_file = os.path.join(SettingsDir, "ladspa_rdf.db")
  2725. if os.path.exists(fr_ladspa_file):
  2726. fr_ladspa = open(fr_ladspa_file, 'r')
  2727. if fr_ladspa:
  2728. try:
  2729. self.ladspa_rdf_list = ladspa_rdf.get_c_ladspa_rdfs(json.load(fr_ladspa))
  2730. except:
  2731. self.ladspa_rdf_list = []
  2732. fr_ladspa.close()
  2733. return
  2734. self.ladspa_rdf_list = []
  2735. @pyqtSlot()
  2736. def slot_file_new(self):
  2737. self.slot_remove_all()
  2738. self.m_project_filename = None
  2739. self.setWindowTitle("Carla")
  2740. @pyqtSlot()
  2741. def slot_file_open(self):
  2742. file_filter = self.tr("Carla Project File (*.carxp)")
  2743. filename = QFileDialog.getOpenFileName(self, self.tr("Open Carla Project File"),
  2744. self.m_savedSettings["Main/DefaultProjectFolder"], filter=file_filter)
  2745. if filename:
  2746. self.m_project_filename = filename
  2747. self.slot_remove_all()
  2748. self.load_project()
  2749. self.setWindowTitle("Carla - %s" % os.path.basename(self.m_project_filename))
  2750. @pyqtSlot()
  2751. def slot_file_save(self, saveAs=False):
  2752. if self.m_project_filename == None or saveAs:
  2753. file_filter = self.tr("Carla Project File (*.carxp)")
  2754. filename = QFileDialog.getSaveFileName(self, self.tr("Save Carla Project File"),
  2755. self.m_savedSettings["Main/DefaultProjectFolder"], filter=file_filter)
  2756. if filename:
  2757. self.m_project_filename = filename
  2758. self.save_project()
  2759. self.setWindowTitle("Carla - %s" % os.path.basename(self.m_project_filename))
  2760. else:
  2761. self.save_project()
  2762. @pyqtSlot()
  2763. def slot_file_save_as(self):
  2764. self.slot_file_save(True)
  2765. @pyqtSlot()
  2766. def slot_plugin_add(self):
  2767. dialog = PluginDatabaseW(self)
  2768. if dialog.exec_():
  2769. btype = dialog.ret_plugin['build']
  2770. ptype = dialog.ret_plugin['type']
  2771. filename = dialog.ret_plugin['binary']
  2772. label = dialog.ret_plugin['label']
  2773. extra_stuff = self.get_extra_stuff(dialog.ret_plugin)
  2774. self.add_plugin(btype, ptype, filename, label, extra_stuff, True)
  2775. @pyqtSlot()
  2776. def slot_remove_all(self):
  2777. for i in range(MAX_PLUGINS):
  2778. if self.m_plugin_list[i]:
  2779. self.remove_plugin(i, False)
  2780. @pyqtSlot()
  2781. def slot_configureCarla(self):
  2782. dialog = SettingsW(self, "carla")
  2783. if dialog.exec_():
  2784. self.loadSettings(False)
  2785. for pwidget in self.m_plugin_list:
  2786. if pwidget:
  2787. pwidget.peak_in.setRefreshRate(self.m_savedSettings["Main/RefreshInterval"])
  2788. pwidget.peak_out.setRefreshRate(self.m_savedSettings["Main/RefreshInterval"])
  2789. @pyqtSlot()
  2790. def slot_aboutCarla(self):
  2791. CarlaAboutW(self).exec_()
  2792. def saveSettings(self):
  2793. self.settings.setValue("Geometry", self.saveGeometry())
  2794. self.settings.setValue("ShowToolbar", self.toolBar.isVisible())
  2795. def loadSettings(self, geometry):
  2796. if geometry:
  2797. self.restoreGeometry(self.settings.value("Geometry", ""))
  2798. show_toolbar = self.settings.value("ShowToolbar", True, type=bool)
  2799. self.act_settings_show_toolbar.setChecked(show_toolbar)
  2800. self.toolBar.setVisible(show_toolbar)
  2801. self.m_savedSettings = {
  2802. "Main/DefaultProjectFolder": self.settings.value("Main/DefaultProjectFolder", DEFAULT_PROJECT_FOLDER, type=str),
  2803. "Main/RefreshInterval": self.settings.value("Main/RefreshInterval", 120, type=int)
  2804. }
  2805. global LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, GIG_PATH, SF2_PATH, SFZ_PATH
  2806. LADSPA_PATH = toList(self.settings.value("Paths/LADSPA", LADSPA_PATH))
  2807. DSSI_PATH = toList(self.settings.value("Paths/DSSI", DSSI_PATH))
  2808. LV2_PATH = toList(self.settings.value("Paths/LV2", LV2_PATH))
  2809. VST_PATH = toList(self.settings.value("Paths/VST", VST_PATH))
  2810. GIG_PATH = toList(self.settings.value("Paths/GIG", GIG_PATH))
  2811. SF2_PATH = toList(self.settings.value("Paths/SF2", SF2_PATH))
  2812. SFZ_PATH = toList(self.settings.value("Paths/SFZ", SFZ_PATH))
  2813. CarlaHost.set_option(OPTION_PATH_LADSPA, 0, splitter.join(LADSPA_PATH))
  2814. CarlaHost.set_option(OPTION_PATH_DSSI, 0, splitter.join(DSSI_PATH))
  2815. CarlaHost.set_option(OPTION_PATH_LV2, 0, splitter.join(LV2_PATH))
  2816. CarlaHost.set_option(OPTION_PATH_VST, 0, splitter.join(VST_PATH))
  2817. CarlaHost.set_option(OPTION_PATH_GIG, 0, splitter.join(GIG_PATH))
  2818. CarlaHost.set_option(OPTION_PATH_SF2, 0, splitter.join(SF2_PATH))
  2819. CarlaHost.set_option(OPTION_PATH_SFZ, 0, splitter.join(SFZ_PATH))
  2820. def timerEvent(self, event):
  2821. if event.timerId() == self.TIMER_GUI_STUFF:
  2822. for pwidget in self.m_plugin_list:
  2823. if pwidget: pwidget.check_gui_stuff()
  2824. CarlaHost.idle_guis()
  2825. elif event.timerId() == self.TIMER_GUI_STUFF2:
  2826. for pwidget in self.m_plugin_list:
  2827. if pwidget: pwidget.check_gui_stuff2()
  2828. QMainWindow.timerEvent(self, event)
  2829. def closeEvent(self, event):
  2830. self.saveSettings()
  2831. self.slot_remove_all()
  2832. QMainWindow.closeEvent(self, event)
  2833. #--------------- main ------------------
  2834. if __name__ == '__main__':
  2835. # App initialization
  2836. app = QApplication(sys.argv)
  2837. app.setApplicationName("Carla")
  2838. app.setApplicationVersion(VERSION)
  2839. app.setOrganizationName("Cadence")
  2840. app.setWindowIcon(QIcon(":/scalable/carla.svg"))
  2841. lib_prefix = None
  2842. project_filename = None
  2843. for i in range(len(app.arguments())):
  2844. if i == 0: continue
  2845. argument = app.arguments()[i]
  2846. if argument.startswith("--with-libprefix="):
  2847. lib_prefix = argument.replace("--with-libprefix=", "")
  2848. elif (os.path.exists(argument)):
  2849. project_filename = argument
  2850. #style = app.style().metaObject().className()
  2851. #force_parameters_style = (style in ("Bespin::Style",))
  2852. CarlaHost = Host(lib_prefix)
  2853. # Create GUI and read settings
  2854. gui = CarlaMainW()
  2855. # Init backend
  2856. process_mode = gui.settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int)
  2857. MAX_PARAMETERS = gui.settings.value("Engine/MaxParameters", MAX_PARAMETERS, type=int)
  2858. prefer_ui_bridges = gui.settings.value("Engine/PreferUIBridges", True, type=bool)
  2859. proccess_hq = gui.settings.value("Engine/ProcessHQ", False, type=bool)
  2860. osc_gui_timeout = gui.settings.value("Engine/OscGuiTimeout", 40, type=int)
  2861. use_dssi_chunks = gui.settings.value("Engine/UseDSSIChunks", False, type=bool)
  2862. if os.getenv("LADISH_APP_NAME") and process_mode == PROCESS_MODE_MULTIPLE_CLIENTS:
  2863. print("LADISH detected but using multiple clients (not allowed), forcing single client now")
  2864. process_mode = PROCESS_MODE_SINGLE_CLIENT
  2865. #process_mode = PROCESS_MODE_CONTINUOUS_RACK
  2866. CarlaHost.set_option(OPTION_PROCESS_MODE, process_mode, "")
  2867. CarlaHost.set_option(OPTION_MAX_PARAMETERS, MAX_PARAMETERS, "")
  2868. CarlaHost.set_option(OPTION_PROCESS_HQ, proccess_hq, "")
  2869. CarlaHost.set_option(OPTION_PREFER_UI_BRIDGES, prefer_ui_bridges, "")
  2870. CarlaHost.set_option(OPTION_OSC_GUI_TIMEOUT, osc_gui_timeout, "")
  2871. CarlaHost.set_option(OPTION_USE_DSSI_CHUNKS, use_dssi_chunks, "")
  2872. if carla_bridge_unix32:
  2873. CarlaHost.set_option(OPTION_PATH_BRIDGE_UNIX32, 0, carla_bridge_unix32)
  2874. if carla_bridge_unix64:
  2875. CarlaHost.set_option(OPTION_PATH_BRIDGE_UNIX64, 0, carla_bridge_unix64)
  2876. if carla_bridge_win32:
  2877. CarlaHost.set_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32)
  2878. if carla_bridge_win64:
  2879. CarlaHost.set_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64)
  2880. if carla_bridge_lv2_gtk2:
  2881. CarlaHost.set_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2)
  2882. if carla_bridge_lv2_qt4:
  2883. CarlaHost.set_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4)
  2884. if carla_bridge_lv2_x11:
  2885. CarlaHost.set_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11)
  2886. if carla_bridge_vst_x11:
  2887. CarlaHost.set_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11)
  2888. if not CarlaHost.engine_init("Carla"):
  2889. CustomMessageBox(None, QMessageBox.Critical, "Error", "Could not connect to JACK",
  2890. cString(CarlaHost.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  2891. sys.exit(1)
  2892. # Set-up custom signal handling
  2893. set_up_signals(gui)
  2894. # Show GUI
  2895. gui.show()
  2896. if project_filename:
  2897. gui.m_project_filename = project_filename
  2898. gui.load_project()
  2899. gui.setWindowTitle("Carla - %s" % os.path.basename(project_filename))
  2900. # App-Loop
  2901. ret = app.exec_()
  2902. # Close Host
  2903. if CarlaHost.is_engine_running() and not CarlaHost.engine_close():
  2904. print(cString(CarlaHost.get_last_error()))
  2905. # Exit properly
  2906. sys.exit(ret)