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.

3296 lines
126KB

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