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.

carla.py 55KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  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 PyQt4.QtCore import Qt, QSize
  20. from PyQt4.QtGui import QApplication, QDialogButtonBox, QMainWindow
  21. # ------------------------------------------------------------------------------------------------------------
  22. # Imports (Custom Stuff)
  23. import ui_carla
  24. import ui_carla_settings
  25. from carla_backend import * # FIXME, remove later
  26. #from carla_shared import *
  27. # ------------------------------------------------------------------------------------------------------------
  28. # Global variables
  29. # Tab indexes
  30. TAB_INDEX_MAIN = 0
  31. TAB_INDEX_CANVAS = 1
  32. TAB_INDEX_CARLA_ENGINE = 2
  33. TAB_INDEX_CARLA_PATHS = 3
  34. TAB_INDEX_NONE = 4
  35. # Single and Multiple client mode is only for JACK,
  36. # but we still want to match QComboBox index to defines,
  37. # so add +2 pos padding if driverName != "JACK".
  38. PROCESS_MODE_NON_JACK_PADDING = 2
  39. # Carla defaults
  40. CARLA_DEFAULT_PROCESS_HIGH_PRECISION = False
  41. CARLA_DEFAULT_MAX_PARAMETERS = 200
  42. CARLA_DEFAULT_FORCE_STEREO = False
  43. CARLA_DEFAULT_USE_DSSI_VST_CHUNKS = False
  44. CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False
  45. CARLA_DEFAULT_PREFER_UI_BRIDGES = True
  46. CARLA_DEFAULT_OSC_UI_TIMEOUT = 4000
  47. CARLA_DEFAULT_DISABLE_CHECKS = False
  48. # PatchCanvas defines
  49. CANVAS_ANTIALIASING_SMALL = 1
  50. CANVAS_EYECANDY_SMALL = 1
  51. # ------------------------------------------------------------------------------------------------------------
  52. # Settings Dialog
  53. class CarlaSettingsW(QDialog):
  54. def __init__(self, parent):
  55. QDialog.__init__(self, parent)
  56. self.ui = ui_carla_settings.Ui_CarlaSettingsW()
  57. self.ui.setupUi(self)
  58. # TODO
  59. self.ui.lw_page.hideRow(TAB_INDEX_CANVAS)
  60. # -------------------------------------------------------------
  61. # Load settings
  62. self.loadSettings()
  63. # -------------------------------------------------------------
  64. # Set-up GUI
  65. driverCount = Carla.host.get_engine_driver_count()
  66. for i in range(driverCount):
  67. driverName = cString(Carla.host.get_engine_driver_name(i))
  68. self.ui.cb_engine_audio_driver.addItem(driverName)
  69. #if not hasOpenGL:
  70. #self.cb_canvas_use_opengl.setChecked(False)
  71. #self.cb_canvas_use_opengl.setEnabled(False)
  72. # -------------------------------------------------------------
  73. # Set-up connections
  74. self.connect(self, SIGNAL("accepted()"), SLOT("slot_saveSettings()"))
  75. self.connect(self.ui.buttonBox.button(QDialogButtonBox.Reset), SIGNAL("clicked()"), SLOT("slot_resetSettings()"))
  76. self.connect(self.ui.b_main_def_folder_open, SIGNAL("clicked()"), SLOT("slot_getAndSetProjectPath()"))
  77. self.connect(self.ui.cb_engine_audio_driver, SIGNAL("currentIndexChanged(int)"), SLOT("slot_engineAudioDriverChanged()"))
  78. self.connect(self.ui.b_paths_add, SIGNAL("clicked()"), SLOT("slot_addPluginPath()"))
  79. self.connect(self.ui.b_paths_remove, SIGNAL("clicked()"), SLOT("slot_removePluginPath()"))
  80. self.connect(self.ui.b_paths_change, SIGNAL("clicked()"), SLOT("slot_changePluginPath()"))
  81. self.connect(self.ui.tw_paths, SIGNAL("currentChanged(int)"), SLOT("slot_pluginPathTabChanged(int)"))
  82. self.connect(self.ui.lw_ladspa, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  83. self.connect(self.ui.lw_dssi, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  84. self.connect(self.ui.lw_lv2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  85. self.connect(self.ui.lw_vst, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  86. self.connect(self.ui.lw_sf2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  87. # -------------------------------------------------------------
  88. # Post-connect setup
  89. self.ui.lw_ladspa.setCurrentRow(0)
  90. self.ui.lw_dssi.setCurrentRow(0)
  91. self.ui.lw_lv2.setCurrentRow(0)
  92. self.ui.lw_vst.setCurrentRow(0)
  93. self.ui.lw_gig.setCurrentRow(0)
  94. self.ui.lw_sf2.setCurrentRow(0)
  95. self.ui.lw_sfz.setCurrentRow(0)
  96. #QTimer.singleShot(0, self, )
  97. #self.slot_pluginPathTabChanged(self.tw_paths.currentIndex())
  98. self.ui.lw_page.setCurrentCell(0, 0)
  99. def loadSettings(self):
  100. settings = QSettings()
  101. # ---------------------------------------
  102. self.ui.le_main_def_folder.setText(settings.value("Main/DefaultProjectFolder", HOME, type=str))
  103. self.ui.sb_gui_refresh.setValue(settings.value("Main/RefreshInterval", 50, type=int))
  104. # ---------------------------------------
  105. self.ui.cb_canvas_hide_groups.setChecked(settings.value("Canvas/AutoHideGroups", False, type=bool))
  106. self.ui.cb_canvas_bezier_lines.setChecked(settings.value("Canvas/UseBezierLines", True, type=bool))
  107. self.ui.cb_canvas_eyecandy.setCheckState(settings.value("Canvas/EyeCandy", CANVAS_EYECANDY_SMALL, type=int))
  108. self.ui.cb_canvas_use_opengl.setChecked(settings.value("Canvas/UseOpenGL", False, type=bool))
  109. self.ui.cb_canvas_render_aa.setCheckState(settings.value("Canvas/Antialiasing", CANVAS_ANTIALIASING_SMALL, type=int))
  110. self.ui.cb_canvas_render_hq_aa.setChecked(settings.value("Canvas/HighQualityAntialiasing", False, type=bool))
  111. #themeName = settings.value("Canvas/Theme", getDefaultThemeName(), type=str)
  112. #for i in range(Theme.THEME_MAX):
  113. #thisThemeName = getThemeName(i)
  114. #self.ui.cb_canvas_theme.addItem(thisThemeName)
  115. #if thisThemeName == themeName:
  116. #self.ui.cb_canvas_theme.setCurrentIndex(i)
  117. # --------------------------------------------
  118. audioDriver = settings.value("Engine/AudioDriver", "JACK", type=str)
  119. for i in range(self.ui.cb_engine_audio_driver.count()):
  120. if self.ui.cb_engine_audio_driver.itemText(i) == audioDriver:
  121. self.ui.cb_engine_audio_driver.setCurrentIndex(i)
  122. break
  123. else:
  124. self.ui.cb_engine_audio_driver.setCurrentIndex(-1)
  125. if audioDriver == "JACK":
  126. processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int)
  127. self.ui.cb_engine_process_mode_jack.setCurrentIndex(processModeIndex)
  128. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  129. else:
  130. processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_CONTINUOUS_RACK, type=int)
  131. processModeIndex -= PROCESS_MODE_NON_JACK_PADDING
  132. self.ui.cb_engine_process_mode_other.setCurrentIndex(processModeIndex)
  133. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  134. self.ui.sb_engine_max_params.setValue(settings.value("Engine/MaxParameters", CARLA_DEFAULT_MAX_PARAMETERS, type=int))
  135. self.ui.ch_engine_prefer_ui_bridges.setChecked(settings.value("Engine/PreferUiBridges", CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool))
  136. self.ui.sb_engine_oscgui_timeout.setValue(settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_OSC_UI_TIMEOUT, type=int))
  137. self.ui.ch_engine_disable_checks.setChecked(settings.value("Engine/DisableChecks", CARLA_DEFAULT_DISABLE_CHECKS, type=bool))
  138. self.ui.ch_engine_dssi_chunks.setChecked(settings.value("Engine/UseDssiVstChunks", CARLA_DEFAULT_USE_DSSI_VST_CHUNKS, type=bool))
  139. self.ui.ch_engine_prefer_plugin_bridges.setChecked(settings.value("Engine/PreferPluginBridges", CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool))
  140. self.ui.ch_engine_force_stereo.setChecked(settings.value("Engine/ForceStereo", CARLA_DEFAULT_FORCE_STEREO, type=bool))
  141. # --------------------------------------------
  142. ladspas = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH))
  143. dssis = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH))
  144. lv2s = toList(settings.value("Paths/LV2", Carla.LV2_PATH))
  145. vsts = toList(settings.value("Paths/VST", Carla.VST_PATH))
  146. gigs = toList(settings.value("Paths/GIG", Carla.GIG_PATH))
  147. sf2s = toList(settings.value("Paths/SF2", Carla.SF2_PATH))
  148. sfzs = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH))
  149. ladspas.sort()
  150. dssis.sort()
  151. lv2s.sort()
  152. vsts.sort()
  153. gigs.sort()
  154. sf2s.sort()
  155. sfzs.sort()
  156. for ladspa in ladspas:
  157. self.ui.lw_ladspa.addItem(ladspa)
  158. for dssi in dssis:
  159. self.ui.lw_dssi.addItem(dssi)
  160. for lv2 in lv2s:
  161. self.ui.lw_lv2.addItem(lv2)
  162. for vst in vsts:
  163. self.ui.lw_vst.addItem(vst)
  164. for gig in gigs:
  165. self.ui.lw_gig.addItem(gig)
  166. for sf2 in sf2s:
  167. self.ui.lw_sf2.addItem(sf2)
  168. for sfz in sfzs:
  169. self.ui.lw_sfz.addItem(sfz)
  170. @pyqtSlot()
  171. def slot_saveSettings(self):
  172. settings = QSettings()
  173. # ---------------------------------------
  174. settings.setValue("Main/RefreshInterval", self.ui.sb_gui_refresh.value())
  175. settings.setValue("Main/DefaultProjectFolder", self.ui.le_main_def_folder.text())
  176. # ---------------------------------------
  177. #settings.setValue("Canvas/Theme", self.ui.cb_canvas_theme.currentText())
  178. #settings.setValue("Canvas/AutoHideGroups", self.ui.cb_canvas_hide_groups.isChecked())
  179. #settings.setValue("Canvas/UseBezierLines", self.ui.cb_canvas_bezier_lines.isChecked())
  180. #settings.setValue("Canvas/UseOpenGL", self.ui.cb_canvas_use_opengl.isChecked())
  181. #settings.setValue("Canvas/HighQualityAntialiasing", self.ui.cb_canvas_render_hq_aa.isChecked())
  182. ## 0, 1, 2 match their enum variants
  183. #settings.setValue("Canvas/EyeCandy", self.ui.cb_canvas_eyecandy.checkState())
  184. #settings.setValue("Canvas/Antialiasing", self.ui.cb_canvas_render_aa.checkState())
  185. # --------------------------------------------
  186. audioDriver = self.ui.cb_engine_audio_driver.currentText()
  187. settings.setValue("Engine/AudioDriver", audioDriver)
  188. if audioDriver == "JACK":
  189. settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_jack.currentIndex())
  190. else:
  191. settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_other.currentIndex()+PROCESS_MODE_NON_JACK_PADDING)
  192. settings.setValue("Engine/MaxParameters", self.ui.sb_engine_max_params.value())
  193. settings.setValue("Engine/PreferUiBridges", self.ui.ch_engine_prefer_ui_bridges.isChecked())
  194. settings.setValue("Engine/OscUiTimeout", self.ui.sb_engine_oscgui_timeout.value())
  195. settings.setValue("Engine/DisableChecks", self.ui.ch_engine_disable_checks.isChecked())
  196. settings.setValue("Engine/UseDssiVstChunks", self.ui.ch_engine_dssi_chunks.isChecked())
  197. settings.setValue("Engine/PreferPluginBridges", self.ui.ch_engine_prefer_plugin_bridges.isChecked())
  198. settings.setValue("Engine/ForceStereo", self.ui.ch_engine_force_stereo.isChecked())
  199. # --------------------------------------------
  200. # FIXME - find a cleaner way to do this, *.items() ?
  201. ladspas = []
  202. dssis = []
  203. lv2s = []
  204. vsts = []
  205. gigs = []
  206. sf2s = []
  207. sfzs = []
  208. for i in range(self.ui.lw_ladspa.count()):
  209. ladspas.append(self.ui.lw_ladspa.item(i).text())
  210. for i in range(self.ui.lw_dssi.count()):
  211. dssis.append(self.ui.lw_dssi.item(i).text())
  212. for i in range(self.ui.lw_lv2.count()):
  213. lv2s.append(self.ui.lw_lv2.item(i).text())
  214. for i in range(self.ui.lw_vst.count()):
  215. vsts.append(self.ui.lw_vst.item(i).text())
  216. for i in range(self.ui.lw_gig.count()):
  217. gigs.append(self.ui.lw_gig.item(i).text())
  218. for i in range(self.ui.lw_sf2.count()):
  219. sf2s.append(self.ui.lw_sf2.item(i).text())
  220. for i in range(self.ui.lw_sfz.count()):
  221. sfzs.append(self.ui.lw_sfz.item(i).text())
  222. settings.setValue("Paths/LADSPA", ladspas)
  223. settings.setValue("Paths/DSSI", dssis)
  224. settings.setValue("Paths/LV2", lv2s)
  225. settings.setValue("Paths/VST", vsts)
  226. settings.setValue("Paths/GIG", gigs)
  227. settings.setValue("Paths/SF2", sf2s)
  228. settings.setValue("Paths/SFZ", sfzs)
  229. @pyqtSlot()
  230. def slot_resetSettings(self):
  231. if self.ui.lw_page.currentRow() == TAB_INDEX_MAIN:
  232. self.ui.le_main_def_folder.setText(HOME)
  233. self.ui.sb_gui_refresh.setValue(50)
  234. elif self.ui.lw_page.currentRow() == TAB_INDEX_CANVAS:
  235. self.ui.cb_canvas_theme.setCurrentIndex(0)
  236. self.ui.cb_canvas_hide_groups.setChecked(False)
  237. self.ui.cb_canvas_bezier_lines.setChecked(True)
  238. self.ui.cb_canvas_eyecandy.setCheckState(Qt.PartiallyChecked)
  239. self.ui.cb_canvas_use_opengl.setChecked(False)
  240. self.ui.cb_canvas_render_aa.setCheckState(Qt.PartiallyChecked)
  241. self.ui.cb_canvas_render_hq_aa.setChecked(False)
  242. elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_ENGINE:
  243. self.ui.cb_engine_audio_driver.setCurrentIndex(0)
  244. self.ui.sb_engine_max_params.setValue(CARLA_DEFAULT_MAX_PARAMETERS)
  245. self.ui.ch_engine_prefer_ui_bridges.setChecked(CARLA_DEFAULT_PREFER_UI_BRIDGES)
  246. self.ui.sb_engine_oscgui_timeout.setValue(CARLA_DEFAULT_OSC_UI_TIMEOUT)
  247. self.ui.ch_engine_disable_checks.setChecked(CARLA_DEFAULT_DISABLE_CHECKS)
  248. self.ui.ch_engine_dssi_chunks.setChecked(CARLA_DEFAULT_USE_DSSI_VST_CHUNKS)
  249. self.ui.ch_engine_prefer_plugin_bridges.setChecked(CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES)
  250. self.ui.ch_engine_force_stereo.setChecked(CARLA_DEFAULT_FORCE_STEREO)
  251. if self.ui.cb_engine_audio_driver.currentText() == "JACK":
  252. self.ui.cb_engine_process_mode_jack.setCurrentIndex(PROCESS_MODE_MULTIPLE_CLIENTS)
  253. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  254. else:
  255. self.ui.cb_engine_process_mode_other.setCurrentIndex(PROCESS_MODE_CONTINUOUS_RACK-PROCESS_MODE_NON_JACK_PADDING)
  256. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  257. elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_PATHS:
  258. if self.ui.tw_paths.currentIndex() == 0:
  259. Carla.LADSPA_PATH.sort()
  260. self.ui.lw_ladspa.clear()
  261. for ladspa in Carla.LADSPA_PATH:
  262. self.ui.lw_ladspa.addItem(ladspa)
  263. elif self.ui.tw_paths.currentIndex() == 1:
  264. Carla.DSSI_PATH.sort()
  265. self.ui.lw_dssi.clear()
  266. for dssi in Carla.DSSI_PATH:
  267. self.ui.lw_dssi.addItem(dssi)
  268. elif self.ui.tw_paths.currentIndex() == 2:
  269. Carla.LV2_PATH.sort()
  270. self.ui.lw_lv2.clear()
  271. for lv2 in Carla.LV2_PATH:
  272. self.ui.lw_lv2.addItem(lv2)
  273. elif self.ui.tw_paths.currentIndex() == 3:
  274. Carla.VST_PATH.sort()
  275. self.ui.lw_vst.clear()
  276. for vst in Carla.VST_PATH:
  277. self.ui.lw_vst.addItem(vst)
  278. elif self.ui.tw_paths.currentIndex() == 4:
  279. Carla.GIG_PATH.sort()
  280. self.ui.lw_gig.clear()
  281. for gig in Carla.GIG_PATH:
  282. self.ui.lw_gig.addItem(gig)
  283. elif self.ui.tw_paths.currentIndex() == 5:
  284. Carla.SF2_PATH.sort()
  285. self.ui.lw_sf2.clear()
  286. for sf2 in Carla.SF2_PATH:
  287. self.ui.lw_sf2.addItem(sf2)
  288. elif self.ui.tw_paths.currentIndex() == 6:
  289. Carla.SFZ_PATH.sort()
  290. self.ui.lw_sfz.clear()
  291. for sfz in Carla.SFZ_PATH:
  292. self.ui.lw_sfz.addItem(sfz)
  293. @pyqtSlot()
  294. def slot_getAndSetProjectPath(self):
  295. pass #getAndSetPath(self, self.le_main_def_folder.text(), self.le_main_def_folder)
  296. @pyqtSlot()
  297. def slot_engineAudioDriverChanged(self):
  298. if self.ui.cb_engine_audio_driver.currentText() == "JACK":
  299. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  300. else:
  301. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  302. @pyqtSlot()
  303. def slot_addPluginPath(self):
  304. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), "", QFileDialog.ShowDirsOnly)
  305. if newPath:
  306. if self.ui.tw_paths.currentIndex() == 0:
  307. self.ui.lw_ladspa.addItem(newPath)
  308. elif self.ui.tw_paths.currentIndex() == 1:
  309. self.ui.lw_dssi.addItem(newPath)
  310. elif self.ui.tw_paths.currentIndex() == 2:
  311. self.ui.lw_lv2.addItem(newPath)
  312. elif self.ui.tw_paths.currentIndex() == 3:
  313. self.ui.lw_vst.addItem(newPath)
  314. elif self.ui.tw_paths.currentIndex() == 4:
  315. self.ui.lw_gig.addItem(newPath)
  316. elif self.ui.tw_paths.currentIndex() == 5:
  317. self.ui.lw_sf2.addItem(newPath)
  318. elif self.ui.tw_paths.currentIndex() == 6:
  319. self.ui.lw_sfz.addItem(newPath)
  320. @pyqtSlot()
  321. def slot_removePluginPath(self):
  322. if self.ui.tw_paths.currentIndex() == 0:
  323. self.ui.lw_ladspa.takeItem(self.ui.lw_ladspa.currentRow())
  324. elif self.ui.tw_paths.currentIndex() == 1:
  325. self.ui.lw_dssi.takeItem(self.ui.lw_dssi.currentRow())
  326. elif self.ui.tw_paths.currentIndex() == 2:
  327. self.ui.lw_lv2.takeItem(self.ui.lw_lv2.currentRow())
  328. elif self.ui.tw_paths.currentIndex() == 3:
  329. self.ui.lw_vst.takeItem(self.ui.lw_vst.currentRow())
  330. elif self.ui.tw_paths.currentIndex() == 4:
  331. self.ui.lw_gig.takeItem(self.ui.lw_gig.currentRow())
  332. elif self.ui.tw_paths.currentIndex() == 5:
  333. self.ui.lw_sf2.takeItem(self.ui.lw_sf2.currentRow())
  334. elif self.ui.tw_paths.currentIndex() == 6:
  335. self.ui.lw_sfz.takeItem(self.ui.lw_sfz.currentRow())
  336. @pyqtSlot()
  337. def slot_changePluginPath(self):
  338. if self.ui.tw_paths.currentIndex() == 0:
  339. currentPath = self.ui.lw_ladspa.currentItem().text()
  340. elif self.ui.tw_paths.currentIndex() == 1:
  341. currentPath = self.ui.lw_dssi.currentItem().text()
  342. elif self.ui.tw_paths.currentIndex() == 2:
  343. currentPath = self.ui.lw_lv2.currentItem().text()
  344. elif self.ui.tw_paths.currentIndex() == 3:
  345. currentPath = self.ui.lw_vst.currentItem().text()
  346. elif self.ui.tw_paths.currentIndex() == 4:
  347. currentPath = self.ui.lw_gig.currentItem().text()
  348. elif self.ui.tw_paths.currentIndex() == 5:
  349. currentPath = self.ui.lw_sf2.currentItem().text()
  350. elif self.ui.tw_paths.currentIndex() == 6:
  351. currentPath = self.ui.lw_sfz.currentItem().text()
  352. else:
  353. currentPath = ""
  354. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), currentPath, QFileDialog.ShowDirsOnly)
  355. if newPath:
  356. if self.ui.tw_paths.currentIndex() == 0:
  357. self.ui.lw_ladspa.currentItem().setText(newPath)
  358. elif self.ui.tw_paths.currentIndex() == 1:
  359. self.ui.lw_dssi.currentItem().setText(newPath)
  360. elif self.ui.tw_paths.currentIndex() == 2:
  361. self.ui.lw_lv2.currentItem().setText(newPath)
  362. elif self.ui.tw_paths.currentIndex() == 3:
  363. self.ui.lw_vst.currentItem().setText(newPath)
  364. elif self.ui.tw_paths.currentIndex() == 4:
  365. self.ui.lw_gig.currentItem().setText(newPath)
  366. elif self.ui.tw_paths.currentIndex() == 5:
  367. self.ui.lw_sf2.currentItem().setText(newPath)
  368. elif self.ui.tw_paths.currentIndex() == 6:
  369. self.ui.lw_sfz.currentItem().setText(newPath)
  370. @pyqtSlot(int)
  371. def slot_pluginPathTabChanged(self, index):
  372. if index == 0:
  373. row = self.ui.lw_ladspa.currentRow()
  374. elif index == 1:
  375. row = self.ui.lw_dssi.currentRow()
  376. elif index == 2:
  377. row = self.ui.lw_lv2.currentRow()
  378. elif index == 3:
  379. row = self.ui.lw_vst.currentRow()
  380. elif index == 4:
  381. row = self.ui.lw_gig.currentRow()
  382. elif index == 5:
  383. row = self.ui.lw_sf2.currentRow()
  384. elif index == 6:
  385. row = self.ui.lw_sfz.currentRow()
  386. else:
  387. row = -1
  388. check = bool(row >= 0)
  389. self.ui.b_paths_remove.setEnabled(check)
  390. self.ui.b_paths_change.setEnabled(check)
  391. @pyqtSlot(int)
  392. def slot_pluginPathRowChanged(self, row):
  393. check = bool(row >= 0)
  394. self.ui.b_paths_remove.setEnabled(check)
  395. self.ui.b_paths_change.setEnabled(check)
  396. def done(self, r):
  397. QDialog.done(self, r)
  398. self.close()
  399. # ------------------------------------------------------------------------------------------------------------
  400. # Main Window
  401. class CarlaMainW(QMainWindow):
  402. def __init__(self, parent=None):
  403. QMainWindow.__init__(self, parent)
  404. self.ui = ui_carla.Ui_CarlaMainW()
  405. self.ui.setupUi(self)
  406. # -------------------------------------------------------------
  407. # Load Settings
  408. self.loadSettings(True)
  409. self.loadRDFs()
  410. self.setStyleSheet("""
  411. QWidget#centralwidget {
  412. background-color: qlineargradient(spread:pad,
  413. x1:0.0, y1:0.0,
  414. x2:0.2, y2:1.0,
  415. stop:0 rgb( 7, 7, 7),
  416. stop:1 rgb(28, 28, 28)
  417. );
  418. }
  419. """)
  420. # -------------------------------------------------------------
  421. # Internal stuff
  422. self.fEngineStarted = False
  423. self.fFirstEngineInit = False
  424. self.fProjectFilename = None
  425. self.fProjectLoading = False
  426. self.fPluginCount = 0
  427. self.fPluginList = []
  428. self.fIdleTimerFast = 0
  429. self.fIdleTimerSlow = 0
  430. #self._nsmAnnounce2str = ""
  431. #self._nsmOpen1str = ""
  432. #self._nsmOpen2str = ""
  433. #self.nsm_server = None
  434. #self.nsm_url = None
  435. # -------------------------------------------------------------
  436. # Set-up GUI stuff
  437. self.ui.act_engine_start.setEnabled(False)
  438. self.ui.act_engine_stop.setEnabled(False)
  439. self.ui.act_plugin_remove_all.setEnabled(False)
  440. self.resize(self.width(), 0)
  441. #self.m_fakeEdit = PluginEdit(self, -1)
  442. #self.m_curEdit = self.m_fakeEdit
  443. #self.w_edit.layout().addWidget(self.m_curEdit)
  444. #self.w_edit.layout().addStretch()
  445. # -------------------------------------------------------------
  446. # Connect actions to functions
  447. self.connect(self.ui.act_file_new, SIGNAL("triggered()"), SLOT("slot_fileNew()"))
  448. self.connect(self.ui.act_file_open, SIGNAL("triggered()"), SLOT("slot_fileOpen()"))
  449. self.connect(self.ui.act_file_save, SIGNAL("triggered()"), SLOT("slot_fileSave()"))
  450. self.connect(self.ui.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_fileSaveAs()"))
  451. self.connect(self.ui.act_engine_start, SIGNAL("triggered()"), SLOT("slot_engineStart()"))
  452. self.connect(self.ui.act_engine_stop, SIGNAL("triggered()"), SLOT("slot_engineStop()"))
  453. self.connect(self.ui.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_pluginAdd()"))
  454. self.connect(self.ui.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_pluginRemoveAll()"))
  455. self.connect(self.ui.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()"))
  456. self.connect(self.ui.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarla()"))
  457. self.connect(self.ui.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  458. self.connect(self.ui.ch_transport, SIGNAL("currentIndexChanged(int)"), SLOT("slot_transportModeChanged(int)"))
  459. self.connect(self.ui.b_transport_play, SIGNAL("clicked(bool)"), SLOT("slot_transportPlayPause(bool)"))
  460. self.connect(self.ui.b_transport_stop, SIGNAL("clicked()"), SLOT("slot_transportStop()"))
  461. self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_handleSIGUSR1()"))
  462. self.connect(self, SIGNAL("SIGTERM()"), SLOT("slot_handleSIGTERM()"))
  463. self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)"))
  464. self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)"))
  465. self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)"))
  466. self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)"))
  467. self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)"))
  468. self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)"))
  469. self.connect(self, SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiCcChangedCallback(int, int, int)"))
  470. self.connect(self, SIGNAL("ProgramChangedCallback(int, int)"), SLOT("slot_handleProgramChangedCallback(int, int)"))
  471. self.connect(self, SIGNAL("MidiProgramChangedCallback(int, int)"), SLOT("slot_handleMidiProgramChangedCallback(int, int)"))
  472. self.connect(self, SIGNAL("NoteOnCallback(int, int, int, int)"), SLOT("slot_handleNoteOnCallback(int, int, int, int)"))
  473. self.connect(self, SIGNAL("NoteOffCallback(int, int, int)"), SLOT("slot_handleNoteOffCallback(int, int, int)"))
  474. self.connect(self, SIGNAL("ShowGuiCallback(int, int)"), SLOT("slot_handleShowGuiCallback(int, int)"))
  475. self.connect(self, SIGNAL("UpdateCallback(int)"), SLOT("slot_handleUpdateCallback(int)"))
  476. self.connect(self, SIGNAL("ReloadInfoCallback(int)"), SLOT("slot_handleReloadInfoCallback(int)"))
  477. self.connect(self, SIGNAL("ReloadParametersCallback(int)"), SLOT("slot_handleReloadParametersCallback(int)"))
  478. self.connect(self, SIGNAL("ReloadProgramsCallback(int)"), SLOT("slot_handleReloadProgramsCallback(int)"))
  479. self.connect(self, SIGNAL("ReloadAllCallback(int)"), SLOT("slot_handleReloadAllCallback(int)"))
  480. #self.connect(self, SIGNAL("NSM_AnnounceCallback()"), SLOT("slot_handleNSM_AnnounceCallback()"))
  481. #self.connect(self, SIGNAL("NSM_Open1Callback()"), SLOT("slot_handleNSM_Open1Callback()"))
  482. #self.connect(self, SIGNAL("NSM_Open2Callback()"), SLOT("slot_handleNSM_Open2Callback()"))
  483. #self.connect(self, SIGNAL("NSM_SaveCallback()"), SLOT("slot_handleNSM_SaveCallback()"))
  484. self.connect(self, SIGNAL("ErrorCallback(QString)"), SLOT("slot_handleErrorCallback(QString)"))
  485. self.connect(self, SIGNAL("QuitCallback()"), SLOT("slot_handleQuitCallback()"))
  486. #NSM_URL = os.getenv("NSM_URL")
  487. #if NSM_URL:
  488. #Carla.host.nsm_announce(NSM_URL, os.getpid())
  489. #else:
  490. QTimer.singleShot(0, self, SLOT("slot_engineStart()"))
  491. def startEngine(self, clientName = "Carla"):
  492. # ---------------------------------------------
  493. # Engine settings
  494. settings = QSettings()
  495. Carla.processMode = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int)
  496. Carla.maxParameters = settings.value("Engine/MaxParameters", MAX_DEFAULT_PARAMETERS, type=int)
  497. transportMode = settings.value("Engine/TransportMode", TRANSPORT_MODE_JACK, type=int)
  498. forceStereo = settings.value("Engine/ForceStereo", False, type=bool)
  499. preferPluginBridges = settings.value("Engine/PreferPluginBridges", False, type=bool)
  500. preferUiBridges = settings.value("Engine/PreferUiBridges", True, type=bool)
  501. useDssiVstChunks = settings.value("Engine/UseDssiVstChunks", False, type=bool)
  502. oscUiTimeout = settings.value("Engine/OscUiTimeout", 40, type=int)
  503. preferredBufferSize = settings.value("Engine/PreferredBufferSize", 512, type=int)
  504. preferredSampleRate = settings.value("Engine/PreferredSampleRate", 44100, type=int)
  505. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  506. forceStereo = True
  507. elif Carla.processMode == PROCESS_MODE_MULTIPLE_CLIENTS and os.getenv("LADISH_APP_NAME"):
  508. print("LADISH detected but using multiple clients (not allowed), forcing single client now")
  509. Carla.processMode = PROCESS_MODE_SINGLE_CLIENT
  510. Carla.host.set_engine_option(OPTION_PROCESS_MODE, Carla.processMode, "")
  511. Carla.host.set_engine_option(OPTION_MAX_PARAMETERS, Carla.maxParameters, "")
  512. Carla.host.set_engine_option(OPTION_FORCE_STEREO, forceStereo, "")
  513. Carla.host.set_engine_option(OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "")
  514. Carla.host.set_engine_option(OPTION_PREFER_UI_BRIDGES, preferUiBridges, "")
  515. Carla.host.set_engine_option(OPTION_USE_DSSI_VST_CHUNKS, useDssiVstChunks, "")
  516. Carla.host.set_engine_option(OPTION_OSC_UI_TIMEOUT, oscUiTimeout, "")
  517. Carla.host.set_engine_option(OPTION_PREFERRED_BUFFER_SIZE, preferredBufferSize, "")
  518. Carla.host.set_engine_option(OPTION_PREFERRED_SAMPLE_RATE, preferredSampleRate, "")
  519. # ---------------------------------------------
  520. # Start
  521. audioDriver = settings.value("Engine/AudioDriver", "JACK", type=str)
  522. if not Carla.host.engine_init(audioDriver, clientName):
  523. if self.fFirstEngineInit:
  524. self.fFirstEngineInit = False
  525. return
  526. audioError = cString(Carla.host.get_last_error())
  527. if audioError:
  528. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver, audioError)))
  529. else:
  530. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver))
  531. return
  532. self.fEngineStarted = True
  533. self.fFirstEngineInit = False
  534. self.fPluginCount = 0
  535. self.fPluginList = []
  536. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  537. maxCount = MAX_RACK_PLUGINS
  538. elif Carla.processMode == PROCESS_MODE_PATCHBAY:
  539. maxCount = MAX_PATCHBAY_PLUGINS
  540. else:
  541. maxCount = MAX_DEFAULT_PLUGINS
  542. self.ui.ch_transport.blockSignals(True)
  543. self.ui.ch_transport.addItem(self.tr("Internal"))
  544. if audioDriver == "JACK":
  545. self.ui.ch_transport.addItem(self.tr("JACK"))
  546. elif transportMode == TRANSPORT_MODE_JACK:
  547. transportMode = TRANSPORT_MODE_INTERNAL
  548. self.ui.ch_transport.setCurrentIndex(transportMode)
  549. self.ui.ch_transport.blockSignals(False)
  550. for x in range(maxCount):
  551. self.fPluginList.append(None)
  552. Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, transportMode, "")
  553. # Peaks
  554. self.fIdleTimerFast = self.startTimer(self.fSavedSettings["Main/RefreshInterval"])
  555. # LEDs and edit dialog parameters
  556. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  557. def stopEngine(self):
  558. if self.fPluginCount > 0:
  559. 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"
  560. "Do you want to do this now?"),
  561. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  562. if ask != QMessageBox.Yes:
  563. return
  564. self.removeAllPlugins()
  565. if Carla.host.is_engine_running() and not Carla.host.engine_close():
  566. print(cString(Carla.host.get_last_error()))
  567. self.fEngineStarted = False
  568. self.fPluginCount = 0
  569. self.fPluginList = []
  570. self.killTimer(self.fIdleTimerFast)
  571. self.killTimer(self.fIdleTimerSlow)
  572. settings = QSettings()
  573. settings.setValue("Engine/TransportMode", self.ui.ch_transport.currentIndex())
  574. self.ui.ch_transport.blockSignals(True)
  575. self.ui.ch_transport.clear()
  576. self.ui.ch_transport.blockSignals(False)
  577. def loadProject(self, filename):
  578. self.fProjectFilename = filename
  579. self.setWindowTitle("Carla - %s" % os.path.basename(filename))
  580. self.fProjectLoading = True
  581. Carla.host.load_project(filename)
  582. self.fProjectLoading = False
  583. def loadProjectLater(self, filename):
  584. self.fProjectFilename = filename
  585. self.setWindowTitle("Carla - %s" % os.path.basename(filename))
  586. QTimer.singleShot(0, self, SLOT("slot_loadProjectLater()"))
  587. def saveProject(self, filename):
  588. self.fProjectFilename = filename
  589. self.setWindowTitle("Carla - %s" % os.path.basename(filename))
  590. Carla.host.save_project(filename)
  591. def addPlugin(self, btype, ptype, filename, name, label, extraStuff):
  592. if not self.fEngineStarted:
  593. QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
  594. return False
  595. if not Carla.host.add_plugin(btype, ptype, filename, name, label, extraStuff):
  596. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  597. return False
  598. return True
  599. def removeAllPlugins(self):
  600. while (self.ui.w_plugins.layout().takeAt(0)):
  601. pass
  602. self.ui.act_plugin_remove_all.setEnabled(False)
  603. for i in range(self.fPluginCount):
  604. pwidget = self.fPluginList[i]
  605. if pwidget is None:
  606. break
  607. self.fPluginList[i] = None
  608. pwidget.ui.edit_dialog.close()
  609. pwidget.close()
  610. pwidget.deleteLater()
  611. del pwidget
  612. self.fPluginCount = 0
  613. Carla.host.remove_all_plugins()
  614. @pyqtSlot()
  615. def slot_fileNew(self):
  616. self.removeAllPlugins()
  617. self.fProjectFilename = None
  618. self.fProjectLoading = False
  619. self.setWindowTitle("Carla")
  620. @pyqtSlot()
  621. def slot_fileOpen(self):
  622. fileFilter = self.tr("Carla Project File (*.carxp)")
  623. filenameTry = QFileDialog.getOpenFileName(self, self.tr("Open Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)
  624. if filenameTry:
  625. # FIXME - show dialog to user
  626. self.removeAllPlugins()
  627. self.loadProject(filenameTry)
  628. @pyqtSlot()
  629. def slot_fileSave(self, saveAs=False):
  630. if self.fProjectFilename and not saveAs:
  631. return self.saveProject(self.fProjectFilename)
  632. fileFilter = self.tr("Carla Project File (*.carxp)")
  633. filenameTry = QFileDialog.getSaveFileName(self, self.tr("Save Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)
  634. if filenameTry:
  635. if not filenameTry.endswith(".carxp"):
  636. filenameTry += ".carxp"
  637. self.saveProject(filenameTry)
  638. @pyqtSlot()
  639. def slot_fileSaveAs(self):
  640. self.slot_fileSave(True)
  641. @pyqtSlot()
  642. def slot_loadProjectLater(self):
  643. self.fProjectLoading = True
  644. Carla.host.load_project(self.fProjectFilename)
  645. self.fProjectLoading = False
  646. @pyqtSlot()
  647. def slot_engineStart(self):
  648. self.startEngine()
  649. check = Carla.host.is_engine_running()
  650. self.ui.act_file_open.setEnabled(check)
  651. self.ui.act_engine_start.setEnabled(not check)
  652. self.ui.act_engine_stop.setEnabled(check)
  653. self.ui.act_engine_configure.setEnabled(not check)
  654. self.ui.frame_transport.setEnabled(check)
  655. @pyqtSlot()
  656. def slot_engineStop(self):
  657. self.stopEngine()
  658. check = Carla.host.is_engine_running()
  659. self.ui.act_file_open.setEnabled(check)
  660. self.ui.act_engine_start.setEnabled(not check)
  661. self.ui.act_engine_stop.setEnabled(check)
  662. self.ui.frame_transport.setEnabled(check)
  663. @pyqtSlot()
  664. def slot_pluginAdd(self):
  665. dialog = PluginDatabaseW(self)
  666. if dialog.exec_():
  667. btype = dialog.fRetPlugin['build']
  668. ptype = dialog.fRetPlugin['type']
  669. filename = dialog.fRetPlugin['binary']
  670. label = dialog.fRetPlugin['label']
  671. extraStuff = self.getExtraStuff(dialog.fRetPlugin)
  672. self.addPlugin(btype, ptype, filename, None, label, extraStuff)
  673. @pyqtSlot()
  674. def slot_pluginRemoveAll(self):
  675. self.removeAllPlugins()
  676. self.connect(self.ui.ch_transport, SIGNAL("currentIndexChanged(int)"), SLOT("(int)"))
  677. self.connect(self.ui.b_transport_play, SIGNAL("clicked(bool)"), SLOT("(bool)"))
  678. self.connect(self.ui.b_transport_stop, SIGNAL("clicked()"), SLOT("()"))
  679. @pyqtSlot(int)
  680. def slot_transportModeChanged(self, newMode):
  681. Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, newMode, "")
  682. @pyqtSlot(bool)
  683. def slot_transportPlayPause(self, toggled):
  684. if toggled:
  685. Carla.host.transport_play()
  686. else:
  687. Carla.host.transport_pause()
  688. @pyqtSlot()
  689. def slot_transportStop(self):
  690. Carla.host.transport_pause()
  691. Carla.host.transport_relocate(0)
  692. @pyqtSlot()
  693. def slot_aboutCarla(self):
  694. CarlaAboutW(self).exec_()
  695. @pyqtSlot()
  696. def slot_configureCarla(self):
  697. dialog = CarlaSettingsW(self)
  698. if dialog.exec_():
  699. self.loadSettings(False)
  700. for pwidget in self.fPluginList:
  701. if pwidget is None:
  702. return
  703. pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  704. @pyqtSlot()
  705. def slot_handleSIGUSR1(self):
  706. print("Got SIGUSR1 -> Saving project now")
  707. QTimer.singleShot(0, self, SLOT("slot_fileSave()"))
  708. @pyqtSlot()
  709. def slot_handleSIGTERM(self):
  710. print("Got SIGTERM -> Closing now")
  711. self.close()
  712. @pyqtSlot(int, int, int, float, str)
  713. def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
  714. print("DEBUG :: %i, %i, %i, %f, \"%s\")" % (pluginId, value1, value2, value3, valueStr))
  715. @pyqtSlot(int)
  716. def slot_handlePluginAddedCallback(self, pluginId):
  717. pwidget = PluginWidget(self, pluginId)
  718. pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  719. self.ui.w_plugins.layout().addWidget(pwidget)
  720. self.fPluginCount += 1
  721. self.fPluginList[pluginId] = pwidget
  722. if not self.fProjectLoading:
  723. pwidget.setActive(True, True, True)
  724. if self.fPluginCount == 1:
  725. self.ui.act_plugin_remove_all.setEnabled(True)
  726. @pyqtSlot(int)
  727. def slot_handlePluginRemovedCallback(self, pluginId):
  728. if pluginId >= self.fPluginCount:
  729. return
  730. pwidget = self.fPluginList[pluginId]
  731. if pwidget is None:
  732. return
  733. self.fPluginList[pluginId] = None
  734. self.fPluginCount -= 1
  735. self.ui.w_plugins.layout().removeWidget(pwidget)
  736. pwidget.ui.edit_dialog.close()
  737. pwidget.close()
  738. pwidget.deleteLater()
  739. del pwidget
  740. # push all plugins 1 slot back
  741. for i in range(pluginId, self.fPluginCount):
  742. self.fPluginList[i] = self.fPluginList[i+1]
  743. self.fPluginList[i].setId(i)
  744. if self.fPluginCount == 0:
  745. self.ui.act_plugin_remove_all.setEnabled(False)
  746. @pyqtSlot(int, int, float)
  747. def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value):
  748. if pluginId >= self.fPluginCount:
  749. return
  750. pwidget = self.fPluginList[pluginId]
  751. if pwidget is None:
  752. return
  753. pwidget.setParameterValue(parameterId, value)
  754. @pyqtSlot(int, int, float)
  755. def slot_handleParameterDefaultChangedCallback(self, pluginId, parameterId, value):
  756. if pluginId >= self.fPluginCount:
  757. return
  758. pwidget = self.fPluginList[pluginId]
  759. if pwidget is None:
  760. return
  761. pwidget.setParameterDefault(parameterId, value)
  762. @pyqtSlot(int, int, int)
  763. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, parameterId, channel):
  764. if pluginId >= self.fPluginCount:
  765. return
  766. pwidget = self.fPluginList[pluginId]
  767. if pwidget is None:
  768. return
  769. pwidget.setParameterMidiChannel(parameterId, channel)
  770. @pyqtSlot(int, int, int)
  771. def slot_handleParameterMidiCcChangedCallback(self, pluginId, parameterId, cc):
  772. if pluginId >= self.fPluginCount:
  773. return
  774. pwidget = self.fPluginList[pluginId]
  775. if pwidget is None:
  776. return
  777. pwidget.setParameterMidiControl(parameterId, cc)
  778. @pyqtSlot(int, int)
  779. def slot_handleProgramChangedCallback(self, pluginId, programId):
  780. if pluginId >= self.fPluginCount:
  781. return
  782. pwidget = self.fPluginList[pluginId]
  783. if pwidget is None:
  784. return
  785. pwidget.setProgram(programId)
  786. @pyqtSlot(int, int)
  787. def slot_handleMidiProgramChangedCallback(self, pluginId, midiProgramId):
  788. if pluginId >= self.fPluginCount:
  789. return
  790. pwidget = self.fPluginList[pluginId]
  791. if pwidget is None:
  792. return
  793. pwidget.setMidiProgram(midiProgramId)
  794. @pyqtSlot(int, int, int, int)
  795. def slot_handleNoteOnCallback(self, pluginId, channel, note, velo):
  796. if pluginId >= self.fPluginCount:
  797. return
  798. pwidget = self.fPluginList[pluginId]
  799. if pwidget is None:
  800. return
  801. pwidget.sendNoteOn(channel, note)
  802. @pyqtSlot(int, int, int)
  803. def slot_handleNoteOffCallback(self, pluginId, channel, note):
  804. if pluginId >= self.fPluginCount:
  805. return
  806. pwidget = self.fPluginList[pluginId]
  807. if pwidget is None:
  808. return
  809. pwidget.sendNoteOff(channel, note)
  810. @pyqtSlot(int, int)
  811. def slot_handleShowGuiCallback(self, pluginId, show):
  812. if pluginId >= self.fPluginCount:
  813. return
  814. pwidget = self.fPluginList[pluginId]
  815. if pwidget is None:
  816. return
  817. if show == 0:
  818. pwidget.ui.b_gui.setChecked(False)
  819. pwidget.ui.b_gui.setEnabled(True)
  820. elif show == 1:
  821. pwidget.ui.b_gui.setChecked(True)
  822. pwidget.ui.b_gui.setEnabled(True)
  823. elif show == -1:
  824. pwidget.ui.b_gui.setChecked(False)
  825. pwidget.ui.b_gui.setEnabled(False)
  826. @pyqtSlot(int)
  827. def slot_handleUpdateCallback(self, pluginId):
  828. if pluginId >= self.fPluginCount:
  829. return
  830. pwidget = self.fPluginList[pluginId]
  831. if pwidget is None:
  832. return
  833. pwidget.ui.edit_dialog.do_update()
  834. @pyqtSlot(int)
  835. def slot_handleReloadInfoCallback(self, pluginId):
  836. if pluginId >= self.fPluginCount:
  837. return
  838. pwidget = self.fPluginList[pluginId]
  839. if pwidget is None:
  840. return
  841. pwidget.ui.edit_dialog.reloadInfo()
  842. @pyqtSlot(int)
  843. def slot_handleReloadParametersCallback(self, pluginId):
  844. if pluginId >= self.fPluginCount:
  845. return
  846. pwidget = self.fPluginList[pluginId]
  847. if pwidget is None:
  848. return
  849. pwidget.ui.edit_dialog.reloadParameters()
  850. @pyqtSlot(int)
  851. def slot_handleReloadProgramsCallback(self, pluginId):
  852. if pluginId >= self.fPluginCount:
  853. return
  854. pwidget = self.fPluginList[pluginId]
  855. if pwidget is None:
  856. return
  857. pwidget.ui.edit_dialog.reloadPrograms()
  858. @pyqtSlot(int)
  859. def slot_handleReloadAllCallback(self, pluginId):
  860. if pluginId >= self.fPluginCount:
  861. return
  862. pwidget = self.fPluginList[pluginId]
  863. if pwidget is None:
  864. return
  865. pwidget.ui.edit_dialog.reloadAll()
  866. @pyqtSlot(str)
  867. def slot_handleErrorCallback(self, error):
  868. QMessageBox.critical(self, self.tr("Error"), error)
  869. @pyqtSlot()
  870. def slot_handleQuitCallback(self):
  871. CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  872. self.tr("Engine has been stopped or crashed.\nPlease restart Carla"),
  873. self.tr("You may want to save your session now..."), QMessageBox.Ok, QMessageBox.Ok)
  874. def getExtraStuff(self, plugin):
  875. ptype = plugin['type']
  876. if ptype == PLUGIN_LADSPA:
  877. uniqueId = plugin['uniqueId']
  878. for rdfItem in self.fLadspaRdfList:
  879. if rdfItem.UniqueID == uniqueId:
  880. return pointer(rdfItem)
  881. elif ptype == PLUGIN_DSSI:
  882. if (plugin['hints'] & PLUGIN_HAS_GUI):
  883. gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label'])
  884. if gui:
  885. return gui.encode("utf-8")
  886. elif ptype == PLUGIN_SF2:
  887. if plugin['name'].endswith(" (16 outputs)"):
  888. # return a dummy non-null pointer
  889. INTPOINTER = POINTER(c_int)
  890. ptr = c_int(0x1)
  891. addr = addressof(ptr)
  892. return cast(addr, INTPOINTER)
  893. return c_nullptr
  894. def loadRDFs(self):
  895. # Save RDF info for later
  896. self.fLadspaRdfList = []
  897. if not haveLRDF:
  898. return
  899. settingsDir = os.path.join(HOME, ".config", "Cadence")
  900. frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db")
  901. if os.path.exists(frLadspaFile):
  902. frLadspa = open(frLadspaFile, 'r')
  903. try:
  904. self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa))
  905. except:
  906. pass
  907. frLadspa.close()
  908. def saveSettings(self):
  909. settings = QSettings()
  910. settings.setValue("Geometry", self.saveGeometry())
  911. settings.setValue("ShowToolbar", self.ui.toolBar.isVisible())
  912. def loadSettings(self, geometry):
  913. settings = QSettings()
  914. if geometry:
  915. self.restoreGeometry(settings.value("Geometry", ""))
  916. showToolbar = settings.value("ShowToolbar", True, type=bool)
  917. self.ui.act_settings_show_toolbar.setChecked(showToolbar)
  918. self.ui.toolBar.setVisible(showToolbar)
  919. self.fSavedSettings = {
  920. "Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", HOME, type=str),
  921. "Main/RefreshInterval": settings.value("Main/RefreshInterval", 50, type=int)
  922. }
  923. # ---------------------------------------------
  924. # plugin checks
  925. if settings.value("Engine/DisableChecks", False, type=bool):
  926. os.environ["CARLA_DISCOVERY_NO_PROCESSING_CHECKS"] = "true"
  927. elif os.getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"):
  928. os.environ.pop("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
  929. # ---------------------------------------------
  930. # plugin paths
  931. Carla.LADSPA_PATH = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH))
  932. Carla.DSSI_PATH = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH))
  933. Carla.LV2_PATH = toList(settings.value("Paths/LV2", Carla.LV2_PATH))
  934. Carla.VST_PATH = toList(settings.value("Paths/VST", Carla.VST_PATH))
  935. Carla.GIG_PATH = toList(settings.value("Paths/GIG", Carla.GIG_PATH))
  936. Carla.SF2_PATH = toList(settings.value("Paths/SF2", Carla.SF2_PATH))
  937. Carla.SFZ_PATH = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH))
  938. os.environ["LADSPA_PATH"] = splitter.join(Carla.LADSPA_PATH)
  939. os.environ["DSSI_PATH"] = splitter.join(Carla.DSSI_PATH)
  940. os.environ["LV2_PATH"] = splitter.join(Carla.LV2_PATH)
  941. os.environ["VST_PATH"] = splitter.join(Carla.VST_PATH)
  942. os.environ["GIG_PATH"] = splitter.join(Carla.GIG_PATH)
  943. os.environ["SF2_PATH"] = splitter.join(Carla.SF2_PATH)
  944. os.environ["SFZ_PATH"] = splitter.join(Carla.SFZ_PATH)
  945. def timerEvent(self, event):
  946. if event.timerId() == self.fIdleTimerFast:
  947. Carla.host.engine_idle()
  948. for pwidget in self.fPluginList:
  949. if pwidget is None:
  950. break
  951. pwidget.idleFast()
  952. elif event.timerId() == self.fIdleTimerSlow:
  953. for pwidget in self.fPluginList:
  954. if pwidget is None:
  955. break
  956. pwidget.idleSlow()
  957. QMainWindow.timerEvent(self, event)
  958. def closeEvent(self, event):
  959. #if self.nsm_server:
  960. #self.nsm_server.stop()
  961. self.saveSettings()
  962. if Carla.host.is_engine_running():
  963. Carla.host.set_engine_about_to_close()
  964. self.removeAllPlugins()
  965. self.stopEngine()
  966. QMainWindow.closeEvent(self, event)
  967. # ------------------------------------------------------------------------------------------------
  968. def callbackFunction(ptr, action, pluginId, value1, value2, value3, valueStr):
  969. if pluginId < 0 or not Carla.gui:
  970. return
  971. if action == CALLBACK_DEBUG:
  972. Carla.gui.emit(SIGNAL("DebugCallback(int, int, int, double, QString)"), pluginId, value1, value2, value3, cString(valueStr))
  973. elif action == CALLBACK_PLUGIN_ADDED:
  974. Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId)
  975. elif action == CALLBACK_PLUGIN_REMOVED:
  976. Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId)
  977. elif action == CALLBACK_PARAMETER_VALUE_CHANGED:
  978. Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3)
  979. elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED:
  980. Carla.gui.emit(SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), pluginId, value1, value3)
  981. elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  982. Carla.gui.emit(SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), pluginId, value1, value2)
  983. elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  984. Carla.gui.emit(SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), pluginId, value1, value2)
  985. elif action == CALLBACK_PROGRAM_CHANGED:
  986. Carla.gui.emit(SIGNAL("ProgramChangedCallback(int, int)"), pluginId, value1)
  987. elif action == CALLBACK_MIDI_PROGRAM_CHANGED:
  988. Carla.gui.emit(SIGNAL("MidiProgramChangedCallback(int, int)"), pluginId, value1)
  989. elif action == CALLBACK_NOTE_ON:
  990. Carla.gui.emit(SIGNAL("NoteOnCallback(int, int, int, int)"), pluginId, value1, value2, value3)
  991. elif action == CALLBACK_NOTE_OFF:
  992. Carla.gui.emit(SIGNAL("NoteOffCallback(int, int, int)"), pluginId, value1, value2)
  993. elif action == CALLBACK_SHOW_GUI:
  994. Carla.gui.emit(SIGNAL("ShowGuiCallback(int, int)"), pluginId, value1)
  995. elif action == CALLBACK_UPDATE:
  996. Carla.gui.emit(SIGNAL("UpdateCallback(int)"), pluginId)
  997. elif action == CALLBACK_RELOAD_INFO:
  998. Carla.gui.emit(SIGNAL("ReloadInfoCallback(int)"), pluginId)
  999. elif action == CALLBACK_RELOAD_PARAMETERS:
  1000. Carla.gui.emit(SIGNAL("ReloadParametersCallback(int)"), pluginId)
  1001. elif action == CALLBACK_RELOAD_PROGRAMS:
  1002. Carla.gui.emit(SIGNAL("ReloadProgramsCallback(int)"), pluginId)
  1003. elif action == CALLBACK_RELOAD_ALL:
  1004. Carla.gui.emit(SIGNAL("ReloadAllCallback(int)"), pluginId)
  1005. #elif action == CALLBACK_NSM_ANNOUNCE:
  1006. #Carla.gui._nsmAnnounce2str = cString(Carla.host.get_last_error())
  1007. #Carla.gui.emit(SIGNAL("NSM_AnnounceCallback()"))
  1008. #elif action == CALLBACK_NSM_OPEN1:
  1009. #Carla.gui._nsmOpen1str = cString(valueStr)
  1010. #Carla.gui.emit(SIGNAL("NSM_Open1Callback()"))
  1011. #elif action == CALLBACK_NSM_OPEN2:
  1012. #Carla.gui._nsmOpen2str = cString(valueStr)
  1013. #Carla.gui.emit(SIGNAL("NSM_Open2Callback()"))
  1014. #elif action == CALLBACK_NSM_SAVE:
  1015. #Carla.gui.emit(SIGNAL("NSM_SaveCallback()"))
  1016. elif action == CALLBACK_ERROR:
  1017. Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), valueStr)
  1018. elif action == CALLBACK_QUIT:
  1019. Carla.gui.emit(SIGNAL("QuitCallback()"))
  1020. #--------------- main ------------------
  1021. if __name__ == '__main__':
  1022. # App initialization
  1023. app = QApplication(sys.argv)
  1024. app.setApplicationName("Carla")
  1025. app.setApplicationVersion(VERSION)
  1026. app.setOrganizationName("Cadence")
  1027. app.setWindowIcon(QIcon(":/scalable/carla.svg"))
  1028. libPrefix = None
  1029. projectFilename = None
  1030. for i in range(len(app.arguments())):
  1031. if i == 0: continue
  1032. argument = app.arguments()[i]
  1033. if argument.startswith("--with-libprefix="):
  1034. libPrefix = argument.replace("--with-libprefix=", "")
  1035. elif os.path.exists(argument):
  1036. projectFilename = argument
  1037. # Init backend
  1038. Carla.host = Host(libPrefix)
  1039. Carla.host.set_engine_callback(callbackFunction)
  1040. Carla.host.set_engine_option(OPTION_PROCESS_NAME, 0, "carla")
  1041. # Set bridge paths
  1042. if carla_bridge_native:
  1043. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_NATIVE, 0, carla_bridge_native)
  1044. if carla_bridge_posix32:
  1045. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX32, 0, carla_bridge_posix32)
  1046. if carla_bridge_posix64:
  1047. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX64, 0, carla_bridge_posix64)
  1048. if carla_bridge_win32:
  1049. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32)
  1050. if carla_bridge_win64:
  1051. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64)
  1052. if WINDOWS:
  1053. if carla_bridge_lv2_windows:
  1054. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, carla_bridge_lv2_windows)
  1055. if carla_bridge_vst_hwnd:
  1056. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_HWND, 0, carla_bridge_vst_hwnd)
  1057. elif MACOS:
  1058. if carla_bridge_lv2_cocoa:
  1059. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_COCOA, 0, carla_bridge_lv2_cocoa)
  1060. if carla_bridge_vst_cocoa:
  1061. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_COCOA, 0, carla_bridge_vst_cocoa)
  1062. else:
  1063. if carla_bridge_lv2_gtk2:
  1064. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2)
  1065. if carla_bridge_lv2_gtk3:
  1066. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK3, 0, carla_bridge_lv2_gtk3)
  1067. if carla_bridge_lv2_qt4:
  1068. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4)
  1069. if carla_bridge_lv2_qt5:
  1070. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT5, 0, carla_bridge_lv2_qt5)
  1071. if carla_bridge_lv2_x11:
  1072. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11)
  1073. if carla_bridge_vst_x11:
  1074. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11)
  1075. # Create GUI and start engine
  1076. Carla.gui = CarlaMainW()
  1077. # Set-up custom signal handling
  1078. setUpSignals()
  1079. # Show GUI
  1080. Carla.gui.show()
  1081. # Load project file if set
  1082. if projectFilename:
  1083. Carla.gui.loadProjectLater(projectFilename)
  1084. # App-Loop
  1085. ret = app.exec_()
  1086. # Exit properly
  1087. sys.exit(ret)