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

1734 lines
71KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin host
  4. # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the GPL.txt file
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from time import sleep
  20. from PyQt4.QtCore import Qt, QModelIndex, QPointF, QSize
  21. from PyQt4.QtGui import QApplication, QDialogButtonBox, QFileSystemModel, QMainWindow, QResizeEvent
  22. # ------------------------------------------------------------------------------------------------------------
  23. # Imports (Custom Stuff)
  24. import patchcanvas
  25. import ui_carla
  26. import ui_carla_settings
  27. from carla_backend import * # FIXME, remove later
  28. from carla_shared import *
  29. # ------------------------------------------------------------------------------------------------------------
  30. # Try Import OpenGL
  31. try:
  32. from PyQt4.QtOpenGL import QGLWidget
  33. hasGL = True
  34. except:
  35. hasGL = False
  36. # ------------------------------------------------------------------------------------------------------------
  37. # Static Variables
  38. DEFAULT_CANVAS_WIDTH = 3100
  39. DEFAULT_CANVAS_HEIGHT = 2400
  40. # Tab indexes
  41. TAB_INDEX_MAIN = 0
  42. TAB_INDEX_CANVAS = 1
  43. TAB_INDEX_CARLA_ENGINE = 2
  44. TAB_INDEX_CARLA_PATHS = 3
  45. TAB_INDEX_NONE = 4
  46. # Single and Multiple client mode is only for JACK,
  47. # but we still want to match QComboBox index to defines,
  48. # so add +2 pos padding if driverName != "JACK".
  49. PROCESS_MODE_NON_JACK_PADDING = 2
  50. # Carla defaults
  51. CARLA_DEFAULT_PROCESS_HIGH_PRECISION = False
  52. CARLA_DEFAULT_MAX_PARAMETERS = 200
  53. CARLA_DEFAULT_FORCE_STEREO = False
  54. CARLA_DEFAULT_USE_DSSI_VST_CHUNKS = False
  55. CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False
  56. CARLA_DEFAULT_PREFER_UI_BRIDGES = True
  57. CARLA_DEFAULT_OSC_UI_TIMEOUT = 4000
  58. CARLA_DEFAULT_DISABLE_CHECKS = False
  59. # PatchCanvas defines
  60. CANVAS_ANTIALIASING_SMALL = 1
  61. CANVAS_EYECANDY_SMALL = 1
  62. # ------------------------------------------------------------------------------------------------------------
  63. # Settings Dialog
  64. class CarlaSettingsW(QDialog):
  65. def __init__(self, parent):
  66. QDialog.__init__(self, parent)
  67. self.ui = ui_carla_settings.Ui_CarlaSettingsW()
  68. self.ui.setupUi(self)
  69. # -------------------------------------------------------------
  70. # Set-up GUI
  71. driverCount = Carla.host.get_engine_driver_count()
  72. for i in range(driverCount):
  73. driverName = cString(Carla.host.get_engine_driver_name(i))
  74. self.ui.cb_engine_audio_driver.addItem(driverName)
  75. # -------------------------------------------------------------
  76. # Load settings
  77. self.loadSettings()
  78. if not hasGL:
  79. self.ui.cb_canvas_use_opengl.setChecked(False)
  80. self.ui.cb_canvas_use_opengl.setEnabled(False)
  81. if WINDOWS:
  82. self.ui.ch_engine_dssi_chunks.setChecked(False)
  83. self.ui.ch_engine_dssi_chunks.setEnabled(False)
  84. # -------------------------------------------------------------
  85. # Set-up connections
  86. self.connect(self, SIGNAL("accepted()"), SLOT("slot_saveSettings()"))
  87. self.connect(self.ui.buttonBox.button(QDialogButtonBox.Reset), SIGNAL("clicked()"), SLOT("slot_resetSettings()"))
  88. self.connect(self.ui.b_main_def_folder_open, SIGNAL("clicked()"), SLOT("slot_getAndSetProjectPath()"))
  89. self.connect(self.ui.cb_engine_audio_driver, SIGNAL("currentIndexChanged(int)"), SLOT("slot_engineAudioDriverChanged()"))
  90. self.connect(self.ui.b_paths_add, SIGNAL("clicked()"), SLOT("slot_addPluginPath()"))
  91. self.connect(self.ui.b_paths_remove, SIGNAL("clicked()"), SLOT("slot_removePluginPath()"))
  92. self.connect(self.ui.b_paths_change, SIGNAL("clicked()"), SLOT("slot_changePluginPath()"))
  93. self.connect(self.ui.tw_paths, SIGNAL("currentChanged(int)"), SLOT("slot_pluginPathTabChanged(int)"))
  94. self.connect(self.ui.lw_ladspa, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  95. self.connect(self.ui.lw_dssi, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  96. self.connect(self.ui.lw_lv2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  97. self.connect(self.ui.lw_vst, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  98. self.connect(self.ui.lw_sf2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  99. # -------------------------------------------------------------
  100. # Post-connect setup
  101. self.ui.lw_ladspa.setCurrentRow(0)
  102. self.ui.lw_dssi.setCurrentRow(0)
  103. self.ui.lw_lv2.setCurrentRow(0)
  104. self.ui.lw_vst.setCurrentRow(0)
  105. self.ui.lw_gig.setCurrentRow(0)
  106. self.ui.lw_sf2.setCurrentRow(0)
  107. self.ui.lw_sfz.setCurrentRow(0)
  108. self.ui.lw_page.setCurrentCell(0, 0)
  109. def loadSettings(self):
  110. settings = QSettings()
  111. # ---------------------------------------
  112. self.ui.le_main_def_folder.setText(settings.value("Main/DefaultProjectFolder", HOME, type=str))
  113. self.ui.sb_gui_refresh.setValue(settings.value("Main/RefreshInterval", 50, type=int))
  114. # ---------------------------------------
  115. self.ui.cb_canvas_hide_groups.setChecked(settings.value("Canvas/AutoHideGroups", False, type=bool))
  116. self.ui.cb_canvas_bezier_lines.setChecked(settings.value("Canvas/UseBezierLines", True, type=bool))
  117. self.ui.cb_canvas_eyecandy.setCheckState(settings.value("Canvas/EyeCandy", CANVAS_EYECANDY_SMALL, type=int))
  118. self.ui.cb_canvas_use_opengl.setChecked(settings.value("Canvas/UseOpenGL", False, type=bool))
  119. self.ui.cb_canvas_render_aa.setCheckState(settings.value("Canvas/Antialiasing", CANVAS_ANTIALIASING_SMALL, type=int))
  120. self.ui.cb_canvas_render_hq_aa.setChecked(settings.value("Canvas/HighQualityAntialiasing", False, type=bool))
  121. themeName = settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str)
  122. for i in range(patchcanvas.Theme.THEME_MAX):
  123. thisThemeName = patchcanvas.getThemeName(i)
  124. self.ui.cb_canvas_theme.addItem(thisThemeName)
  125. if thisThemeName == themeName:
  126. self.ui.cb_canvas_theme.setCurrentIndex(i)
  127. # --------------------------------------------
  128. if WINDOWS:
  129. defaultDriver = "DirectSound"
  130. elif MACOS:
  131. defaultDriver = "CoreAudio"
  132. else:
  133. defaultDriver = "JACK"
  134. audioDriver = settings.value("Engine/AudioDriver", defaultDriver, type=str)
  135. for i in range(self.ui.cb_engine_audio_driver.count()):
  136. if self.ui.cb_engine_audio_driver.itemText(i) == audioDriver:
  137. self.ui.cb_engine_audio_driver.setCurrentIndex(i)
  138. break
  139. else:
  140. self.ui.cb_engine_audio_driver.setCurrentIndex(-1)
  141. if audioDriver == "JACK":
  142. processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int)
  143. self.ui.cb_engine_process_mode_jack.setCurrentIndex(processModeIndex)
  144. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  145. else:
  146. processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_CONTINUOUS_RACK, type=int)
  147. processModeIndex -= PROCESS_MODE_NON_JACK_PADDING
  148. self.ui.cb_engine_process_mode_other.setCurrentIndex(processModeIndex)
  149. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  150. self.ui.sb_engine_max_params.setValue(settings.value("Engine/MaxParameters", CARLA_DEFAULT_MAX_PARAMETERS, type=int))
  151. self.ui.ch_engine_prefer_ui_bridges.setChecked(settings.value("Engine/PreferUiBridges", CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool))
  152. self.ui.sb_engine_oscgui_timeout.setValue(settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_OSC_UI_TIMEOUT, type=int))
  153. self.ui.ch_engine_disable_checks.setChecked(settings.value("Engine/DisableChecks", CARLA_DEFAULT_DISABLE_CHECKS, type=bool))
  154. self.ui.ch_engine_dssi_chunks.setChecked(settings.value("Engine/UseDssiVstChunks", CARLA_DEFAULT_USE_DSSI_VST_CHUNKS, type=bool))
  155. self.ui.ch_engine_prefer_plugin_bridges.setChecked(settings.value("Engine/PreferPluginBridges", CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool))
  156. self.ui.ch_engine_force_stereo.setChecked(settings.value("Engine/ForceStereo", CARLA_DEFAULT_FORCE_STEREO, type=bool))
  157. # --------------------------------------------
  158. ladspas = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH))
  159. dssis = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH))
  160. lv2s = toList(settings.value("Paths/LV2", Carla.LV2_PATH))
  161. vsts = toList(settings.value("Paths/VST", Carla.VST_PATH))
  162. gigs = toList(settings.value("Paths/GIG", Carla.GIG_PATH))
  163. sf2s = toList(settings.value("Paths/SF2", Carla.SF2_PATH))
  164. sfzs = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH))
  165. ladspas.sort()
  166. dssis.sort()
  167. lv2s.sort()
  168. vsts.sort()
  169. gigs.sort()
  170. sf2s.sort()
  171. sfzs.sort()
  172. for ladspa in ladspas:
  173. self.ui.lw_ladspa.addItem(ladspa)
  174. for dssi in dssis:
  175. self.ui.lw_dssi.addItem(dssi)
  176. for lv2 in lv2s:
  177. self.ui.lw_lv2.addItem(lv2)
  178. for vst in vsts:
  179. self.ui.lw_vst.addItem(vst)
  180. for gig in gigs:
  181. self.ui.lw_gig.addItem(gig)
  182. for sf2 in sf2s:
  183. self.ui.lw_sf2.addItem(sf2)
  184. for sfz in sfzs:
  185. self.ui.lw_sfz.addItem(sfz)
  186. @pyqtSlot()
  187. def slot_saveSettings(self):
  188. settings = QSettings()
  189. # ---------------------------------------
  190. settings.setValue("Main/RefreshInterval", self.ui.sb_gui_refresh.value())
  191. settings.setValue("Main/DefaultProjectFolder", self.ui.le_main_def_folder.text())
  192. # ---------------------------------------
  193. settings.setValue("Canvas/Theme", self.ui.cb_canvas_theme.currentText())
  194. settings.setValue("Canvas/AutoHideGroups", self.ui.cb_canvas_hide_groups.isChecked())
  195. settings.setValue("Canvas/UseBezierLines", self.ui.cb_canvas_bezier_lines.isChecked())
  196. settings.setValue("Canvas/UseOpenGL", self.ui.cb_canvas_use_opengl.isChecked())
  197. settings.setValue("Canvas/HighQualityAntialiasing", self.ui.cb_canvas_render_hq_aa.isChecked())
  198. # 0, 1, 2 match their enum variants
  199. settings.setValue("Canvas/EyeCandy", self.ui.cb_canvas_eyecandy.checkState())
  200. settings.setValue("Canvas/Antialiasing", self.ui.cb_canvas_render_aa.checkState())
  201. # --------------------------------------------
  202. audioDriver = self.ui.cb_engine_audio_driver.currentText()
  203. settings.setValue("Engine/AudioDriver", audioDriver)
  204. if audioDriver == "JACK":
  205. settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_jack.currentIndex())
  206. else:
  207. settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_other.currentIndex()+PROCESS_MODE_NON_JACK_PADDING)
  208. settings.setValue("Engine/MaxParameters", self.ui.sb_engine_max_params.value())
  209. settings.setValue("Engine/PreferUiBridges", self.ui.ch_engine_prefer_ui_bridges.isChecked())
  210. settings.setValue("Engine/OscUiTimeout", self.ui.sb_engine_oscgui_timeout.value())
  211. settings.setValue("Engine/DisableChecks", self.ui.ch_engine_disable_checks.isChecked())
  212. settings.setValue("Engine/UseDssiVstChunks", self.ui.ch_engine_dssi_chunks.isChecked())
  213. settings.setValue("Engine/PreferPluginBridges", self.ui.ch_engine_prefer_plugin_bridges.isChecked())
  214. settings.setValue("Engine/ForceStereo", self.ui.ch_engine_force_stereo.isChecked())
  215. # --------------------------------------------
  216. # FIXME - find a cleaner way to do this, *.items() ?
  217. ladspas = []
  218. dssis = []
  219. lv2s = []
  220. vsts = []
  221. gigs = []
  222. sf2s = []
  223. sfzs = []
  224. for i in range(self.ui.lw_ladspa.count()):
  225. ladspas.append(self.ui.lw_ladspa.item(i).text())
  226. for i in range(self.ui.lw_dssi.count()):
  227. dssis.append(self.ui.lw_dssi.item(i).text())
  228. for i in range(self.ui.lw_lv2.count()):
  229. lv2s.append(self.ui.lw_lv2.item(i).text())
  230. for i in range(self.ui.lw_vst.count()):
  231. vsts.append(self.ui.lw_vst.item(i).text())
  232. for i in range(self.ui.lw_gig.count()):
  233. gigs.append(self.ui.lw_gig.item(i).text())
  234. for i in range(self.ui.lw_sf2.count()):
  235. sf2s.append(self.ui.lw_sf2.item(i).text())
  236. for i in range(self.ui.lw_sfz.count()):
  237. sfzs.append(self.ui.lw_sfz.item(i).text())
  238. settings.setValue("Paths/LADSPA", ladspas)
  239. settings.setValue("Paths/DSSI", dssis)
  240. settings.setValue("Paths/LV2", lv2s)
  241. settings.setValue("Paths/VST", vsts)
  242. settings.setValue("Paths/GIG", gigs)
  243. settings.setValue("Paths/SF2", sf2s)
  244. settings.setValue("Paths/SFZ", sfzs)
  245. @pyqtSlot()
  246. def slot_resetSettings(self):
  247. if self.ui.lw_page.currentRow() == TAB_INDEX_MAIN:
  248. self.ui.le_main_def_folder.setText(HOME)
  249. self.ui.sb_gui_refresh.setValue(50)
  250. elif self.ui.lw_page.currentRow() == TAB_INDEX_CANVAS:
  251. self.ui.cb_canvas_theme.setCurrentIndex(0)
  252. self.ui.cb_canvas_hide_groups.setChecked(False)
  253. self.ui.cb_canvas_bezier_lines.setChecked(True)
  254. self.ui.cb_canvas_eyecandy.setCheckState(Qt.PartiallyChecked)
  255. self.ui.cb_canvas_use_opengl.setChecked(False)
  256. self.ui.cb_canvas_render_aa.setCheckState(Qt.PartiallyChecked)
  257. self.ui.cb_canvas_render_hq_aa.setChecked(False)
  258. elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_ENGINE:
  259. self.ui.cb_engine_audio_driver.setCurrentIndex(0)
  260. self.ui.sb_engine_max_params.setValue(CARLA_DEFAULT_MAX_PARAMETERS)
  261. self.ui.ch_engine_prefer_ui_bridges.setChecked(CARLA_DEFAULT_PREFER_UI_BRIDGES)
  262. self.ui.sb_engine_oscgui_timeout.setValue(CARLA_DEFAULT_OSC_UI_TIMEOUT)
  263. self.ui.ch_engine_disable_checks.setChecked(CARLA_DEFAULT_DISABLE_CHECKS)
  264. self.ui.ch_engine_dssi_chunks.setChecked(CARLA_DEFAULT_USE_DSSI_VST_CHUNKS)
  265. self.ui.ch_engine_prefer_plugin_bridges.setChecked(CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES)
  266. self.ui.ch_engine_force_stereo.setChecked(CARLA_DEFAULT_FORCE_STEREO)
  267. if self.ui.cb_engine_audio_driver.currentText() == "JACK":
  268. self.ui.cb_engine_process_mode_jack.setCurrentIndex(PROCESS_MODE_MULTIPLE_CLIENTS)
  269. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  270. else:
  271. self.ui.cb_engine_process_mode_other.setCurrentIndex(PROCESS_MODE_CONTINUOUS_RACK-PROCESS_MODE_NON_JACK_PADDING)
  272. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  273. elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_PATHS:
  274. if self.ui.tw_paths.currentIndex() == 0:
  275. Carla.LADSPA_PATH.sort()
  276. self.ui.lw_ladspa.clear()
  277. for ladspa in Carla.LADSPA_PATH:
  278. self.ui.lw_ladspa.addItem(ladspa)
  279. elif self.ui.tw_paths.currentIndex() == 1:
  280. Carla.DSSI_PATH.sort()
  281. self.ui.lw_dssi.clear()
  282. for dssi in Carla.DSSI_PATH:
  283. self.ui.lw_dssi.addItem(dssi)
  284. elif self.ui.tw_paths.currentIndex() == 2:
  285. Carla.LV2_PATH.sort()
  286. self.ui.lw_lv2.clear()
  287. for lv2 in Carla.LV2_PATH:
  288. self.ui.lw_lv2.addItem(lv2)
  289. elif self.ui.tw_paths.currentIndex() == 3:
  290. Carla.VST_PATH.sort()
  291. self.ui.lw_vst.clear()
  292. for vst in Carla.VST_PATH:
  293. self.ui.lw_vst.addItem(vst)
  294. elif self.ui.tw_paths.currentIndex() == 4:
  295. Carla.GIG_PATH.sort()
  296. self.ui.lw_gig.clear()
  297. for gig in Carla.GIG_PATH:
  298. self.ui.lw_gig.addItem(gig)
  299. elif self.ui.tw_paths.currentIndex() == 5:
  300. Carla.SF2_PATH.sort()
  301. self.ui.lw_sf2.clear()
  302. for sf2 in Carla.SF2_PATH:
  303. self.ui.lw_sf2.addItem(sf2)
  304. elif self.ui.tw_paths.currentIndex() == 6:
  305. Carla.SFZ_PATH.sort()
  306. self.ui.lw_sfz.clear()
  307. for sfz in Carla.SFZ_PATH:
  308. self.ui.lw_sfz.addItem(sfz)
  309. @pyqtSlot()
  310. def slot_getAndSetProjectPath(self):
  311. getAndSetPath(self, self.ui.le_main_def_folder.text(), self.ui.le_main_def_folder)
  312. @pyqtSlot()
  313. def slot_engineAudioDriverChanged(self):
  314. if self.ui.cb_engine_audio_driver.currentText() == "JACK":
  315. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  316. else:
  317. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  318. @pyqtSlot()
  319. def slot_addPluginPath(self):
  320. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), "", QFileDialog.ShowDirsOnly)
  321. if newPath:
  322. if self.ui.tw_paths.currentIndex() == 0:
  323. self.ui.lw_ladspa.addItem(newPath)
  324. elif self.ui.tw_paths.currentIndex() == 1:
  325. self.ui.lw_dssi.addItem(newPath)
  326. elif self.ui.tw_paths.currentIndex() == 2:
  327. self.ui.lw_lv2.addItem(newPath)
  328. elif self.ui.tw_paths.currentIndex() == 3:
  329. self.ui.lw_vst.addItem(newPath)
  330. elif self.ui.tw_paths.currentIndex() == 4:
  331. self.ui.lw_gig.addItem(newPath)
  332. elif self.ui.tw_paths.currentIndex() == 5:
  333. self.ui.lw_sf2.addItem(newPath)
  334. elif self.ui.tw_paths.currentIndex() == 6:
  335. self.ui.lw_sfz.addItem(newPath)
  336. @pyqtSlot()
  337. def slot_removePluginPath(self):
  338. if self.ui.tw_paths.currentIndex() == 0:
  339. self.ui.lw_ladspa.takeItem(self.ui.lw_ladspa.currentRow())
  340. elif self.ui.tw_paths.currentIndex() == 1:
  341. self.ui.lw_dssi.takeItem(self.ui.lw_dssi.currentRow())
  342. elif self.ui.tw_paths.currentIndex() == 2:
  343. self.ui.lw_lv2.takeItem(self.ui.lw_lv2.currentRow())
  344. elif self.ui.tw_paths.currentIndex() == 3:
  345. self.ui.lw_vst.takeItem(self.ui.lw_vst.currentRow())
  346. elif self.ui.tw_paths.currentIndex() == 4:
  347. self.ui.lw_gig.takeItem(self.ui.lw_gig.currentRow())
  348. elif self.ui.tw_paths.currentIndex() == 5:
  349. self.ui.lw_sf2.takeItem(self.ui.lw_sf2.currentRow())
  350. elif self.ui.tw_paths.currentIndex() == 6:
  351. self.ui.lw_sfz.takeItem(self.ui.lw_sfz.currentRow())
  352. @pyqtSlot()
  353. def slot_changePluginPath(self):
  354. if self.ui.tw_paths.currentIndex() == 0:
  355. currentPath = self.ui.lw_ladspa.currentItem().text()
  356. elif self.ui.tw_paths.currentIndex() == 1:
  357. currentPath = self.ui.lw_dssi.currentItem().text()
  358. elif self.ui.tw_paths.currentIndex() == 2:
  359. currentPath = self.ui.lw_lv2.currentItem().text()
  360. elif self.ui.tw_paths.currentIndex() == 3:
  361. currentPath = self.ui.lw_vst.currentItem().text()
  362. elif self.ui.tw_paths.currentIndex() == 4:
  363. currentPath = self.ui.lw_gig.currentItem().text()
  364. elif self.ui.tw_paths.currentIndex() == 5:
  365. currentPath = self.ui.lw_sf2.currentItem().text()
  366. elif self.ui.tw_paths.currentIndex() == 6:
  367. currentPath = self.ui.lw_sfz.currentItem().text()
  368. else:
  369. currentPath = ""
  370. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), currentPath, QFileDialog.ShowDirsOnly)
  371. if newPath:
  372. if self.ui.tw_paths.currentIndex() == 0:
  373. self.ui.lw_ladspa.currentItem().setText(newPath)
  374. elif self.ui.tw_paths.currentIndex() == 1:
  375. self.ui.lw_dssi.currentItem().setText(newPath)
  376. elif self.ui.tw_paths.currentIndex() == 2:
  377. self.ui.lw_lv2.currentItem().setText(newPath)
  378. elif self.ui.tw_paths.currentIndex() == 3:
  379. self.ui.lw_vst.currentItem().setText(newPath)
  380. elif self.ui.tw_paths.currentIndex() == 4:
  381. self.ui.lw_gig.currentItem().setText(newPath)
  382. elif self.ui.tw_paths.currentIndex() == 5:
  383. self.ui.lw_sf2.currentItem().setText(newPath)
  384. elif self.ui.tw_paths.currentIndex() == 6:
  385. self.ui.lw_sfz.currentItem().setText(newPath)
  386. @pyqtSlot(int)
  387. def slot_pluginPathTabChanged(self, index):
  388. if index == 0:
  389. row = self.ui.lw_ladspa.currentRow()
  390. elif index == 1:
  391. row = self.ui.lw_dssi.currentRow()
  392. elif index == 2:
  393. row = self.ui.lw_lv2.currentRow()
  394. elif index == 3:
  395. row = self.ui.lw_vst.currentRow()
  396. elif index == 4:
  397. row = self.ui.lw_gig.currentRow()
  398. elif index == 5:
  399. row = self.ui.lw_sf2.currentRow()
  400. elif index == 6:
  401. row = self.ui.lw_sfz.currentRow()
  402. else:
  403. row = -1
  404. check = bool(row >= 0)
  405. self.ui.b_paths_remove.setEnabled(check)
  406. self.ui.b_paths_change.setEnabled(check)
  407. @pyqtSlot(int)
  408. def slot_pluginPathRowChanged(self, row):
  409. check = bool(row >= 0)
  410. self.ui.b_paths_remove.setEnabled(check)
  411. self.ui.b_paths_change.setEnabled(check)
  412. def done(self, r):
  413. QDialog.done(self, r)
  414. self.close()
  415. # ------------------------------------------------------------------------------------------------------------
  416. # Main Window
  417. class CarlaMainW(QMainWindow):
  418. def __init__(self, parent=None):
  419. QMainWindow.__init__(self, parent)
  420. self.ui = ui_carla.Ui_CarlaMainW()
  421. self.ui.setupUi(self)
  422. # -------------------------------------------------------------
  423. # Load Settings
  424. self.loadSettings(True)
  425. self.loadRDFs()
  426. self.setStyleSheet("""
  427. QWidget#w_plugins {
  428. background-color: qlineargradient(spread:pad,
  429. x1:0.0, y1:0.0,
  430. x2:0.2, y2:1.0,
  431. stop:0 rgb( 7, 7, 7),
  432. stop:1 rgb(28, 28, 28)
  433. );
  434. }
  435. """)
  436. # -------------------------------------------------------------
  437. # Internal stuff
  438. self.fEngineStarted = False
  439. self.fFirstEngineInit = False
  440. self.fProjectFilename = None
  441. self.fProjectLoading = False
  442. self.fPluginCount = 0
  443. self.fPluginList = []
  444. self.fIdleTimerFast = 0
  445. self.fIdleTimerSlow = 0
  446. self.fLastLoadedPluginId = -1
  447. #self._nsmAnnounce2str = ""
  448. #self._nsmOpen1str = ""
  449. #self._nsmOpen2str = ""
  450. #self.nsm_server = None
  451. #self.nsm_url = None
  452. # -------------------------------------------------------------
  453. # Set-up GUI stuff
  454. self.fDirModel = QFileSystemModel(self)
  455. self.fDirModel.setNameFilters(cString(Carla.host.get_supported_file_types()).split(";"))
  456. self.fDirModel.setRootPath(HOME)
  457. self.ui.fileTreeView.setModel(self.fDirModel)
  458. self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME))
  459. self.ui.fileTreeView.setColumnHidden(1, True)
  460. self.ui.fileTreeView.setColumnHidden(2, True)
  461. self.ui.fileTreeView.setColumnHidden(3, True)
  462. self.ui.fileTreeView.setHeaderHidden(True)
  463. self.ui.act_engine_start.setEnabled(False)
  464. self.ui.act_engine_stop.setEnabled(False)
  465. self.ui.act_plugin_remove_all.setEnabled(False)
  466. # FIXME: Qt4 needs this so it properly create & resize the canvas
  467. self.ui.tabMain.setCurrentIndex(1)
  468. self.ui.tabMain.setCurrentIndex(0)
  469. # -------------------------------------------------------------
  470. # Set-up Canvas
  471. self.scene = patchcanvas.PatchScene(self, self.ui.graphicsView)
  472. self.ui.graphicsView.setScene(self.scene)
  473. #self.ui.graphicsView.setRenderHint(QPainter.Antialiasing, bool(self.fSavedSettings["Canvas/Antialiasing"] == patchcanvas.ANTIALIASING_FULL))
  474. #if self.fSavedSettings["Canvas/UseOpenGL"] and hasGL:
  475. #self.ui.graphicsView.setViewport(QGLWidget(self.ui.graphicsView))
  476. #self.ui.graphicsView.setRenderHint(QPainter.HighQualityAntialiasing, self.fSavedSettings["Canvas/HighQualityAntialiasing"])
  477. pOptions = patchcanvas.options_t()
  478. pOptions.theme_name = self.fSavedSettings["Canvas/Theme"]
  479. pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
  480. pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
  481. pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
  482. pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
  483. pFeatures = patchcanvas.features_t()
  484. pFeatures.group_info = False
  485. pFeatures.group_rename = False
  486. pFeatures.port_info = False
  487. pFeatures.port_rename = False
  488. pFeatures.handle_group_pos = True
  489. patchcanvas.setOptions(pOptions)
  490. patchcanvas.setFeatures(pFeatures)
  491. patchcanvas.init("Carla", self.scene, canvasCallback, False)
  492. patchcanvas.setCanvasSize(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
  493. patchcanvas.setInitialPos(DEFAULT_CANVAS_WIDTH / 2, DEFAULT_CANVAS_HEIGHT / 2)
  494. self.ui.graphicsView.setSceneRect(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
  495. # -------------------------------------------------------------
  496. # Set-up Canvas Preview
  497. self.ui.miniCanvasPreview.setRealParent(self)
  498. self.ui.miniCanvasPreview.setViewTheme(patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color())
  499. self.ui.miniCanvasPreview.init(self.scene, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
  500. QTimer.singleShot(100, self, SLOT("slot_miniCanvasInit()"))
  501. #self.m_fakeEdit = PluginEdit(self, -1)
  502. #self.m_curEdit = self.m_fakeEdit
  503. #self.w_edit.layout().addWidget(self.m_curEdit)
  504. #self.w_edit.layout().addStretch()
  505. # -------------------------------------------------------------
  506. # Connect actions to functions
  507. self.connect(self.ui.act_file_new, SIGNAL("triggered()"), SLOT("slot_fileNew()"))
  508. self.connect(self.ui.act_file_open, SIGNAL("triggered()"), SLOT("slot_fileOpen()"))
  509. self.connect(self.ui.act_file_save, SIGNAL("triggered()"), SLOT("slot_fileSave()"))
  510. self.connect(self.ui.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_fileSaveAs()"))
  511. self.connect(self.ui.act_engine_start, SIGNAL("triggered()"), SLOT("slot_engineStart()"))
  512. self.connect(self.ui.act_engine_stop, SIGNAL("triggered()"), SLOT("slot_engineStop()"))
  513. self.connect(self.ui.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_pluginAdd()"))
  514. self.connect(self.ui.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_pluginRemoveAll()"))
  515. self.connect(self.ui.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()"))
  516. self.connect(self.ui.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarla()"))
  517. self.connect(self.ui.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  518. self.connect(self.ui.ch_transport, SIGNAL("currentIndexChanged(int)"), SLOT("slot_transportModeChanged(int)"))
  519. self.connect(self.ui.b_transport_play, SIGNAL("clicked(bool)"), SLOT("slot_transportPlayPause(bool)"))
  520. self.connect(self.ui.b_transport_stop, SIGNAL("clicked()"), SLOT("slot_transportStop()"))
  521. self.connect(self.ui.fileTreeView, SIGNAL("doubleClicked(QModelIndex)"), SLOT("slot_fileTreeDoubleClicked(QModelIndex)"))
  522. self.connect(self.ui.miniCanvasPreview, SIGNAL("miniCanvasMoved(double, double)"), SLOT("slot_miniCanvasMoved(double, double)"))
  523. self.connect(self.ui.graphicsView.horizontalScrollBar(), SIGNAL("valueChanged(int)"), SLOT("slot_horizontalScrollBarChanged(int)"))
  524. self.connect(self.ui.graphicsView.verticalScrollBar(), SIGNAL("valueChanged(int)"), SLOT("slot_verticalScrollBarChanged(int)"))
  525. self.connect(self.scene, SIGNAL("sceneGroupMoved(int, int, QPointF)"), SLOT("slot_canvasItemMoved(int, int, QPointF)"))
  526. self.connect(self.scene, SIGNAL("scaleChanged(double)"), SLOT("slot_canvasScaleChanged(double)"))
  527. self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_handleSIGUSR1()"))
  528. self.connect(self, SIGNAL("SIGTERM()"), SLOT("slot_handleSIGTERM()"))
  529. self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)"))
  530. self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)"))
  531. self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)"))
  532. self.connect(self, SIGNAL("PluginRenamedCallback(int, QString)"), SLOT("slot_handlePluginRenamedCallback(int, QString)"))
  533. self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)"))
  534. self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)"))
  535. self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)"))
  536. self.connect(self, SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiCcChangedCallback(int, int, int)"))
  537. self.connect(self, SIGNAL("ProgramChangedCallback(int, int)"), SLOT("slot_handleProgramChangedCallback(int, int)"))
  538. self.connect(self, SIGNAL("MidiProgramChangedCallback(int, int)"), SLOT("slot_handleMidiProgramChangedCallback(int, int)"))
  539. self.connect(self, SIGNAL("NoteOnCallback(int, int, int, int)"), SLOT("slot_handleNoteOnCallback(int, int, int, int)"))
  540. self.connect(self, SIGNAL("NoteOffCallback(int, int, int)"), SLOT("slot_handleNoteOffCallback(int, int, int)"))
  541. self.connect(self, SIGNAL("ShowGuiCallback(int, int)"), SLOT("slot_handleShowGuiCallback(int, int)"))
  542. self.connect(self, SIGNAL("UpdateCallback(int)"), SLOT("slot_handleUpdateCallback(int)"))
  543. self.connect(self, SIGNAL("ReloadInfoCallback(int)"), SLOT("slot_handleReloadInfoCallback(int)"))
  544. self.connect(self, SIGNAL("ReloadParametersCallback(int)"), SLOT("slot_handleReloadParametersCallback(int)"))
  545. self.connect(self, SIGNAL("ReloadProgramsCallback(int)"), SLOT("slot_handleReloadProgramsCallback(int)"))
  546. self.connect(self, SIGNAL("ReloadAllCallback(int)"), SLOT("slot_handleReloadAllCallback(int)"))
  547. self.connect(self, SIGNAL("PatchbayClientAddedCallback(int, QString)"), SLOT("slot_handlePatchbayClientAddedCallback(int, QString)"))
  548. self.connect(self, SIGNAL("PatchbayClientRemovedCallback(int)"), SLOT("slot_handlePatchbayClientRemovedCallback(int)"))
  549. self.connect(self, SIGNAL("PatchbayClientRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayClientRenamedCallback(int, QString)"))
  550. self.connect(self, SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), SLOT("slot_handlePatchbayPortAddedCallback(int, int, int, QString)"))
  551. self.connect(self, SIGNAL("PatchbayPortRemovedCallback(int)"), SLOT("slot_handlePatchbayPortRemovedCallback(int)"))
  552. self.connect(self, SIGNAL("PatchbayPortRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayPortRenamedCallback(int, QString)"))
  553. self.connect(self, SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), SLOT("slot_handlePatchbayConnectionAddedCallback(int, int, int)"))
  554. self.connect(self, SIGNAL("PatchbayConnectionRemovedCallback(int)"), SLOT("slot_handlePatchbayConnectionRemovedCallback(int)"))
  555. #self.connect(self, SIGNAL("NSM_AnnounceCallback()"), SLOT("slot_handleNSM_AnnounceCallback()"))
  556. #self.connect(self, SIGNAL("NSM_Open1Callback()"), SLOT("slot_handleNSM_Open1Callback()"))
  557. #self.connect(self, SIGNAL("NSM_Open2Callback()"), SLOT("slot_handleNSM_Open2Callback()"))
  558. #self.connect(self, SIGNAL("NSM_SaveCallback()"), SLOT("slot_handleNSM_SaveCallback()"))
  559. self.connect(self, SIGNAL("ErrorCallback(QString)"), SLOT("slot_handleErrorCallback(QString)"))
  560. self.connect(self, SIGNAL("QuitCallback()"), SLOT("slot_handleQuitCallback()"))
  561. #NSM_URL = os.getenv("NSM_URL")
  562. #if NSM_URL:
  563. #Carla.host.nsm_announce(NSM_URL, os.getpid())
  564. #else:
  565. QTimer.singleShot(0, self, SLOT("slot_engineStart()"))
  566. @pyqtSlot(QModelIndex)
  567. def slot_fileTreeDoubleClicked(self, modelIndex):
  568. filename = self.fDirModel.filePath(modelIndex)
  569. print(filename)
  570. if not os.path.exists(filename):
  571. return
  572. if not os.path.isfile(filename):
  573. return
  574. basename = os.path.basename(filename)
  575. extension = filename.rsplit(".", 1)[-1].lower()
  576. if extension == "carxp":
  577. Carla.host.load_project(filename)
  578. elif extension == "gig":
  579. Carla.host.add_plugin(BINARY_NATIVE, PLUGIN_GIG, filename, None, basename, None)
  580. elif extension == "sf2":
  581. Carla.host.add_plugin(BINARY_NATIVE, PLUGIN_SF2, filename, None, basename, None)
  582. elif extension == "sfz":
  583. Carla.host.add_plugin(BINARY_NATIVE, PLUGIN_SFZ, filename, None, basename, None)
  584. elif extension in ("aac", "flac", "oga", "ogg", "mp3", "wav"):
  585. self.fLastLoadedPluginId = -2
  586. if Carla.host.add_plugin(BINARY_NATIVE, PLUGIN_INTERNAL, None, basename, "audiofile", None):
  587. while (self.fLastLoadedPluginId == -2): sleep(0.2)
  588. idx = self.fLastLoadedPluginId
  589. self.fLastLoadedPluginId = -1
  590. Carla.host.set_custom_data(idx, CUSTOM_DATA_STRING, "file00", filename)
  591. else:
  592. self.fLastLoadedPluginId = -1
  593. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"),
  594. cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  595. elif extension in ("mid", "midi"):
  596. self.fLastLoadedPluginId = -2
  597. if Carla.host.add_plugin(BINARY_NATIVE, PLUGIN_INTERNAL, None, basename, "midifile", None):
  598. while (self.fLastLoadedPluginId == -2): sleep(0.2)
  599. idx = self.fLastLoadedPluginId
  600. self.fLastLoadedPluginId = -1
  601. Carla.host.set_custom_data(idx, CUSTOM_DATA_STRING, "file", filename)
  602. else:
  603. self.fLastLoadedPluginId = -1
  604. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"),
  605. cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  606. @pyqtSlot(float)
  607. def slot_canvasScaleChanged(self, scale):
  608. self.ui.miniCanvasPreview.setViewScale(scale)
  609. @pyqtSlot(int, int, QPointF)
  610. def slot_canvasItemMoved(self, group_id, split_mode, pos):
  611. self.ui.miniCanvasPreview.update()
  612. @pyqtSlot(int)
  613. def slot_horizontalScrollBarChanged(self, value):
  614. maximum = self.ui.graphicsView.horizontalScrollBar().maximum()
  615. if maximum == 0:
  616. xp = 0
  617. else:
  618. xp = float(value) / maximum
  619. self.ui.miniCanvasPreview.setViewPosX(xp)
  620. @pyqtSlot(int)
  621. def slot_verticalScrollBarChanged(self, value):
  622. maximum = self.ui.graphicsView.verticalScrollBar().maximum()
  623. if maximum == 0:
  624. yp = 0
  625. else:
  626. yp = float(value) / maximum
  627. self.ui.miniCanvasPreview.setViewPosY(yp)
  628. @pyqtSlot()
  629. def slot_miniCanvasInit(self):
  630. settings = QSettings()
  631. self.ui.graphicsView.horizontalScrollBar().setValue(settings.value("HorizontalScrollBarValue", DEFAULT_CANVAS_WIDTH / 3, type=int))
  632. self.ui.graphicsView.verticalScrollBar().setValue(settings.value("VerticalScrollBarValue", DEFAULT_CANVAS_HEIGHT * 3 / 8, type=int))
  633. @pyqtSlot(float, float)
  634. def slot_miniCanvasMoved(self, xp, yp):
  635. self.ui.graphicsView.horizontalScrollBar().setValue(xp * DEFAULT_CANVAS_WIDTH)
  636. self.ui.graphicsView.verticalScrollBar().setValue(yp * DEFAULT_CANVAS_HEIGHT)
  637. @pyqtSlot()
  638. def slot_miniCanvasCheckAll(self):
  639. self.slot_miniCanvasCheckSize()
  640. self.slot_horizontalScrollBarChanged(self.ui.graphicsView.horizontalScrollBar().value())
  641. self.slot_verticalScrollBarChanged(self.ui.graphicsView.verticalScrollBar().value())
  642. @pyqtSlot()
  643. def slot_miniCanvasCheckSize(self):
  644. self.ui.miniCanvasPreview.setViewSize(float(self.ui.graphicsView.width()) / DEFAULT_CANVAS_WIDTH, float(self.ui.graphicsView.height()) / DEFAULT_CANVAS_HEIGHT)
  645. def startEngine(self, clientName = "Carla"):
  646. # ---------------------------------------------
  647. # Engine settings
  648. settings = QSettings()
  649. if LINUX:
  650. defaultMode = PROCESS_MODE_MULTIPLE_CLIENTS
  651. else:
  652. defaultMode = PROCESS_MODE_CONTINUOUS_RACK
  653. Carla.processMode = settings.value("Engine/ProcessMode", defaultMode, type=int)
  654. Carla.maxParameters = settings.value("Engine/MaxParameters", MAX_DEFAULT_PARAMETERS, type=int)
  655. transportMode = settings.value("Engine/TransportMode", TRANSPORT_MODE_JACK, type=int)
  656. forceStereo = settings.value("Engine/ForceStereo", False, type=bool)
  657. preferPluginBridges = settings.value("Engine/PreferPluginBridges", False, type=bool)
  658. preferUiBridges = settings.value("Engine/PreferUiBridges", True, type=bool)
  659. useDssiVstChunks = settings.value("Engine/UseDssiVstChunks", False, type=bool)
  660. oscUiTimeout = settings.value("Engine/OscUiTimeout", 40, type=int)
  661. preferredBufferSize = settings.value("Engine/PreferredBufferSize", 512, type=int)
  662. preferredSampleRate = settings.value("Engine/PreferredSampleRate", 44100, type=int)
  663. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  664. forceStereo = True
  665. elif Carla.processMode == PROCESS_MODE_MULTIPLE_CLIENTS and os.getenv("LADISH_APP_NAME"):
  666. print("LADISH detected but using multiple clients (not allowed), forcing single client now")
  667. Carla.processMode = PROCESS_MODE_SINGLE_CLIENT
  668. Carla.host.set_engine_option(OPTION_PROCESS_MODE, Carla.processMode, "")
  669. Carla.host.set_engine_option(OPTION_MAX_PARAMETERS, Carla.maxParameters, "")
  670. Carla.host.set_engine_option(OPTION_FORCE_STEREO, forceStereo, "")
  671. Carla.host.set_engine_option(OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "")
  672. Carla.host.set_engine_option(OPTION_PREFER_UI_BRIDGES, preferUiBridges, "")
  673. Carla.host.set_engine_option(OPTION_USE_DSSI_VST_CHUNKS, useDssiVstChunks, "")
  674. Carla.host.set_engine_option(OPTION_OSC_UI_TIMEOUT, oscUiTimeout, "")
  675. Carla.host.set_engine_option(OPTION_PREFERRED_BUFFER_SIZE, preferredBufferSize, "")
  676. Carla.host.set_engine_option(OPTION_PREFERRED_SAMPLE_RATE, preferredSampleRate, "")
  677. # ---------------------------------------------
  678. # Start
  679. if WINDOWS:
  680. defaultDriver = "DirectSound"
  681. elif MACOS:
  682. defaultDriver = "CoreAudio"
  683. else:
  684. defaultDriver = "JACK"
  685. audioDriver = settings.value("Engine/AudioDriver", defaultDriver, type=str)
  686. if not Carla.host.engine_init(audioDriver, clientName):
  687. if self.fFirstEngineInit:
  688. self.fFirstEngineInit = False
  689. return
  690. audioError = cString(Carla.host.get_last_error())
  691. if audioError:
  692. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver, audioError)))
  693. else:
  694. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver))
  695. return
  696. self.fEngineStarted = True
  697. self.fFirstEngineInit = False
  698. self.fPluginCount = 0
  699. self.fPluginList = []
  700. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  701. maxCount = MAX_RACK_PLUGINS
  702. elif Carla.processMode == PROCESS_MODE_PATCHBAY:
  703. maxCount = MAX_PATCHBAY_PLUGINS
  704. else:
  705. maxCount = MAX_DEFAULT_PLUGINS
  706. self.ui.ch_transport.blockSignals(True)
  707. self.ui.ch_transport.addItem(self.tr("Internal"))
  708. if audioDriver == "JACK":
  709. self.ui.ch_transport.addItem(self.tr("JACK"))
  710. elif transportMode == TRANSPORT_MODE_JACK:
  711. transportMode = TRANSPORT_MODE_INTERNAL
  712. self.ui.ch_transport.setCurrentIndex(transportMode)
  713. self.ui.ch_transport.blockSignals(False)
  714. for x in range(maxCount):
  715. self.fPluginList.append(None)
  716. Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, transportMode, "")
  717. # Peaks
  718. self.fIdleTimerFast = self.startTimer(self.fSavedSettings["Main/RefreshInterval"])
  719. # LEDs and edit dialog parameters
  720. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  721. def stopEngine(self):
  722. if self.fPluginCount > 0:
  723. ask = QMessageBox.question(self, self.tr("Warning"), self.tr("There are still some plugins loaded, you need to remove them to stop the engine.\n"
  724. "Do you want to do this now?"),
  725. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  726. if ask != QMessageBox.Yes:
  727. return
  728. self.removeAllPlugins()
  729. if Carla.host.is_engine_running() and not Carla.host.engine_close():
  730. print(cString(Carla.host.get_last_error()))
  731. self.fEngineStarted = False
  732. self.fPluginCount = 0
  733. self.fPluginList = []
  734. self.killTimer(self.fIdleTimerFast)
  735. self.killTimer(self.fIdleTimerSlow)
  736. settings = QSettings()
  737. settings.setValue("Engine/TransportMode", self.ui.ch_transport.currentIndex())
  738. self.ui.ch_transport.blockSignals(True)
  739. self.ui.ch_transport.clear()
  740. self.ui.ch_transport.blockSignals(False)
  741. patchcanvas.clear()
  742. def loadProject(self, filename):
  743. self.fProjectFilename = filename
  744. self.setWindowTitle("Carla - %s" % os.path.basename(filename))
  745. self.fProjectLoading = True
  746. Carla.host.load_project(filename)
  747. self.fProjectLoading = False
  748. def loadProjectLater(self, filename):
  749. self.fProjectFilename = filename
  750. self.setWindowTitle("Carla - %s" % os.path.basename(filename))
  751. QTimer.singleShot(0, self, SLOT("slot_loadProjectLater()"))
  752. def saveProject(self, filename):
  753. self.fProjectFilename = filename
  754. self.setWindowTitle("Carla - %s" % os.path.basename(filename))
  755. Carla.host.save_project(filename)
  756. def addPlugin(self, btype, ptype, filename, name, label, extraStuff):
  757. if not self.fEngineStarted:
  758. QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
  759. return False
  760. if not Carla.host.add_plugin(btype, ptype, filename, name, label, extraStuff):
  761. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  762. return False
  763. return True
  764. def removeAllPlugins(self):
  765. while (self.ui.w_plugins.layout().takeAt(0)):
  766. pass
  767. self.ui.act_plugin_remove_all.setEnabled(False)
  768. for i in range(self.fPluginCount):
  769. pwidget = self.fPluginList[i]
  770. if pwidget is None:
  771. break
  772. self.fPluginList[i] = None
  773. pwidget.ui.edit_dialog.close()
  774. pwidget.close()
  775. pwidget.deleteLater()
  776. del pwidget
  777. self.fPluginCount = 0
  778. Carla.host.remove_all_plugins()
  779. @pyqtSlot()
  780. def slot_fileNew(self):
  781. self.removeAllPlugins()
  782. self.fProjectFilename = None
  783. self.fProjectLoading = False
  784. self.setWindowTitle("Carla")
  785. @pyqtSlot()
  786. def slot_fileOpen(self):
  787. fileFilter = self.tr("Carla Project File (*.carxp)")
  788. filenameTry = QFileDialog.getOpenFileName(self, self.tr("Open Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)
  789. if filenameTry:
  790. # FIXME - show dialog to user
  791. self.removeAllPlugins()
  792. self.loadProject(filenameTry)
  793. @pyqtSlot()
  794. def slot_fileSave(self, saveAs=False):
  795. if self.fProjectFilename and not saveAs:
  796. return self.saveProject(self.fProjectFilename)
  797. fileFilter = self.tr("Carla Project File (*.carxp)")
  798. filenameTry = QFileDialog.getSaveFileName(self, self.tr("Save Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)
  799. if filenameTry:
  800. if not filenameTry.endswith(".carxp"):
  801. filenameTry += ".carxp"
  802. self.saveProject(filenameTry)
  803. @pyqtSlot()
  804. def slot_fileSaveAs(self):
  805. self.slot_fileSave(True)
  806. @pyqtSlot()
  807. def slot_loadProjectLater(self):
  808. self.fProjectLoading = True
  809. Carla.host.load_project(self.fProjectFilename)
  810. self.fProjectLoading = False
  811. @pyqtSlot()
  812. def slot_engineStart(self):
  813. self.startEngine()
  814. check = Carla.host.is_engine_running()
  815. self.ui.act_file_open.setEnabled(check)
  816. self.ui.act_engine_start.setEnabled(not check)
  817. self.ui.act_engine_stop.setEnabled(check)
  818. self.ui.act_engine_configure.setEnabled(not check)
  819. self.ui.frame_transport.setEnabled(check)
  820. @pyqtSlot()
  821. def slot_engineStop(self):
  822. self.stopEngine()
  823. check = Carla.host.is_engine_running()
  824. self.ui.act_file_open.setEnabled(check)
  825. self.ui.act_engine_start.setEnabled(not check)
  826. self.ui.act_engine_stop.setEnabled(check)
  827. self.ui.frame_transport.setEnabled(check)
  828. @pyqtSlot()
  829. def slot_pluginAdd(self):
  830. dialog = PluginDatabaseW(self)
  831. if dialog.exec_():
  832. btype = dialog.fRetPlugin['build']
  833. ptype = dialog.fRetPlugin['type']
  834. filename = dialog.fRetPlugin['binary']
  835. label = dialog.fRetPlugin['label']
  836. extraStuff = self.getExtraStuff(dialog.fRetPlugin)
  837. self.addPlugin(btype, ptype, filename, None, label, extraStuff)
  838. @pyqtSlot()
  839. def slot_pluginRemoveAll(self):
  840. self.removeAllPlugins()
  841. self.connect(self.ui.ch_transport, SIGNAL("currentIndexChanged(int)"), SLOT("(int)"))
  842. self.connect(self.ui.b_transport_play, SIGNAL("clicked(bool)"), SLOT("(bool)"))
  843. self.connect(self.ui.b_transport_stop, SIGNAL("clicked()"), SLOT("()"))
  844. @pyqtSlot(int)
  845. def slot_transportModeChanged(self, newMode):
  846. Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, newMode, "")
  847. @pyqtSlot(bool)
  848. def slot_transportPlayPause(self, toggled):
  849. if toggled:
  850. Carla.host.transport_play()
  851. else:
  852. Carla.host.transport_pause()
  853. @pyqtSlot()
  854. def slot_transportStop(self):
  855. Carla.host.transport_pause()
  856. Carla.host.transport_relocate(0)
  857. @pyqtSlot()
  858. def slot_aboutCarla(self):
  859. CarlaAboutW(self).exec_()
  860. @pyqtSlot()
  861. def slot_configureCarla(self):
  862. dialog = CarlaSettingsW(self)
  863. if dialog.exec_():
  864. self.loadSettings(False)
  865. for pwidget in self.fPluginList:
  866. if pwidget is None:
  867. return
  868. pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  869. @pyqtSlot()
  870. def slot_handleSIGUSR1(self):
  871. print("Got SIGUSR1 -> Saving project now")
  872. QTimer.singleShot(0, self, SLOT("slot_fileSave()"))
  873. @pyqtSlot()
  874. def slot_handleSIGTERM(self):
  875. print("Got SIGTERM -> Closing now")
  876. self.close()
  877. @pyqtSlot(int, int, int, float, str)
  878. def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
  879. print("DEBUG :: %i, %i, %i, %f, \"%s\")" % (pluginId, value1, value2, value3, valueStr))
  880. @pyqtSlot(int)
  881. def slot_handlePluginAddedCallback(self, pluginId):
  882. pwidget = PluginWidget(self, pluginId)
  883. pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  884. self.ui.w_plugins.layout().addWidget(pwidget)
  885. self.fPluginCount += 1
  886. self.fPluginList[pluginId] = pwidget
  887. if not self.fProjectLoading:
  888. pwidget.setActive(True, True, True)
  889. if self.fPluginCount == 1:
  890. self.ui.act_plugin_remove_all.setEnabled(True)
  891. if self.fLastLoadedPluginId == -2:
  892. self.fLastLoadedPluginId = pluginId
  893. @pyqtSlot(int)
  894. def slot_handlePluginRemovedCallback(self, pluginId):
  895. if pluginId >= self.fPluginCount:
  896. return
  897. pwidget = self.fPluginList[pluginId]
  898. if pwidget is None:
  899. return
  900. self.fPluginList[pluginId] = None
  901. self.fPluginCount -= 1
  902. self.ui.w_plugins.layout().removeWidget(pwidget)
  903. pwidget.ui.edit_dialog.close()
  904. pwidget.close()
  905. pwidget.deleteLater()
  906. del pwidget
  907. # push all plugins 1 slot back
  908. for i in range(pluginId, self.fPluginCount):
  909. self.fPluginList[i] = self.fPluginList[i+1]
  910. self.fPluginList[i].setId(i)
  911. if self.fPluginCount == 0:
  912. self.ui.act_plugin_remove_all.setEnabled(False)
  913. @pyqtSlot(int, str)
  914. def slot_handlePluginRenamedCallback(self, pluginId, newName):
  915. if pluginId >= self.fPluginCount:
  916. return
  917. pwidget = self.fPluginList[pluginId]
  918. if pwidget is None:
  919. return
  920. pwidget.ui.label_name.setText(newName)
  921. @pyqtSlot(int, int, float)
  922. def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value):
  923. if pluginId >= self.fPluginCount:
  924. return
  925. pwidget = self.fPluginList[pluginId]
  926. if pwidget is None:
  927. return
  928. pwidget.setParameterValue(parameterId, value)
  929. @pyqtSlot(int, int, float)
  930. def slot_handleParameterDefaultChangedCallback(self, pluginId, parameterId, value):
  931. if pluginId >= self.fPluginCount:
  932. return
  933. pwidget = self.fPluginList[pluginId]
  934. if pwidget is None:
  935. return
  936. pwidget.setParameterDefault(parameterId, value)
  937. @pyqtSlot(int, int, int)
  938. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, parameterId, channel):
  939. if pluginId >= self.fPluginCount:
  940. return
  941. pwidget = self.fPluginList[pluginId]
  942. if pwidget is None:
  943. return
  944. pwidget.setParameterMidiChannel(parameterId, channel)
  945. @pyqtSlot(int, int, int)
  946. def slot_handleParameterMidiCcChangedCallback(self, pluginId, parameterId, cc):
  947. if pluginId >= self.fPluginCount:
  948. return
  949. pwidget = self.fPluginList[pluginId]
  950. if pwidget is None:
  951. return
  952. pwidget.setParameterMidiControl(parameterId, cc)
  953. @pyqtSlot(int, int)
  954. def slot_handleProgramChangedCallback(self, pluginId, programId):
  955. if pluginId >= self.fPluginCount:
  956. return
  957. pwidget = self.fPluginList[pluginId]
  958. if pwidget is None:
  959. return
  960. pwidget.setProgram(programId)
  961. @pyqtSlot(int, int)
  962. def slot_handleMidiProgramChangedCallback(self, pluginId, midiProgramId):
  963. if pluginId >= self.fPluginCount:
  964. return
  965. pwidget = self.fPluginList[pluginId]
  966. if pwidget is None:
  967. return
  968. pwidget.setMidiProgram(midiProgramId)
  969. @pyqtSlot(int, int, int, int)
  970. def slot_handleNoteOnCallback(self, pluginId, channel, note, velo):
  971. if pluginId >= self.fPluginCount:
  972. return
  973. pwidget = self.fPluginList[pluginId]
  974. if pwidget is None:
  975. return
  976. pwidget.sendNoteOn(channel, note)
  977. @pyqtSlot(int, int, int)
  978. def slot_handleNoteOffCallback(self, pluginId, channel, note):
  979. if pluginId >= self.fPluginCount:
  980. return
  981. pwidget = self.fPluginList[pluginId]
  982. if pwidget is None:
  983. return
  984. pwidget.sendNoteOff(channel, note)
  985. @pyqtSlot(int, int)
  986. def slot_handleShowGuiCallback(self, pluginId, show):
  987. if pluginId >= self.fPluginCount:
  988. return
  989. pwidget = self.fPluginList[pluginId]
  990. if pwidget is None:
  991. return
  992. if show == 0:
  993. pwidget.ui.b_gui.setChecked(False)
  994. pwidget.ui.b_gui.setEnabled(True)
  995. elif show == 1:
  996. pwidget.ui.b_gui.setChecked(True)
  997. pwidget.ui.b_gui.setEnabled(True)
  998. elif show == -1:
  999. pwidget.ui.b_gui.setChecked(False)
  1000. pwidget.ui.b_gui.setEnabled(False)
  1001. @pyqtSlot(int)
  1002. def slot_handleUpdateCallback(self, pluginId):
  1003. if pluginId >= self.fPluginCount:
  1004. return
  1005. pwidget = self.fPluginList[pluginId]
  1006. if pwidget is None:
  1007. return
  1008. pwidget.ui.edit_dialog.updateInfo()
  1009. @pyqtSlot(int)
  1010. def slot_handleReloadInfoCallback(self, pluginId):
  1011. if pluginId >= self.fPluginCount:
  1012. return
  1013. pwidget = self.fPluginList[pluginId]
  1014. if pwidget is None:
  1015. return
  1016. pwidget.ui.edit_dialog.reloadInfo()
  1017. @pyqtSlot(int)
  1018. def slot_handleReloadParametersCallback(self, pluginId):
  1019. if pluginId >= self.fPluginCount:
  1020. return
  1021. pwidget = self.fPluginList[pluginId]
  1022. if pwidget is None:
  1023. return
  1024. pwidget.ui.edit_dialog.reloadParameters()
  1025. @pyqtSlot(int)
  1026. def slot_handleReloadProgramsCallback(self, pluginId):
  1027. if pluginId >= self.fPluginCount:
  1028. return
  1029. pwidget = self.fPluginList[pluginId]
  1030. if pwidget is None:
  1031. return
  1032. pwidget.ui.edit_dialog.reloadPrograms()
  1033. @pyqtSlot(int)
  1034. def slot_handleReloadAllCallback(self, pluginId):
  1035. if pluginId >= self.fPluginCount:
  1036. return
  1037. pwidget = self.fPluginList[pluginId]
  1038. if pwidget is None:
  1039. return
  1040. pwidget.ui.edit_dialog.reloadAll()
  1041. @pyqtSlot(int, str)
  1042. def slot_handlePatchbayClientAddedCallback(self, clientId, clientName):
  1043. patchcanvas.addGroup(clientId, clientName)
  1044. @pyqtSlot(int)
  1045. def slot_handlePatchbayClientRemovedCallback(self, clientId):
  1046. patchcanvas.removeGroup(clientId)
  1047. @pyqtSlot(int, str)
  1048. def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName):
  1049. patchcanvas.renameGroup(clientId, newClientName)
  1050. @pyqtSlot(int, int, int, str)
  1051. def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags, portName):
  1052. if (portFlags & PATCHBAY_PORT_IS_INPUT):
  1053. portMode = patchcanvas.PORT_MODE_INPUT
  1054. elif (portFlags & PATCHBAY_PORT_IS_OUTPUT):
  1055. portMode = patchcanvas.PORT_MODE_OUTPUT
  1056. else:
  1057. portMode = patchcanvas.PORT_MODE_NULL
  1058. if (portFlags & PATCHBAY_PORT_IS_AUDIO):
  1059. portType = patchcanvas.PORT_TYPE_AUDIO_JACK
  1060. elif (portFlags & PATCHBAY_PORT_IS_MIDI):
  1061. portType = patchcanvas.PORT_TYPE_MIDI_JACK
  1062. else:
  1063. portType = patchcanvas.PORT_TYPE_NULL
  1064. patchcanvas.addPort(clientId, portId, portName, portMode, portType)
  1065. @pyqtSlot(int)
  1066. def slot_handlePatchbayPortRemovedCallback(self, portId):
  1067. patchcanvas.removePort(portId)
  1068. @pyqtSlot(int, str)
  1069. def slot_handlePatchbayPortRenamedCallback(self, portId, newPortName):
  1070. patchcanvas.renamePort(portId, newPortName)
  1071. @pyqtSlot(int, int, int)
  1072. def slot_handlePatchbayConnectionAddedCallback(self, connectionId, portOutId, portInId):
  1073. patchcanvas.connectPorts(connectionId, portOutId, portInId)
  1074. @pyqtSlot(int)
  1075. def slot_handlePatchbayConnectionRemovedCallback(self, connectionId):
  1076. patchcanvas.disconnectPorts(connectionId)
  1077. @pyqtSlot(str)
  1078. def slot_handleErrorCallback(self, error):
  1079. QMessageBox.critical(self, self.tr("Error"), error)
  1080. @pyqtSlot()
  1081. def slot_handleQuitCallback(self):
  1082. CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  1083. self.tr("Engine has been stopped or crashed.\nPlease restart Carla"),
  1084. self.tr("You may want to save your session now..."), QMessageBox.Ok, QMessageBox.Ok)
  1085. def getExtraStuff(self, plugin):
  1086. ptype = plugin['type']
  1087. if ptype == PLUGIN_LADSPA:
  1088. uniqueId = plugin['uniqueId']
  1089. for rdfItem in self.fLadspaRdfList:
  1090. if rdfItem.UniqueID == uniqueId:
  1091. return pointer(rdfItem)
  1092. elif ptype == PLUGIN_DSSI:
  1093. if (plugin['hints'] & PLUGIN_HAS_GUI):
  1094. gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label'])
  1095. if gui:
  1096. return gui.encode("utf-8")
  1097. elif ptype == PLUGIN_SF2:
  1098. if plugin['name'].endswith(" (16 outputs)"):
  1099. # return a dummy non-null pointer
  1100. INTPOINTER = POINTER(c_int)
  1101. ptr = c_int(0x1)
  1102. addr = addressof(ptr)
  1103. return cast(addr, INTPOINTER)
  1104. return c_nullptr
  1105. def loadRDFs(self):
  1106. # Save RDF info for later
  1107. self.fLadspaRdfList = []
  1108. if not haveLRDF:
  1109. return
  1110. settingsDir = os.path.join(HOME, ".config", "falkTX")
  1111. frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db")
  1112. if os.path.exists(frLadspaFile):
  1113. frLadspa = open(frLadspaFile, 'r')
  1114. try:
  1115. self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa))
  1116. except:
  1117. pass
  1118. frLadspa.close()
  1119. def saveSettings(self):
  1120. settings = QSettings()
  1121. settings.setValue("Geometry", self.saveGeometry())
  1122. settings.setValue("SplitterState", self.ui.splitter.saveState())
  1123. settings.setValue("ShowToolbar", self.ui.toolBar.isVisible())
  1124. #settings.setValue("ShowTransport", self.ui.frame_transport.isVisible())
  1125. settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value())
  1126. settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value())
  1127. def loadSettings(self, geometry):
  1128. settings = QSettings()
  1129. if geometry:
  1130. self.restoreGeometry(settings.value("Geometry", ""))
  1131. showToolbar = settings.value("ShowToolbar", True, type=bool)
  1132. self.ui.act_settings_show_toolbar.setChecked(showToolbar)
  1133. self.ui.toolBar.setVisible(showToolbar)
  1134. #showTransport = settings.value("ShowTransport", True, type=bool)
  1135. #self.ui.act_settings_show_transport.setChecked(showTransport)
  1136. #self.ui.frame_transport.setVisible(showTransport)
  1137. self.ui.frame_transport.setVisible(False)
  1138. if settings.contains("SplitterState"):
  1139. self.ui.splitter.restoreState(settings.value("SplitterState", ""))
  1140. else:
  1141. self.ui.splitter.setSizes([99999, 210])
  1142. self.fSavedSettings = {
  1143. "Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", HOME, type=str),
  1144. "Main/RefreshInterval": settings.value("Main/RefreshInterval", 50, type=int),
  1145. "Canvas/Theme": settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str),
  1146. "Canvas/AutoHideGroups": settings.value("Canvas/AutoHideGroups", False, type=bool),
  1147. "Canvas/UseBezierLines": settings.value("Canvas/UseBezierLines", True, type=bool),
  1148. "Canvas/EyeCandy": settings.value("Canvas/EyeCandy", patchcanvas.EYECANDY_SMALL, type=int),
  1149. "Canvas/UseOpenGL": settings.value("Canvas/UseOpenGL", False, type=bool),
  1150. "Canvas/Antialiasing": settings.value("Canvas/Antialiasing", patchcanvas.ANTIALIASING_SMALL, type=int),
  1151. "Canvas/HighQualityAntialiasing": settings.value("Canvas/HighQualityAntialiasing", False, type=bool)
  1152. }
  1153. # ---------------------------------------------
  1154. # plugin checks
  1155. if settings.value("Engine/DisableChecks", False, type=bool):
  1156. os.environ["CARLA_DISCOVERY_NO_PROCESSING_CHECKS"] = "true"
  1157. elif os.getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"):
  1158. os.environ.pop("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
  1159. # ---------------------------------------------
  1160. # plugin paths
  1161. Carla.LADSPA_PATH = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH))
  1162. Carla.DSSI_PATH = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH))
  1163. Carla.LV2_PATH = toList(settings.value("Paths/LV2", Carla.LV2_PATH))
  1164. Carla.VST_PATH = toList(settings.value("Paths/VST", Carla.VST_PATH))
  1165. Carla.GIG_PATH = toList(settings.value("Paths/GIG", Carla.GIG_PATH))
  1166. Carla.SF2_PATH = toList(settings.value("Paths/SF2", Carla.SF2_PATH))
  1167. Carla.SFZ_PATH = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH))
  1168. os.environ["LADSPA_PATH"] = splitter.join(Carla.LADSPA_PATH)
  1169. os.environ["DSSI_PATH"] = splitter.join(Carla.DSSI_PATH)
  1170. os.environ["LV2_PATH"] = splitter.join(Carla.LV2_PATH)
  1171. os.environ["VST_PATH"] = splitter.join(Carla.VST_PATH)
  1172. os.environ["GIG_PATH"] = splitter.join(Carla.GIG_PATH)
  1173. os.environ["SF2_PATH"] = splitter.join(Carla.SF2_PATH)
  1174. os.environ["SFZ_PATH"] = splitter.join(Carla.SFZ_PATH)
  1175. def resizeEvent(self, event):
  1176. if self.ui.tabMain.currentIndex() == 0:
  1177. # Force update of 2nd tab
  1178. width = self.ui.tab_plugins.width()-4
  1179. height = self.ui.tab_plugins.height()-4
  1180. self.ui.miniCanvasPreview.setViewSize(float(width) / DEFAULT_CANVAS_WIDTH, float(height) / DEFAULT_CANVAS_HEIGHT)
  1181. else:
  1182. QTimer.singleShot(0, self, SLOT("slot_miniCanvasCheckSize()"))
  1183. QMainWindow.resizeEvent(self, event)
  1184. def timerEvent(self, event):
  1185. if event.timerId() == self.fIdleTimerFast:
  1186. Carla.host.engine_idle()
  1187. for pwidget in self.fPluginList:
  1188. if pwidget is None:
  1189. break
  1190. pwidget.idleFast()
  1191. elif event.timerId() == self.fIdleTimerSlow:
  1192. for pwidget in self.fPluginList:
  1193. if pwidget is None:
  1194. break
  1195. pwidget.idleSlow()
  1196. QMainWindow.timerEvent(self, event)
  1197. def closeEvent(self, event):
  1198. #if self.nsm_server:
  1199. #self.nsm_server.stop()
  1200. self.saveSettings()
  1201. if Carla.host.is_engine_running():
  1202. Carla.host.set_engine_about_to_close()
  1203. self.removeAllPlugins()
  1204. self.stopEngine()
  1205. QMainWindow.closeEvent(self, event)
  1206. # ------------------------------------------------------------------------------------------------
  1207. def canvasCallback(action, value1, value2, valueStr):
  1208. if action == patchcanvas.ACTION_GROUP_INFO:
  1209. pass
  1210. elif action == patchcanvas.ACTION_GROUP_RENAME:
  1211. pass
  1212. elif action == patchcanvas.ACTION_GROUP_SPLIT:
  1213. groupId = value1
  1214. patchcanvas.splitGroup(groupId)
  1215. elif action == patchcanvas.ACTION_GROUP_JOIN:
  1216. groupId = value1
  1217. patchcanvas.joinGroup(groupId)
  1218. elif action == patchcanvas.ACTION_PORT_INFO:
  1219. pass
  1220. elif action == patchcanvas.ACTION_PORT_RENAME:
  1221. pass
  1222. elif action == patchcanvas.ACTION_PORTS_CONNECT:
  1223. portIdA = value1
  1224. portIdB = value2
  1225. Carla.host.patchbay_connect(portIdA, portIdB)
  1226. elif action == patchcanvas.ACTION_PORTS_DISCONNECT:
  1227. connectionId = value1
  1228. Carla.host.patchbay_disconnect(connectionId)
  1229. def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr):
  1230. if pluginId < 0 or not Carla.gui:
  1231. return
  1232. if action == CALLBACK_DEBUG:
  1233. Carla.gui.emit(SIGNAL("DebugCallback(int, int, int, double, QString)"), pluginId, value1, value2, value3, cString(valueStr))
  1234. elif action == CALLBACK_PLUGIN_ADDED:
  1235. Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId)
  1236. elif action == CALLBACK_PLUGIN_REMOVED:
  1237. Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId)
  1238. elif action == CALLBACK_PLUGIN_RENAMED:
  1239. Carla.gui.emit(SIGNAL("PluginRenamedCallback(int, QString)"), pluginId, valueStr)
  1240. elif action == CALLBACK_PARAMETER_VALUE_CHANGED:
  1241. Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3)
  1242. elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED:
  1243. Carla.gui.emit(SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), pluginId, value1, value3)
  1244. elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  1245. Carla.gui.emit(SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), pluginId, value1, value2)
  1246. elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  1247. Carla.gui.emit(SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), pluginId, value1, value2)
  1248. elif action == CALLBACK_PROGRAM_CHANGED:
  1249. Carla.gui.emit(SIGNAL("ProgramChangedCallback(int, int)"), pluginId, value1)
  1250. elif action == CALLBACK_MIDI_PROGRAM_CHANGED:
  1251. Carla.gui.emit(SIGNAL("MidiProgramChangedCallback(int, int)"), pluginId, value1)
  1252. elif action == CALLBACK_NOTE_ON:
  1253. Carla.gui.emit(SIGNAL("NoteOnCallback(int, int, int, int)"), pluginId, value1, value2, value3)
  1254. elif action == CALLBACK_NOTE_OFF:
  1255. Carla.gui.emit(SIGNAL("NoteOffCallback(int, int, int)"), pluginId, value1, value2)
  1256. elif action == CALLBACK_SHOW_GUI:
  1257. Carla.gui.emit(SIGNAL("ShowGuiCallback(int, int)"), pluginId, value1)
  1258. elif action == CALLBACK_UPDATE:
  1259. Carla.gui.emit(SIGNAL("UpdateCallback(int)"), pluginId)
  1260. elif action == CALLBACK_RELOAD_INFO:
  1261. Carla.gui.emit(SIGNAL("ReloadInfoCallback(int)"), pluginId)
  1262. elif action == CALLBACK_RELOAD_PARAMETERS:
  1263. Carla.gui.emit(SIGNAL("ReloadParametersCallback(int)"), pluginId)
  1264. elif action == CALLBACK_RELOAD_PROGRAMS:
  1265. Carla.gui.emit(SIGNAL("ReloadProgramsCallback(int)"), pluginId)
  1266. elif action == CALLBACK_RELOAD_ALL:
  1267. Carla.gui.emit(SIGNAL("ReloadAllCallback(int)"), pluginId)
  1268. elif action == CALLBACK_PATCHBAY_CLIENT_ADDED:
  1269. Carla.gui.emit(SIGNAL("PatchbayClientAddedCallback(int, QString)"), value1, cString(valueStr))
  1270. elif action == CALLBACK_PATCHBAY_CLIENT_REMOVED:
  1271. Carla.gui.emit(SIGNAL("PatchbayClientRemovedCallback(int)"), value1)
  1272. elif action == CALLBACK_PATCHBAY_CLIENT_RENAMED:
  1273. Carla.gui.emit(SIGNAL("PatchbayClientRenamedCallback(int, QString)"), value1, cString(valueStr))
  1274. elif action == CALLBACK_PATCHBAY_PORT_ADDED:
  1275. Carla.gui.emit(SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), value1, value2, value3, cString(valueStr))
  1276. elif action == CALLBACK_PATCHBAY_PORT_REMOVED:
  1277. Carla.gui.emit(SIGNAL("PatchbayPortRemovedCallback(int)"), value1)
  1278. elif action == CALLBACK_PATCHBAY_PORT_RENAMED:
  1279. Carla.gui.emit(SIGNAL("PatchbayPortRenamedCallback(int, QString)"), value1, cString(valueStr))
  1280. elif action == CALLBACK_PATCHBAY_CONNECTION_ADDED:
  1281. Carla.gui.emit(SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), value1, value2, value3)
  1282. elif action == CALLBACK_PATCHBAY_CONNECTION_REMOVED:
  1283. Carla.gui.emit(SIGNAL("PatchbayConnectionRemovedCallback(int)"), value1)
  1284. #elif action == CALLBACK_NSM_ANNOUNCE:
  1285. #Carla.gui._nsmAnnounce2str = cString(Carla.host.get_last_error())
  1286. #Carla.gui.emit(SIGNAL("NSM_AnnounceCallback()"))
  1287. #elif action == CALLBACK_NSM_OPEN1:
  1288. #Carla.gui._nsmOpen1str = cString(valueStr)
  1289. #Carla.gui.emit(SIGNAL("NSM_Open1Callback()"))
  1290. #elif action == CALLBACK_NSM_OPEN2:
  1291. #Carla.gui._nsmOpen2str = cString(valueStr)
  1292. #Carla.gui.emit(SIGNAL("NSM_Open2Callback()"))
  1293. #elif action == CALLBACK_NSM_SAVE:
  1294. #Carla.gui.emit(SIGNAL("NSM_SaveCallback()"))
  1295. elif action == CALLBACK_ERROR:
  1296. Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), cString(valueStr))
  1297. elif action == CALLBACK_QUIT:
  1298. Carla.gui.emit(SIGNAL("QuitCallback()"))
  1299. #--------------- main ------------------
  1300. if __name__ == '__main__':
  1301. # App initialization
  1302. app = QApplication(sys.argv)
  1303. app.setApplicationName("Carla")
  1304. app.setApplicationVersion(VERSION)
  1305. app.setOrganizationName("falkTX")
  1306. app.setWindowIcon(QIcon(":/scalable/carla.svg"))
  1307. libPrefix = None
  1308. projectFilename = None
  1309. for i in range(len(app.arguments())):
  1310. if i == 0: continue
  1311. argument = app.arguments()[i]
  1312. if argument.startswith("--with-libprefix="):
  1313. libPrefix = argument.replace("--with-libprefix=", "")
  1314. elif os.path.exists(argument):
  1315. projectFilename = argument
  1316. # Init backend
  1317. Carla.host = Host(libPrefix)
  1318. Carla.host.set_engine_callback(engineCallback)
  1319. Carla.host.set_engine_option(OPTION_PROCESS_NAME, 0, "carla")
  1320. # Set bridge paths
  1321. if carla_bridge_native:
  1322. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_NATIVE, 0, carla_bridge_native)
  1323. if carla_bridge_posix32:
  1324. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX32, 0, carla_bridge_posix32)
  1325. if carla_bridge_posix64:
  1326. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX64, 0, carla_bridge_posix64)
  1327. if carla_bridge_win32:
  1328. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32)
  1329. if carla_bridge_win64:
  1330. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64)
  1331. if WINDOWS:
  1332. if carla_bridge_lv2_windows:
  1333. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, carla_bridge_lv2_windows)
  1334. if carla_bridge_vst_hwnd:
  1335. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_HWND, 0, carla_bridge_vst_hwnd)
  1336. elif MACOS:
  1337. if carla_bridge_lv2_cocoa:
  1338. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_COCOA, 0, carla_bridge_lv2_cocoa)
  1339. if carla_bridge_vst_cocoa:
  1340. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_COCOA, 0, carla_bridge_vst_cocoa)
  1341. else:
  1342. if carla_bridge_lv2_gtk2:
  1343. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2)
  1344. if carla_bridge_lv2_gtk3:
  1345. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK3, 0, carla_bridge_lv2_gtk3)
  1346. if carla_bridge_lv2_qt4:
  1347. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4)
  1348. if carla_bridge_lv2_qt5:
  1349. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT5, 0, carla_bridge_lv2_qt5)
  1350. if carla_bridge_lv2_x11:
  1351. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11)
  1352. if carla_bridge_vst_x11:
  1353. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11)
  1354. # Create GUI and start engine
  1355. Carla.gui = CarlaMainW()
  1356. # Set-up custom signal handling
  1357. setUpSignals()
  1358. # Show GUI
  1359. Carla.gui.show()
  1360. # Load project file if set
  1361. if projectFilename:
  1362. Carla.gui.loadProjectLater(projectFilename)
  1363. # App-Loop
  1364. ret = app.exec_()
  1365. # Exit properly
  1366. sys.exit(ret)