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 92KB

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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289
  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, QLabel, QMainWindow, QResizeEvent
  22. from PyQt4.QtGui import QImage, QPalette, QPrinter, QPrintDialog, QSyntaxHighlighter
  23. # ------------------------------------------------------------------------------------------------------------
  24. # Imports (Custom Stuff)
  25. import patchcanvas
  26. import ui_carla
  27. import ui_carla_settings
  28. import ui_carla_settings_driver
  29. from carla_shared import *
  30. # ------------------------------------------------------------------------------------------------------------
  31. # Try Import OpenGL
  32. try:
  33. from PyQt4.QtOpenGL import QGLWidget
  34. hasGL = True
  35. except:
  36. hasGL = False
  37. # ------------------------------------------------------------------------------------------------------------
  38. # Static Variables
  39. DEFAULT_CANVAS_WIDTH = 3100
  40. DEFAULT_CANVAS_HEIGHT = 2400
  41. # Tab indexes
  42. TAB_INDEX_MAIN = 0
  43. TAB_INDEX_CANVAS = 1
  44. TAB_INDEX_CARLA_ENGINE = 2
  45. TAB_INDEX_CARLA_PATHS = 3
  46. TAB_INDEX_NONE = 4
  47. # Single and Multiple client mode is only for JACK,
  48. # but we still want to match QComboBox index to defines,
  49. # so add +2 pos padding if driverName != "JACK".
  50. PROCESS_MODE_NON_JACK_PADDING = 2
  51. # Carla defaults
  52. CARLA_DEFAULT_PROCESS_HIGH_PRECISION = False
  53. CARLA_DEFAULT_MAX_PARAMETERS = 200
  54. CARLA_DEFAULT_FORCE_STEREO = False
  55. CARLA_DEFAULT_USE_DSSI_VST_CHUNKS = False
  56. CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False
  57. CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = True
  58. CARLA_DEFAULT_PREFER_UI_BRIDGES = True
  59. CARLA_DEFAULT_OSC_UI_TIMEOUT = 4000
  60. CARLA_DEFAULT_DISABLE_CHECKS = False
  61. CARLA_DEFAULT_RTAUDIO_BUFFER_SIZE = 1024
  62. CARLA_DEFAULT_RTAUDIO_SAMPLE_RATE = 44100
  63. if WINDOWS:
  64. CARLA_DEFAULT_AUDIO_DRIVER = "DirectSound"
  65. elif MACOS:
  66. CARLA_DEFAULT_AUDIO_DRIVER = "CoreAudio"
  67. else:
  68. CARLA_DEFAULT_AUDIO_DRIVER = "JACK"
  69. BUFFER_SIZES = (16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192)
  70. SAMPLE_RATES = (22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000)
  71. # ------------------------------------------------------------------------------------------------------------
  72. # Global Variables
  73. appName = os.path.basename(__file__) if os.path.dirname(__file__) in PATH else sys.argv[0]
  74. libPrefix = None
  75. projectFilename = None
  76. # ------------------------------------------------------------------------------------------------------------
  77. # Log Syntax Highlighter
  78. class LogSyntaxHighlighter(QSyntaxHighlighter):
  79. def __init__(self, parent):
  80. QSyntaxHighlighter.__init__(self, parent)
  81. palette = parent.palette()
  82. self.fColorDebug = palette.color(QPalette.Disabled, QPalette.WindowText)
  83. self.fColorError = Qt.red
  84. def highlightBlock(self, text):
  85. if text.startswith("DEBUG:"):
  86. self.setFormat(0, len(text), self.fColorDebug)
  87. elif text.startswith("ERROR:"):
  88. self.setFormat(0, len(text), self.fColorError)
  89. # ------------------------------------------------------------------------------------------------------------
  90. # Settings Dialog
  91. class DriverSettingsW(QDialog):
  92. def __init__(self, parent, driverIndex, driverName):
  93. QDialog.__init__(self, parent)
  94. self.ui = ui_carla_settings_driver.Ui_DriverSettingsW()
  95. self.ui.setupUi(self)
  96. self.ui.stackedWidget.setCurrentIndex(0 if (driverName == "JACK") else 1)
  97. self.fDriverIndex = driverIndex
  98. self.fDriverName = driverName
  99. self.loadSettings()
  100. self.connect(self, SIGNAL("accepted()"), SLOT("slot_saveSettings()"))
  101. def loadSettings(self):
  102. settings = QSettings()
  103. if self.fDriverName == "JACK":
  104. self.ui.cb_jack_autoconnect.setChecked(settings.value("Engine/JackAutoConnect", False, type=bool))
  105. self.ui.cb_jack_timemaster.setChecked(settings.value("Engine/JackTimeMaster", False, type=bool))
  106. else:
  107. deviceNames = Carla.host.get_engine_driver_device_names(self.fDriverIndex)
  108. for name in deviceNames:
  109. self.ui.cb_rtaudio_device.addItem(name)
  110. for bsize in BUFFER_SIZES:
  111. self.ui.cb_rtaudio_buffersize.addItem(str(bsize))
  112. for srate in SAMPLE_RATES:
  113. self.ui.cb_rtaudio_samplerate.addItem(str(srate))
  114. rtaudioDevice = settings.value("Engine/RtAudioDevice", "", type=str)
  115. rtaudioBufferSize = settings.value("Engine/RtAudioBufferSize", CARLA_DEFAULT_RTAUDIO_BUFFER_SIZE, type=int)
  116. rtaudioSampleRate = settings.value("Engine/RtAudioSampleRate", CARLA_DEFAULT_RTAUDIO_SAMPLE_RATE, type=int)
  117. if rtaudioDevice and rtaudioDevice in deviceNames:
  118. self.ui.cb_rtaudio_device.setCurrentIndex(deviceNames.index(rtaudioDevice))
  119. else:
  120. self.ui.cb_rtaudio_device.setCurrentIndex(-1)
  121. if rtaudioBufferSize and rtaudioBufferSize in BUFFER_SIZES:
  122. self.ui.cb_rtaudio_buffersize.setCurrentIndex(BUFFER_SIZES.index(rtaudioBufferSize))
  123. else:
  124. self.ui.cb_rtaudio_buffersize.setCurrentIndex(BUFFER_SIZES.index(CARLA_DEFAULT_RTAUDIO_BUFFER_SIZE))
  125. if rtaudioSampleRate and rtaudioSampleRate in SAMPLE_RATES:
  126. self.ui.cb_rtaudio_samplerate.setCurrentIndex(SAMPLE_RATES.index(rtaudioSampleRate))
  127. else:
  128. self.ui.cb_rtaudio_samplerate.setCurrentIndex(SAMPLE_RATES.index(CARLA_DEFAULT_RTAUDIO_SAMPLE_RATE))
  129. @pyqtSlot()
  130. def slot_saveSettings(self):
  131. settings = QSettings()
  132. if self.fDriverName == "JACK":
  133. settings.setValue("Engine/JackAutoConnect", self.ui.cb_jack_autoconnect.isChecked())
  134. settings.setValue("Engine/JackTimeMaster", self.ui.cb_jack_timemaster.isChecked())
  135. else:
  136. settings.setValue("Engine/RtAudioDevice", self.ui.cb_rtaudio_device.currentText())
  137. settings.setValue("Engine/RtAudioBufferSize", self.ui.cb_rtaudio_buffersize.currentText())
  138. settings.setValue("Engine/RtAudioSampleRate", self.ui.cb_rtaudio_samplerate.currentText())
  139. def done(self, r):
  140. QDialog.done(self, r)
  141. self.close()
  142. class CarlaSettingsW(QDialog):
  143. def __init__(self, parent):
  144. QDialog.__init__(self, parent)
  145. self.ui = ui_carla_settings.Ui_CarlaSettingsW()
  146. self.ui.setupUi(self)
  147. # -------------------------------------------------------------
  148. # Set-up GUI
  149. driverCount = Carla.host.get_engine_driver_count()
  150. for i in range(driverCount):
  151. driverName = cString(Carla.host.get_engine_driver_name(i))
  152. self.ui.cb_engine_audio_driver.addItem(driverName)
  153. # TODO in backend
  154. self.ui.tb_engine_driver_config.setEnabled(False)
  155. # -------------------------------------------------------------
  156. # Load settings
  157. self.loadSettings()
  158. if not hasGL:
  159. self.ui.cb_canvas_use_opengl.setChecked(False)
  160. self.ui.cb_canvas_use_opengl.setEnabled(False)
  161. if WINDOWS:
  162. self.ui.ch_engine_dssi_chunks.setChecked(False)
  163. self.ui.ch_engine_dssi_chunks.setEnabled(False)
  164. # -------------------------------------------------------------
  165. # Set-up connections
  166. self.connect(self, SIGNAL("accepted()"), SLOT("slot_saveSettings()"))
  167. self.connect(self.ui.buttonBox.button(QDialogButtonBox.Reset), SIGNAL("clicked()"), SLOT("slot_resetSettings()"))
  168. self.connect(self.ui.b_main_def_folder_open, SIGNAL("clicked()"), SLOT("slot_getAndSetProjectPath()"))
  169. self.connect(self.ui.cb_engine_audio_driver, SIGNAL("currentIndexChanged(int)"), SLOT("slot_engineAudioDriverChanged()"))
  170. self.connect(self.ui.tb_engine_driver_config, SIGNAL("clicked()"), SLOT("slot_showAudioDriverSettings()"))
  171. self.connect(self.ui.b_paths_add, SIGNAL("clicked()"), SLOT("slot_addPluginPath()"))
  172. self.connect(self.ui.b_paths_remove, SIGNAL("clicked()"), SLOT("slot_removePluginPath()"))
  173. self.connect(self.ui.b_paths_change, SIGNAL("clicked()"), SLOT("slot_changePluginPath()"))
  174. self.connect(self.ui.tw_paths, SIGNAL("currentChanged(int)"), SLOT("slot_pluginPathTabChanged(int)"))
  175. self.connect(self.ui.lw_ladspa, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  176. self.connect(self.ui.lw_dssi, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  177. self.connect(self.ui.lw_lv2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  178. self.connect(self.ui.lw_vst, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  179. self.connect(self.ui.lw_sf2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)"))
  180. # -------------------------------------------------------------
  181. # Post-connect setup
  182. self.ui.lw_ladspa.setCurrentRow(0)
  183. self.ui.lw_dssi.setCurrentRow(0)
  184. self.ui.lw_lv2.setCurrentRow(0)
  185. self.ui.lw_vst.setCurrentRow(0)
  186. self.ui.lw_gig.setCurrentRow(0)
  187. self.ui.lw_sf2.setCurrentRow(0)
  188. self.ui.lw_sfz.setCurrentRow(0)
  189. self.ui.lw_page.setCurrentCell(0, 0)
  190. def loadSettings(self):
  191. settings = QSettings()
  192. # ---------------------------------------
  193. self.ui.le_main_def_folder.setText(settings.value("Main/DefaultProjectFolder", HOME, type=str))
  194. self.ui.ch_theme_pro.setChecked(settings.value("Main/UseProTheme", True, type=bool))
  195. self.ui.sb_gui_refresh.setValue(settings.value("Main/RefreshInterval", 50, type=int))
  196. themeColor = settings.value("Main/ProThemeColor", "Black", type=str)
  197. if themeColor == "Blue":
  198. self.ui.cb_theme_color.setCurrentIndex(1)
  199. elif themeColor == "System":
  200. self.ui.cb_theme_color.setCurrentIndex(2)
  201. else:
  202. self.ui.cb_theme_color.setCurrentIndex(0)
  203. # ---------------------------------------
  204. self.ui.cb_canvas_hide_groups.setChecked(settings.value("Canvas/AutoHideGroups", False, type=bool))
  205. self.ui.cb_canvas_bezier_lines.setChecked(settings.value("Canvas/UseBezierLines", True, type=bool))
  206. self.ui.cb_canvas_eyecandy.setCheckState(settings.value("Canvas/EyeCandy", patchcanvas.EYECANDY_SMALL, type=int))
  207. self.ui.cb_canvas_use_opengl.setChecked(settings.value("Canvas/UseOpenGL", False, type=bool))
  208. self.ui.cb_canvas_render_aa.setCheckState(settings.value("Canvas/Antialiasing", patchcanvas.ANTIALIASING_SMALL, type=int))
  209. self.ui.cb_canvas_render_hq_aa.setChecked(settings.value("Canvas/HighQualityAntialiasing", False, type=bool))
  210. canvasThemeName = settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str)
  211. for i in range(patchcanvas.Theme.THEME_MAX):
  212. thisThemeName = patchcanvas.getThemeName(i)
  213. self.ui.cb_canvas_theme.addItem(thisThemeName)
  214. if thisThemeName == canvasThemeName:
  215. self.ui.cb_canvas_theme.setCurrentIndex(i)
  216. # --------------------------------------------
  217. audioDriver = settings.value("Engine/AudioDriver", CARLA_DEFAULT_AUDIO_DRIVER, type=str)
  218. for i in range(self.ui.cb_engine_audio_driver.count()):
  219. if self.ui.cb_engine_audio_driver.itemText(i) == audioDriver:
  220. self.ui.cb_engine_audio_driver.setCurrentIndex(i)
  221. break
  222. else:
  223. self.ui.cb_engine_audio_driver.setCurrentIndex(-1)
  224. if audioDriver == "JACK":
  225. processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int)
  226. self.ui.cb_engine_process_mode_jack.setCurrentIndex(processModeIndex)
  227. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  228. else:
  229. processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_CONTINUOUS_RACK, type=int)
  230. processModeIndex -= PROCESS_MODE_NON_JACK_PADDING
  231. self.ui.cb_engine_process_mode_other.setCurrentIndex(processModeIndex)
  232. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  233. self.ui.sb_engine_max_params.setValue(settings.value("Engine/MaxParameters", CARLA_DEFAULT_MAX_PARAMETERS, type=int))
  234. self.ui.ch_engine_uis_always_on_top.setChecked(settings.value("Engine/UIsAlwaysOnTop", CARLA_DEFAULT_UIS_ALWAYS_ON_TOP, type=bool))
  235. self.ui.ch_engine_prefer_ui_bridges.setChecked(settings.value("Engine/PreferUiBridges", CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool))
  236. self.ui.sb_engine_oscgui_timeout.setValue(settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_OSC_UI_TIMEOUT, type=int))
  237. self.ui.ch_engine_disable_checks.setChecked(settings.value("Engine/DisableChecks", CARLA_DEFAULT_DISABLE_CHECKS, type=bool))
  238. self.ui.ch_engine_dssi_chunks.setChecked(settings.value("Engine/UseDssiVstChunks", CARLA_DEFAULT_USE_DSSI_VST_CHUNKS, type=bool))
  239. self.ui.ch_engine_prefer_plugin_bridges.setChecked(settings.value("Engine/PreferPluginBridges", CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool))
  240. self.ui.ch_engine_force_stereo.setChecked(settings.value("Engine/ForceStereo", CARLA_DEFAULT_FORCE_STEREO, type=bool))
  241. # --------------------------------------------
  242. ladspas = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH))
  243. dssis = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH))
  244. lv2s = toList(settings.value("Paths/LV2", Carla.LV2_PATH))
  245. vsts = toList(settings.value("Paths/VST", Carla.VST_PATH))
  246. gigs = toList(settings.value("Paths/GIG", Carla.GIG_PATH))
  247. sf2s = toList(settings.value("Paths/SF2", Carla.SF2_PATH))
  248. sfzs = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH))
  249. ladspas.sort()
  250. dssis.sort()
  251. lv2s.sort()
  252. vsts.sort()
  253. gigs.sort()
  254. sf2s.sort()
  255. sfzs.sort()
  256. for ladspa in ladspas:
  257. self.ui.lw_ladspa.addItem(ladspa)
  258. for dssi in dssis:
  259. self.ui.lw_dssi.addItem(dssi)
  260. for lv2 in lv2s:
  261. self.ui.lw_lv2.addItem(lv2)
  262. for vst in vsts:
  263. self.ui.lw_vst.addItem(vst)
  264. for gig in gigs:
  265. self.ui.lw_gig.addItem(gig)
  266. for sf2 in sf2s:
  267. self.ui.lw_sf2.addItem(sf2)
  268. for sfz in sfzs:
  269. self.ui.lw_sfz.addItem(sfz)
  270. @pyqtSlot()
  271. def slot_saveSettings(self):
  272. settings = QSettings()
  273. # ---------------------------------------
  274. settings.setValue("Main/DefaultProjectFolder", self.ui.le_main_def_folder.text())
  275. settings.setValue("Main/UseProTheme", self.ui.ch_theme_pro.isChecked())
  276. settings.setValue("Main/ProThemeColor", self.ui.cb_theme_color.currentText())
  277. settings.setValue("Main/RefreshInterval", self.ui.sb_gui_refresh.value())
  278. # ---------------------------------------
  279. settings.setValue("Canvas/Theme", self.ui.cb_canvas_theme.currentText())
  280. settings.setValue("Canvas/AutoHideGroups", self.ui.cb_canvas_hide_groups.isChecked())
  281. settings.setValue("Canvas/UseBezierLines", self.ui.cb_canvas_bezier_lines.isChecked())
  282. settings.setValue("Canvas/UseOpenGL", self.ui.cb_canvas_use_opengl.isChecked())
  283. settings.setValue("Canvas/HighQualityAntialiasing", self.ui.cb_canvas_render_hq_aa.isChecked())
  284. # 0, 1, 2 match their enum variants
  285. settings.setValue("Canvas/EyeCandy", self.ui.cb_canvas_eyecandy.checkState())
  286. settings.setValue("Canvas/Antialiasing", self.ui.cb_canvas_render_aa.checkState())
  287. # --------------------------------------------
  288. audioDriver = self.ui.cb_engine_audio_driver.currentText()
  289. if audioDriver:
  290. settings.setValue("Engine/AudioDriver", audioDriver)
  291. if audioDriver == "JACK":
  292. settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_jack.currentIndex())
  293. else:
  294. settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_other.currentIndex()+PROCESS_MODE_NON_JACK_PADDING)
  295. settings.setValue("Engine/MaxParameters", self.ui.sb_engine_max_params.value())
  296. settings.setValue("Engine/UIsAlwaysOnTop", self.ui.ch_engine_uis_always_on_top.isChecked())
  297. settings.setValue("Engine/PreferUiBridges", self.ui.ch_engine_prefer_ui_bridges.isChecked())
  298. settings.setValue("Engine/OscUiTimeout", self.ui.sb_engine_oscgui_timeout.value())
  299. settings.setValue("Engine/DisableChecks", self.ui.ch_engine_disable_checks.isChecked())
  300. settings.setValue("Engine/UseDssiVstChunks", self.ui.ch_engine_dssi_chunks.isChecked())
  301. settings.setValue("Engine/PreferPluginBridges", self.ui.ch_engine_prefer_plugin_bridges.isChecked())
  302. settings.setValue("Engine/ForceStereo", self.ui.ch_engine_force_stereo.isChecked())
  303. # --------------------------------------------
  304. ladspas = []
  305. dssis = []
  306. lv2s = []
  307. vsts = []
  308. gigs = []
  309. sf2s = []
  310. sfzs = []
  311. for i in range(self.ui.lw_ladspa.count()):
  312. ladspas.append(self.ui.lw_ladspa.item(i).text())
  313. for i in range(self.ui.lw_dssi.count()):
  314. dssis.append(self.ui.lw_dssi.item(i).text())
  315. for i in range(self.ui.lw_lv2.count()):
  316. lv2s.append(self.ui.lw_lv2.item(i).text())
  317. for i in range(self.ui.lw_vst.count()):
  318. vsts.append(self.ui.lw_vst.item(i).text())
  319. for i in range(self.ui.lw_gig.count()):
  320. gigs.append(self.ui.lw_gig.item(i).text())
  321. for i in range(self.ui.lw_sf2.count()):
  322. sf2s.append(self.ui.lw_sf2.item(i).text())
  323. for i in range(self.ui.lw_sfz.count()):
  324. sfzs.append(self.ui.lw_sfz.item(i).text())
  325. settings.setValue("Paths/LADSPA", ladspas)
  326. settings.setValue("Paths/DSSI", dssis)
  327. settings.setValue("Paths/LV2", lv2s)
  328. settings.setValue("Paths/VST", vsts)
  329. settings.setValue("Paths/GIG", gigs)
  330. settings.setValue("Paths/SF2", sf2s)
  331. settings.setValue("Paths/SFZ", sfzs)
  332. @pyqtSlot()
  333. def slot_resetSettings(self):
  334. if self.ui.lw_page.currentRow() == TAB_INDEX_MAIN:
  335. self.ui.le_main_def_folder.setText(HOME)
  336. self.ui.ch_theme_pro.setChecked(True)
  337. self.ui.cb_theme_color.setCurrentIndex(0)
  338. self.ui.sb_gui_refresh.setValue(50)
  339. elif self.ui.lw_page.currentRow() == TAB_INDEX_CANVAS:
  340. self.ui.cb_canvas_theme.setCurrentIndex(0)
  341. self.ui.cb_canvas_hide_groups.setChecked(False)
  342. self.ui.cb_canvas_bezier_lines.setChecked(True)
  343. self.ui.cb_canvas_eyecandy.setCheckState(Qt.PartiallyChecked)
  344. self.ui.cb_canvas_use_opengl.setChecked(False)
  345. self.ui.cb_canvas_render_aa.setCheckState(Qt.PartiallyChecked)
  346. self.ui.cb_canvas_render_hq_aa.setChecked(False)
  347. elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_ENGINE:
  348. self.ui.cb_engine_audio_driver.setCurrentIndex(0)
  349. self.ui.sb_engine_max_params.setValue(CARLA_DEFAULT_MAX_PARAMETERS)
  350. self.ui.ch_engine_uis_always_on_top.setChecked(CARLA_DEFAULT_UIS_ALWAYS_ON_TOP)
  351. self.ui.ch_engine_prefer_ui_bridges.setChecked(CARLA_DEFAULT_PREFER_UI_BRIDGES)
  352. self.ui.sb_engine_oscgui_timeout.setValue(CARLA_DEFAULT_OSC_UI_TIMEOUT)
  353. self.ui.ch_engine_disable_checks.setChecked(CARLA_DEFAULT_DISABLE_CHECKS)
  354. self.ui.ch_engine_dssi_chunks.setChecked(CARLA_DEFAULT_USE_DSSI_VST_CHUNKS)
  355. self.ui.ch_engine_prefer_plugin_bridges.setChecked(CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES)
  356. self.ui.ch_engine_force_stereo.setChecked(CARLA_DEFAULT_FORCE_STEREO)
  357. if self.ui.cb_engine_audio_driver.currentText() == "JACK":
  358. self.ui.cb_engine_process_mode_jack.setCurrentIndex(PROCESS_MODE_MULTIPLE_CLIENTS)
  359. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  360. else:
  361. self.ui.cb_engine_process_mode_other.setCurrentIndex(PROCESS_MODE_CONTINUOUS_RACK-PROCESS_MODE_NON_JACK_PADDING)
  362. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  363. elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_PATHS:
  364. if self.ui.tw_paths.currentIndex() == 0:
  365. paths = DEFAULT_LADSPA_PATH.split(splitter)
  366. paths.sort()
  367. self.ui.lw_ladspa.clear()
  368. for ladspa in Carla.paths:
  369. self.ui.lw_ladspa.addItem(ladspa)
  370. elif self.ui.tw_paths.currentIndex() == 1:
  371. paths = DEFAULT_DSSI_PATH.split(splitter)
  372. paths.sort()
  373. self.ui.lw_dssi.clear()
  374. for dssi in paths:
  375. self.ui.lw_dssi.addItem(dssi)
  376. elif self.ui.tw_paths.currentIndex() == 2:
  377. paths = DEFAULT_LV2_PATH.split(splitter)
  378. paths.sort()
  379. self.ui.lw_lv2.clear()
  380. for lv2 in paths:
  381. self.ui.lw_lv2.addItem(lv2)
  382. elif self.ui.tw_paths.currentIndex() == 3:
  383. paths = DEFAULT_VST_PATH.split(splitter)
  384. paths.sort()
  385. self.ui.lw_vst.clear()
  386. for vst in paths:
  387. self.ui.lw_vst.addItem(vst)
  388. elif self.ui.tw_paths.currentIndex() == 4:
  389. paths = DEFAULT_GIG_PATH.split(splitter)
  390. paths.sort()
  391. self.ui.lw_gig.clear()
  392. for gig in paths:
  393. self.ui.lw_gig.addItem(gig)
  394. elif self.ui.tw_paths.currentIndex() == 5:
  395. paths = DEFAULT_SF2_PATH.split(splitter)
  396. paths.sort()
  397. self.ui.lw_sf2.clear()
  398. for sf2 in paths:
  399. self.ui.lw_sf2.addItem(sf2)
  400. elif self.ui.tw_paths.currentIndex() == 6:
  401. paths = DEFAULT_SFZ_PATH.split(splitter)
  402. paths.sort()
  403. self.ui.lw_sfz.clear()
  404. for sfz in paths:
  405. self.ui.lw_sfz.addItem(sfz)
  406. @pyqtSlot()
  407. def slot_getAndSetProjectPath(self):
  408. getAndSetPath(self, self.ui.le_main_def_folder.text(), self.ui.le_main_def_folder)
  409. @pyqtSlot()
  410. def slot_engineAudioDriverChanged(self):
  411. if self.ui.cb_engine_audio_driver.currentText() == "JACK":
  412. self.ui.sw_engine_process_mode.setCurrentIndex(0)
  413. else:
  414. self.ui.sw_engine_process_mode.setCurrentIndex(1)
  415. @pyqtSlot()
  416. def slot_showAudioDriverSettings(self):
  417. driverIndex = self.ui.cb_engine_audio_driver.currentIndex()
  418. driverName = self.ui.cb_engine_audio_driver.currentText()
  419. DriverSettingsW(self, driverIndex, driverName).exec_()
  420. @pyqtSlot()
  421. def slot_addPluginPath(self):
  422. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), "", QFileDialog.ShowDirsOnly)
  423. if newPath:
  424. if self.ui.tw_paths.currentIndex() == 0:
  425. self.ui.lw_ladspa.addItem(newPath)
  426. elif self.ui.tw_paths.currentIndex() == 1:
  427. self.ui.lw_dssi.addItem(newPath)
  428. elif self.ui.tw_paths.currentIndex() == 2:
  429. self.ui.lw_lv2.addItem(newPath)
  430. elif self.ui.tw_paths.currentIndex() == 3:
  431. self.ui.lw_vst.addItem(newPath)
  432. elif self.ui.tw_paths.currentIndex() == 4:
  433. self.ui.lw_gig.addItem(newPath)
  434. elif self.ui.tw_paths.currentIndex() == 5:
  435. self.ui.lw_sf2.addItem(newPath)
  436. elif self.ui.tw_paths.currentIndex() == 6:
  437. self.ui.lw_sfz.addItem(newPath)
  438. @pyqtSlot()
  439. def slot_removePluginPath(self):
  440. if self.ui.tw_paths.currentIndex() == 0:
  441. self.ui.lw_ladspa.takeItem(self.ui.lw_ladspa.currentRow())
  442. elif self.ui.tw_paths.currentIndex() == 1:
  443. self.ui.lw_dssi.takeItem(self.ui.lw_dssi.currentRow())
  444. elif self.ui.tw_paths.currentIndex() == 2:
  445. self.ui.lw_lv2.takeItem(self.ui.lw_lv2.currentRow())
  446. elif self.ui.tw_paths.currentIndex() == 3:
  447. self.ui.lw_vst.takeItem(self.ui.lw_vst.currentRow())
  448. elif self.ui.tw_paths.currentIndex() == 4:
  449. self.ui.lw_gig.takeItem(self.ui.lw_gig.currentRow())
  450. elif self.ui.tw_paths.currentIndex() == 5:
  451. self.ui.lw_sf2.takeItem(self.ui.lw_sf2.currentRow())
  452. elif self.ui.tw_paths.currentIndex() == 6:
  453. self.ui.lw_sfz.takeItem(self.ui.lw_sfz.currentRow())
  454. @pyqtSlot()
  455. def slot_changePluginPath(self):
  456. if self.ui.tw_paths.currentIndex() == 0:
  457. currentPath = self.ui.lw_ladspa.currentItem().text()
  458. elif self.ui.tw_paths.currentIndex() == 1:
  459. currentPath = self.ui.lw_dssi.currentItem().text()
  460. elif self.ui.tw_paths.currentIndex() == 2:
  461. currentPath = self.ui.lw_lv2.currentItem().text()
  462. elif self.ui.tw_paths.currentIndex() == 3:
  463. currentPath = self.ui.lw_vst.currentItem().text()
  464. elif self.ui.tw_paths.currentIndex() == 4:
  465. currentPath = self.ui.lw_gig.currentItem().text()
  466. elif self.ui.tw_paths.currentIndex() == 5:
  467. currentPath = self.ui.lw_sf2.currentItem().text()
  468. elif self.ui.tw_paths.currentIndex() == 6:
  469. currentPath = self.ui.lw_sfz.currentItem().text()
  470. else:
  471. currentPath = ""
  472. newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), currentPath, QFileDialog.ShowDirsOnly)
  473. if newPath:
  474. if self.ui.tw_paths.currentIndex() == 0:
  475. self.ui.lw_ladspa.currentItem().setText(newPath)
  476. elif self.ui.tw_paths.currentIndex() == 1:
  477. self.ui.lw_dssi.currentItem().setText(newPath)
  478. elif self.ui.tw_paths.currentIndex() == 2:
  479. self.ui.lw_lv2.currentItem().setText(newPath)
  480. elif self.ui.tw_paths.currentIndex() == 3:
  481. self.ui.lw_vst.currentItem().setText(newPath)
  482. elif self.ui.tw_paths.currentIndex() == 4:
  483. self.ui.lw_gig.currentItem().setText(newPath)
  484. elif self.ui.tw_paths.currentIndex() == 5:
  485. self.ui.lw_sf2.currentItem().setText(newPath)
  486. elif self.ui.tw_paths.currentIndex() == 6:
  487. self.ui.lw_sfz.currentItem().setText(newPath)
  488. @pyqtSlot(int)
  489. def slot_pluginPathTabChanged(self, index):
  490. if index == 0:
  491. row = self.ui.lw_ladspa.currentRow()
  492. elif index == 1:
  493. row = self.ui.lw_dssi.currentRow()
  494. elif index == 2:
  495. row = self.ui.lw_lv2.currentRow()
  496. elif index == 3:
  497. row = self.ui.lw_vst.currentRow()
  498. elif index == 4:
  499. row = self.ui.lw_gig.currentRow()
  500. elif index == 5:
  501. row = self.ui.lw_sf2.currentRow()
  502. elif index == 6:
  503. row = self.ui.lw_sfz.currentRow()
  504. else:
  505. row = -1
  506. check = bool(row >= 0)
  507. self.ui.b_paths_remove.setEnabled(check)
  508. self.ui.b_paths_change.setEnabled(check)
  509. @pyqtSlot(int)
  510. def slot_pluginPathRowChanged(self, row):
  511. check = bool(row >= 0)
  512. self.ui.b_paths_remove.setEnabled(check)
  513. self.ui.b_paths_change.setEnabled(check)
  514. def done(self, r):
  515. QDialog.done(self, r)
  516. self.close()
  517. # ------------------------------------------------------------------------------------------------------------
  518. # Main Window
  519. class CarlaMainW(QMainWindow):
  520. def __init__(self, parent=None):
  521. QMainWindow.__init__(self, parent)
  522. self.ui = ui_carla.Ui_CarlaMainW()
  523. self.ui.setupUi(self)
  524. if MACOS:
  525. self.setUnifiedTitleAndToolBarOnMac(True)
  526. # -------------------------------------------------------------
  527. # Load Settings
  528. self.loadSettings(True)
  529. self.loadRDFs()
  530. # -------------------------------------------------------------
  531. # Internal stuff
  532. self.fBufferSize = 0
  533. self.fSampleRate = 0.0
  534. self.fEngineStarted = False
  535. self.fFirstEngineInit = True
  536. self.fProjectFilename = None
  537. self.fProjectLoading = False
  538. self.fPluginCount = 0
  539. self.fPluginList = []
  540. self.fIdleTimerFast = 0
  541. self.fIdleTimerSlow = 0
  542. self.fTransportWasPlaying = False
  543. self.fClientName = "Carla"
  544. self.fSessionManagerName = "LADISH" if os.getenv("LADISH_APP_NAME") else ""
  545. # -------------------------------------------------------------
  546. # Set-up GUI stuff
  547. self.fInfoLabel = QLabel(self)
  548. self.fInfoLabel.setText("")
  549. self.fInfoText = ""
  550. self.fDirModel = QFileSystemModel(self)
  551. self.fDirModel.setNameFilters(cString(Carla.host.get_supported_file_types()).split(";"))
  552. self.fDirModel.setRootPath(HOME)
  553. if not WINDOWS:
  554. self.fSyntaxLog = LogSyntaxHighlighter(self.ui.pte_log)
  555. self.fSyntaxLog.setDocument(self.ui.pte_log.document())
  556. #else:
  557. #self.ui.tabMain.setT
  558. self.ui.fileTreeView.setModel(self.fDirModel)
  559. self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME))
  560. self.ui.fileTreeView.setColumnHidden(1, True)
  561. self.ui.fileTreeView.setColumnHidden(2, True)
  562. self.ui.fileTreeView.setColumnHidden(3, True)
  563. self.ui.fileTreeView.setHeaderHidden(True)
  564. self.ui.act_engine_start.setEnabled(False)
  565. self.ui.act_engine_stop.setEnabled(False)
  566. self.ui.act_plugin_remove_all.setEnabled(False)
  567. # FIXME: Qt4 needs this so it properly creates & resizes the canvas
  568. self.ui.tabMain.setCurrentIndex(1)
  569. self.ui.tabMain.setCurrentIndex(0)
  570. # -------------------------------------------------------------
  571. # Set-up Canvas
  572. self.scene = patchcanvas.PatchScene(self, self.ui.graphicsView)
  573. self.ui.graphicsView.setScene(self.scene)
  574. self.ui.graphicsView.setRenderHint(QPainter.Antialiasing, bool(self.fSavedSettings["Canvas/Antialiasing"] == patchcanvas.ANTIALIASING_FULL))
  575. if self.fSavedSettings["Canvas/UseOpenGL"] and hasGL:
  576. self.ui.graphicsView.setViewport(QGLWidget(self.ui.graphicsView))
  577. self.ui.graphicsView.setRenderHint(QPainter.HighQualityAntialiasing, self.fSavedSettings["Canvas/HighQualityAntialiasing"])
  578. pOptions = patchcanvas.options_t()
  579. pOptions.theme_name = self.fSavedSettings["Canvas/Theme"]
  580. pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
  581. pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
  582. pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
  583. pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
  584. pFeatures = patchcanvas.features_t()
  585. pFeatures.group_info = False
  586. pFeatures.group_rename = False
  587. pFeatures.port_info = False
  588. pFeatures.port_rename = False
  589. pFeatures.handle_group_pos = True
  590. patchcanvas.setOptions(pOptions)
  591. patchcanvas.setFeatures(pFeatures)
  592. patchcanvas.init("Carla", self.scene, canvasCallback, False)
  593. patchcanvas.setCanvasSize(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
  594. patchcanvas.setInitialPos(DEFAULT_CANVAS_WIDTH / 2, DEFAULT_CANVAS_HEIGHT / 2)
  595. self.ui.graphicsView.setSceneRect(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
  596. # -------------------------------------------------------------
  597. # Set-up Canvas Preview
  598. self.ui.miniCanvasPreview.setRealParent(self)
  599. self.ui.miniCanvasPreview.setViewTheme(patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color())
  600. self.ui.miniCanvasPreview.init(self.scene, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT)
  601. QTimer.singleShot(100, self, SLOT("slot_miniCanvasInit()"))
  602. # -------------------------------------------------------------
  603. # Connect actions to functions
  604. self.connect(self.ui.act_file_new, SIGNAL("triggered()"), SLOT("slot_fileNew()"))
  605. self.connect(self.ui.act_file_open, SIGNAL("triggered()"), SLOT("slot_fileOpen()"))
  606. self.connect(self.ui.act_file_save, SIGNAL("triggered()"), SLOT("slot_fileSave()"))
  607. self.connect(self.ui.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_fileSaveAs()"))
  608. self.connect(self.ui.act_engine_start, SIGNAL("triggered()"), SLOT("slot_engineStart()"))
  609. self.connect(self.ui.act_engine_stop, SIGNAL("triggered()"), SLOT("slot_engineStop()"))
  610. self.connect(self.ui.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_pluginAdd()"))
  611. #self.connect(self.ui.act_plugin_refresh, SIGNAL("triggered()"), SLOT("slot_pluginRefresh()"))
  612. self.connect(self.ui.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_pluginRemoveAll()"))
  613. self.connect(self.ui.act_plugins_enable, SIGNAL("triggered()"), SLOT("slot_pluginsEnable()"))
  614. self.connect(self.ui.act_plugins_volume100, SIGNAL("triggered()"), SLOT("slot_pluginsVolume100()"))
  615. self.connect(self.ui.act_plugins_wet100, SIGNAL("triggered()"), SLOT("slot_pluginsWet100()"))
  616. self.connect(self.ui.act_plugins_center, SIGNAL("triggered()"), SLOT("slot_pluginsCenter()"))
  617. self.connect(self.ui.act_plugins_disable, SIGNAL("triggered()"), SLOT("slot_pluginsDisable()"))
  618. self.connect(self.ui.act_plugins_mute, SIGNAL("triggered()"), SLOT("slot_pluginsMute()"))
  619. self.connect(self.ui.act_plugins_bypass, SIGNAL("triggered()"), SLOT("slot_pluginsBypass()"))
  620. self.connect(self.ui.act_transport_play, SIGNAL("triggered(bool)"), SLOT("slot_transportPlayPause(bool)"))
  621. self.connect(self.ui.act_transport_stop, SIGNAL("triggered()"), SLOT("slot_transportStop()"))
  622. self.connect(self.ui.act_transport_backwards, SIGNAL("triggered()"), SLOT("slot_transportBackwards()"))
  623. self.connect(self.ui.act_transport_forwards, SIGNAL("triggered()"), SLOT("slot_transportForwards()"))
  624. self.ui.act_canvas_arrange.setEnabled(False) # TODO, later
  625. self.connect(self.ui.act_canvas_arrange, SIGNAL("triggered()"), SLOT("slot_canvasArrange()"))
  626. self.connect(self.ui.act_canvas_refresh, SIGNAL("triggered()"), SLOT("slot_canvasRefresh()"))
  627. self.connect(self.ui.act_canvas_zoom_fit, SIGNAL("triggered()"), SLOT("slot_canvasZoomFit()"))
  628. self.connect(self.ui.act_canvas_zoom_in, SIGNAL("triggered()"), SLOT("slot_canvasZoomIn()"))
  629. self.connect(self.ui.act_canvas_zoom_out, SIGNAL("triggered()"), SLOT("slot_canvasZoomOut()"))
  630. self.connect(self.ui.act_canvas_zoom_100, SIGNAL("triggered()"), SLOT("slot_canvasZoomReset()"))
  631. self.connect(self.ui.act_canvas_print, SIGNAL("triggered()"), SLOT("slot_canvasPrint()"))
  632. self.connect(self.ui.act_canvas_save_image, SIGNAL("triggered()"), SLOT("slot_canvasSaveImage()"))
  633. self.connect(self.ui.act_settings_show_toolbar, SIGNAL("triggered(bool)"), SLOT("slot_toolbarShown()"))
  634. self.connect(self.ui.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()"))
  635. self.connect(self.ui.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarla()"))
  636. self.connect(self.ui.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  637. self.connect(self.ui.splitter, SIGNAL("splitterMoved(int, int)"), SLOT("slot_splitterMoved()"))
  638. self.connect(self.ui.cb_disk, SIGNAL("currentIndexChanged(int)"), SLOT("slot_diskFolderChanged(int)"))
  639. self.connect(self.ui.b_disk_add, SIGNAL("clicked()"), SLOT("slot_diskFolderAdd()"))
  640. self.connect(self.ui.b_disk_remove, SIGNAL("clicked()"), SLOT("slot_diskFolderRemove()"))
  641. self.connect(self.ui.fileTreeView, SIGNAL("doubleClicked(QModelIndex)"), SLOT("slot_fileTreeDoubleClicked(QModelIndex)"))
  642. self.connect(self.ui.miniCanvasPreview, SIGNAL("miniCanvasMoved(double, double)"), SLOT("slot_miniCanvasMoved(double, double)"))
  643. self.connect(self.ui.graphicsView.horizontalScrollBar(), SIGNAL("valueChanged(int)"), SLOT("slot_horizontalScrollBarChanged(int)"))
  644. self.connect(self.ui.graphicsView.verticalScrollBar(), SIGNAL("valueChanged(int)"), SLOT("slot_verticalScrollBarChanged(int)"))
  645. self.connect(self.scene, SIGNAL("sceneGroupMoved(int, int, QPointF)"), SLOT("slot_canvasItemMoved(int, int, QPointF)"))
  646. self.connect(self.scene, SIGNAL("scaleChanged(double)"), SLOT("slot_canvasScaleChanged(double)"))
  647. self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_handleSIGUSR1()"))
  648. self.connect(self, SIGNAL("SIGTERM()"), SLOT("slot_handleSIGTERM()"))
  649. self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)"))
  650. self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)"))
  651. self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)"))
  652. self.connect(self, SIGNAL("PluginRenamedCallback(int, QString)"), SLOT("slot_handlePluginRenamedCallback(int, QString)"))
  653. self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)"))
  654. self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)"))
  655. self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)"))
  656. self.connect(self, SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiCcChangedCallback(int, int, int)"))
  657. self.connect(self, SIGNAL("ProgramChangedCallback(int, int)"), SLOT("slot_handleProgramChangedCallback(int, int)"))
  658. self.connect(self, SIGNAL("MidiProgramChangedCallback(int, int)"), SLOT("slot_handleMidiProgramChangedCallback(int, int)"))
  659. self.connect(self, SIGNAL("NoteOnCallback(int, int, int, int)"), SLOT("slot_handleNoteOnCallback(int, int, int, int)"))
  660. self.connect(self, SIGNAL("NoteOffCallback(int, int, int)"), SLOT("slot_handleNoteOffCallback(int, int, int)"))
  661. self.connect(self, SIGNAL("ShowGuiCallback(int, int)"), SLOT("slot_handleShowGuiCallback(int, int)"))
  662. self.connect(self, SIGNAL("UpdateCallback(int)"), SLOT("slot_handleUpdateCallback(int)"))
  663. self.connect(self, SIGNAL("ReloadInfoCallback(int)"), SLOT("slot_handleReloadInfoCallback(int)"))
  664. self.connect(self, SIGNAL("ReloadParametersCallback(int)"), SLOT("slot_handleReloadParametersCallback(int)"))
  665. self.connect(self, SIGNAL("ReloadProgramsCallback(int)"), SLOT("slot_handleReloadProgramsCallback(int)"))
  666. self.connect(self, SIGNAL("ReloadAllCallback(int)"), SLOT("slot_handleReloadAllCallback(int)"))
  667. self.connect(self, SIGNAL("PatchbayClientAddedCallback(int, QString)"), SLOT("slot_handlePatchbayClientAddedCallback(int, QString)"))
  668. self.connect(self, SIGNAL("PatchbayClientRemovedCallback(int)"), SLOT("slot_handlePatchbayClientRemovedCallback(int)"))
  669. self.connect(self, SIGNAL("PatchbayClientRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayClientRenamedCallback(int, QString)"))
  670. self.connect(self, SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), SLOT("slot_handlePatchbayPortAddedCallback(int, int, int, QString)"))
  671. self.connect(self, SIGNAL("PatchbayPortRemovedCallback(int)"), SLOT("slot_handlePatchbayPortRemovedCallback(int)"))
  672. self.connect(self, SIGNAL("PatchbayPortRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayPortRenamedCallback(int, QString)"))
  673. self.connect(self, SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), SLOT("slot_handlePatchbayConnectionAddedCallback(int, int, int)"))
  674. self.connect(self, SIGNAL("PatchbayConnectionRemovedCallback(int)"), SLOT("slot_handlePatchbayConnectionRemovedCallback(int)"))
  675. self.connect(self, SIGNAL("BufferSizeChangedCallback(int)"), SLOT("slot_handleBufferSizeChangedCallback(int)"))
  676. self.connect(self, SIGNAL("SampleRateChangedCallback(double)"), SLOT("slot_handleSampleRateChangedCallback(double)"))
  677. self.connect(self, SIGNAL("NSM_AnnounceCallback(QString)"), SLOT("slot_handleNSM_AnnounceCallback(QString)"))
  678. self.connect(self, SIGNAL("NSM_OpenCallback(QString)"), SLOT("slot_handleNSM_OpenCallback(QString)"))
  679. self.connect(self, SIGNAL("NSM_SaveCallback()"), SLOT("slot_handleNSM_SaveCallback()"))
  680. self.connect(self, SIGNAL("ErrorCallback(QString)"), SLOT("slot_handleErrorCallback(QString)"))
  681. self.connect(self, SIGNAL("QuitCallback()"), SLOT("slot_handleQuitCallback()"))
  682. self.setProperWindowTitle()
  683. NSM_URL = os.getenv("NSM_URL")
  684. if NSM_URL:
  685. Carla.host.nsm_announce(NSM_URL, appName, os.getpid())
  686. else:
  687. QTimer.singleShot(0, self, SLOT("slot_engineStart()"))
  688. @pyqtSlot()
  689. def slot_pluginsEnable(self):
  690. if not self.fEngineStarted:
  691. return
  692. for i in range(self.fPluginCount):
  693. pwidget = self.fPluginList[i]
  694. if pwidget is None:
  695. break
  696. pwidget.setActive(True, True, True)
  697. @pyqtSlot()
  698. def slot_pluginsVolume100(self):
  699. if not self.fEngineStarted:
  700. return
  701. for i in range(self.fPluginCount):
  702. pwidget = self.fPluginList[i]
  703. if pwidget is None:
  704. break
  705. if pwidget.fPluginInfo["hints"] & PLUGIN_CAN_VOLUME:
  706. pwidget.ui.edit_dialog.setParameterValue(PARAMETER_VOLUME, 1.0)
  707. Carla.host.set_volume(i, 1.0)
  708. @pyqtSlot()
  709. def slot_pluginsWet100(self):
  710. if not self.fEngineStarted:
  711. return
  712. for i in range(self.fPluginCount):
  713. pwidget = self.fPluginList[i]
  714. if pwidget is None:
  715. break
  716. if pwidget.fPluginInfo["hints"] & PLUGIN_CAN_DRYWET:
  717. pwidget.ui.edit_dialog.setParameterValue(PARAMETER_DRYWET, 1.0)
  718. Carla.host.set_drywet(i, 1.0)
  719. @pyqtSlot()
  720. def slot_pluginsCenter(self):
  721. if not self.fEngineStarted:
  722. return
  723. for i in range(self.fPluginCount):
  724. pwidget = self.fPluginList[i]
  725. if pwidget is None:
  726. break
  727. if pwidget.fPluginInfo["hints"] & PLUGIN_CAN_BALANCE:
  728. pwidget.ui.edit_dialog.setParameterValue(PARAMETER_BALANCE_LEFT, -1.0)
  729. pwidget.ui.edit_dialog.setParameterValue(PARAMETER_BALANCE_RIGHT, 1.0)
  730. Carla.host.set_balance_left(i, -1.0)
  731. Carla.host.set_balance_right(i, 1.0)
  732. @pyqtSlot()
  733. def slot_pluginsDisable(self):
  734. if not self.fEngineStarted:
  735. return
  736. for i in range(self.fPluginCount):
  737. pwidget = self.fPluginList[i]
  738. if pwidget is None:
  739. break
  740. pwidget.setActive(False, True, True)
  741. @pyqtSlot()
  742. def slot_pluginsMute(self):
  743. if not self.fEngineStarted:
  744. return
  745. for i in range(self.fPluginCount):
  746. pwidget = self.fPluginList[i]
  747. if pwidget is None:
  748. break
  749. if pwidget.fPluginInfo["hints"] & PLUGIN_CAN_VOLUME:
  750. pwidget.ui.edit_dialog.setParameterValue(PARAMETER_VOLUME, 0.0)
  751. Carla.host.set_volume(i, 0.0)
  752. @pyqtSlot()
  753. def slot_pluginsBypass(self):
  754. if not self.fEngineStarted:
  755. return
  756. for i in range(self.fPluginCount):
  757. pwidget = self.fPluginList[i]
  758. if pwidget is None:
  759. break
  760. if pwidget.fPluginInfo["hints"] & PLUGIN_CAN_DRYWET:
  761. pwidget.ui.edit_dialog.setParameterValue(PARAMETER_DRYWET, 0.0)
  762. Carla.host.set_drywet(i, 0.0)
  763. @pyqtSlot(int)
  764. def slot_diskFolderChanged(self, index):
  765. if index < 0:
  766. return
  767. elif index == 0:
  768. filename = HOME
  769. self.ui.b_disk_remove.setEnabled(False)
  770. else:
  771. filename = self.ui.cb_disk.itemData(index)
  772. self.ui.b_disk_remove.setEnabled(True)
  773. self.fDirModel.setRootPath(filename)
  774. self.ui.fileTreeView.setRootIndex(self.fDirModel.index(filename))
  775. @pyqtSlot()
  776. def slot_diskFolderAdd(self):
  777. newPath = QFileDialog.getExistingDirectory(self, self.tr("New Folder"), "", QFileDialog.ShowDirsOnly)
  778. if newPath:
  779. if newPath[-1] == os.sep:
  780. newPath = newPath[:-1]
  781. self.ui.cb_disk.addItem(os.path.basename(newPath), newPath)
  782. self.ui.cb_disk.setCurrentIndex(self.ui.cb_disk.count()-1)
  783. self.ui.b_disk_remove.setEnabled(True)
  784. @pyqtSlot()
  785. def slot_diskFolderRemove(self):
  786. index = self.ui.cb_disk.currentIndex()
  787. if index <= 0:
  788. return
  789. self.ui.cb_disk.removeItem(index)
  790. if self.ui.cb_disk.currentIndex() == 0:
  791. self.ui.b_disk_remove.setEnabled(False)
  792. @pyqtSlot(str)
  793. def slot_handleNSM_AnnounceCallback(self, smName):
  794. self.fSessionManagerName = smName
  795. self.ui.act_file_new.setEnabled(False)
  796. self.ui.act_file_open.setEnabled(False)
  797. self.ui.act_file_save_as.setEnabled(False)
  798. self.ui.act_engine_start.setEnabled(True)
  799. self.ui.act_engine_stop.setEnabled(False)
  800. @pyqtSlot(str)
  801. def slot_handleNSM_OpenCallback(self, data):
  802. projectPath, clientId = data.rsplit(":", 1)
  803. self.fClientName = clientId
  804. # restart engine
  805. if self.fEngineStarted:
  806. self.stopEngine()
  807. self.slot_engineStart()
  808. if self.fEngineStarted:
  809. self.loadProject(projectPath)
  810. Carla.host.nsm_reply_open()
  811. @pyqtSlot()
  812. def slot_handleNSM_SaveCallback(self):
  813. self.saveProject(self.fProjectFilename)
  814. Carla.host.nsm_reply_save()
  815. @pyqtSlot()
  816. def slot_toolbarShown(self):
  817. self.updateInfoLabelPos()
  818. @pyqtSlot()
  819. def slot_splitterMoved(self):
  820. self.updateInfoLabelSize()
  821. @pyqtSlot()
  822. def slot_canvasArrange(self):
  823. patchcanvas.arrange()
  824. @pyqtSlot()
  825. def slot_canvasRefresh(self):
  826. patchcanvas.clear()
  827. if Carla.host.is_engine_running():
  828. Carla.host.patchbay_refresh()
  829. QTimer.singleShot(1000 if self.fSavedSettings['Canvas/EyeCandy'] else 0, self.ui.miniCanvasPreview, SLOT("update()"))
  830. @pyqtSlot()
  831. def slot_canvasZoomFit(self):
  832. self.scene.zoom_fit()
  833. @pyqtSlot()
  834. def slot_canvasZoomIn(self):
  835. self.scene.zoom_in()
  836. @pyqtSlot()
  837. def slot_canvasZoomOut(self):
  838. self.scene.zoom_out()
  839. @pyqtSlot()
  840. def slot_canvasZoomReset(self):
  841. self.scene.zoom_reset()
  842. @pyqtSlot()
  843. def slot_canvasPrint(self):
  844. self.scene.clearSelection()
  845. self.fExportPrinter = QPrinter()
  846. dialog = QPrintDialog(self.fExportPrinter, self)
  847. if dialog.exec_():
  848. painter = QPainter(self.fExportPrinter)
  849. painter.setRenderHint(QPainter.Antialiasing)
  850. painter.setRenderHint(QPainter.TextAntialiasing)
  851. self.scene.render(painter)
  852. @pyqtSlot()
  853. def slot_canvasSaveImage(self):
  854. newPath = QFileDialog.getSaveFileName(self, self.tr("Save Image"), filter=self.tr("PNG Image (*.png);;JPEG Image (*.jpg)"))
  855. if newPath:
  856. self.scene.clearSelection()
  857. # FIXME - must be a better way...
  858. if newPath.endswith((".jpg", ".jpG", ".jPG", ".JPG", ".JPg", ".Jpg")):
  859. imgFormat = "JPG"
  860. elif newPath.endswith((".png", ".pnG", ".pNG", ".PNG", ".PNg", ".Png")):
  861. imgFormat = "PNG"
  862. else:
  863. # File-dialog may not auto-add the extension
  864. imgFormat = "PNG"
  865. newPath += ".png"
  866. self.fExportImage = QImage(self.scene.sceneRect().width(), self.scene.sceneRect().height(), QImage.Format_RGB32)
  867. painter = QPainter(self.fExportImage)
  868. painter.setRenderHint(QPainter.Antialiasing) # TODO - set true, cleanup this
  869. painter.setRenderHint(QPainter.TextAntialiasing)
  870. self.scene.render(painter)
  871. self.fExportImage.save(newPath, imgFormat, 100)
  872. @pyqtSlot(QModelIndex)
  873. def slot_fileTreeDoubleClicked(self, modelIndex):
  874. filename = self.fDirModel.filePath(modelIndex)
  875. if not Carla.host.load_filename(filename):
  876. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"),
  877. self.tr("Failed to load file"),
  878. cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  879. @pyqtSlot(float)
  880. def slot_canvasScaleChanged(self, scale):
  881. self.ui.miniCanvasPreview.setViewScale(scale)
  882. @pyqtSlot(int, int, QPointF)
  883. def slot_canvasItemMoved(self, group_id, split_mode, pos):
  884. self.ui.miniCanvasPreview.update()
  885. @pyqtSlot(int)
  886. def slot_horizontalScrollBarChanged(self, value):
  887. maximum = self.ui.graphicsView.horizontalScrollBar().maximum()
  888. if maximum == 0:
  889. xp = 0
  890. else:
  891. xp = float(value) / maximum
  892. self.ui.miniCanvasPreview.setViewPosX(xp)
  893. @pyqtSlot(int)
  894. def slot_verticalScrollBarChanged(self, value):
  895. maximum = self.ui.graphicsView.verticalScrollBar().maximum()
  896. if maximum == 0:
  897. yp = 0
  898. else:
  899. yp = float(value) / maximum
  900. self.ui.miniCanvasPreview.setViewPosY(yp)
  901. @pyqtSlot()
  902. def slot_miniCanvasInit(self):
  903. settings = QSettings()
  904. self.ui.graphicsView.horizontalScrollBar().setValue(settings.value("HorizontalScrollBarValue", DEFAULT_CANVAS_WIDTH / 3, type=int))
  905. self.ui.graphicsView.verticalScrollBar().setValue(settings.value("VerticalScrollBarValue", DEFAULT_CANVAS_HEIGHT * 3 / 8, type=int))
  906. tabBar = self.ui.tabMain.tabBar()
  907. x = tabBar.width()+20
  908. y = tabBar.mapFromParent(self.ui.centralwidget.pos()).y()+tabBar.height()/4
  909. self.fInfoLabel.move(x, y)
  910. self.fInfoLabel.resize(self.ui.tabMain.width()-x, tabBar.height())
  911. @pyqtSlot(float, float)
  912. def slot_miniCanvasMoved(self, xp, yp):
  913. self.ui.graphicsView.horizontalScrollBar().setValue(xp * DEFAULT_CANVAS_WIDTH)
  914. self.ui.graphicsView.verticalScrollBar().setValue(yp * DEFAULT_CANVAS_HEIGHT)
  915. @pyqtSlot()
  916. def slot_miniCanvasCheckAll(self):
  917. self.slot_miniCanvasCheckSize()
  918. self.slot_horizontalScrollBarChanged(self.ui.graphicsView.horizontalScrollBar().value())
  919. self.slot_verticalScrollBarChanged(self.ui.graphicsView.verticalScrollBar().value())
  920. @pyqtSlot()
  921. def slot_miniCanvasCheckSize(self):
  922. self.ui.miniCanvasPreview.setViewSize(float(self.ui.graphicsView.width()) / DEFAULT_CANVAS_WIDTH, float(self.ui.graphicsView.height()) / DEFAULT_CANVAS_HEIGHT)
  923. def startEngine(self):
  924. # ---------------------------------------------
  925. # Engine settings
  926. settings = QSettings()
  927. if LINUX:
  928. defaultMode = PROCESS_MODE_MULTIPLE_CLIENTS
  929. else:
  930. defaultMode = PROCESS_MODE_CONTINUOUS_RACK
  931. audioDriver = settings.value("Engine/AudioDriver", CARLA_DEFAULT_AUDIO_DRIVER, type=str)
  932. transportMode = settings.value("Engine/TransportMode", TRANSPORT_MODE_JACK, type=int)
  933. forceStereo = settings.value("Engine/ForceStereo", False, type=bool)
  934. preferPluginBridges = settings.value("Engine/PreferPluginBridges", False, type=bool)
  935. preferUiBridges = settings.value("Engine/PreferUiBridges", True, type=bool)
  936. useDssiVstChunks = settings.value("Engine/UseDssiVstChunks", False, type=bool)
  937. oscUiTimeout = settings.value("Engine/OscUiTimeout", 40, type=int)
  938. Carla.processMode = settings.value("Engine/ProcessMode", defaultMode, type=int)
  939. Carla.maxParameters = settings.value("Engine/MaxParameters", MAX_DEFAULT_PARAMETERS, type=int)
  940. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  941. forceStereo = True
  942. elif Carla.processMode == PROCESS_MODE_MULTIPLE_CLIENTS and os.getenv("LADISH_APP_NAME"):
  943. print("LADISH detected but using multiple clients (not allowed), forcing single client now")
  944. Carla.processMode = PROCESS_MODE_SINGLE_CLIENT
  945. Carla.host.set_engine_option(OPTION_PROCESS_MODE, Carla.processMode, "")
  946. Carla.host.set_engine_option(OPTION_MAX_PARAMETERS, Carla.maxParameters, "")
  947. Carla.host.set_engine_option(OPTION_FORCE_STEREO, forceStereo, "")
  948. Carla.host.set_engine_option(OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "")
  949. Carla.host.set_engine_option(OPTION_PREFER_UI_BRIDGES, preferUiBridges, "")
  950. Carla.host.set_engine_option(OPTION_USE_DSSI_VST_CHUNKS, useDssiVstChunks, "")
  951. Carla.host.set_engine_option(OPTION_OSC_UI_TIMEOUT, oscUiTimeout, "")
  952. if audioDriver == "JACK":
  953. jackAutoConnect = settings.value("Engine/JackAutoConnect", False, type=bool)
  954. jackTimeMaster = settings.value("Engine/JackTimeMaster", False, type=bool)
  955. Carla.host.set_engine_option(OPTION_JACK_AUTOCONNECT, jackAutoConnect, "")
  956. Carla.host.set_engine_option(OPTION_JACK_TIMEMASTER, jackTimeMaster, "")
  957. else:
  958. rtaudioBufferSize = settings.value("Engine/RtAudioBufferSize", CARLA_DEFAULT_RTAUDIO_BUFFER_SIZE, type=int)
  959. rtaudioSampleRate = settings.value("Engine/RtAudioSampleRate", CARLA_DEFAULT_RTAUDIO_SAMPLE_RATE, type=int)
  960. rtaudioDevice = settings.value("Engine/RtAudioDevice", "", type=str)
  961. Carla.host.set_engine_option(OPTION_RTAUDIO_BUFFER_SIZE, rtaudioBufferSize, "")
  962. Carla.host.set_engine_option(OPTION_RTAUDIO_SAMPLE_RATE, rtaudioSampleRate, "")
  963. Carla.host.set_engine_option(OPTION_RTAUDIO_DEVICE, 0, rtaudioDevice)
  964. # ---------------------------------------------
  965. # Start
  966. if not Carla.host.engine_init(audioDriver, self.fClientName):
  967. if self.fFirstEngineInit:
  968. self.fFirstEngineInit = False
  969. return
  970. audioError = cString(Carla.host.get_last_error())
  971. if audioError:
  972. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver, audioError)))
  973. else:
  974. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver))
  975. return
  976. self.fBufferSize = Carla.host.get_buffer_size()
  977. self.fSampleRate = Carla.host.get_sample_rate()
  978. self.fEngineStarted = True
  979. self.fFirstEngineInit = False
  980. self.fPluginCount = 0
  981. self.fPluginList = []
  982. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  983. maxCount = MAX_RACK_PLUGINS
  984. elif Carla.processMode == PROCESS_MODE_PATCHBAY:
  985. maxCount = MAX_PATCHBAY_PLUGINS
  986. else:
  987. maxCount = MAX_DEFAULT_PLUGINS
  988. if transportMode == TRANSPORT_MODE_JACK and audioDriver != "JACK":
  989. transportMode = TRANSPORT_MODE_INTERNAL
  990. Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, transportMode, "")
  991. # Peaks and TimeInfo
  992. self.fIdleTimerFast = self.startTimer(self.fSavedSettings["Main/RefreshInterval"])
  993. # LEDs and edit dialog parameters
  994. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  995. def stopEngine(self):
  996. if self.fPluginCount > 0:
  997. 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"
  998. "Do you want to do this now?"),
  999. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  1000. if ask != QMessageBox.Yes:
  1001. return
  1002. self.removeAllPlugins()
  1003. self.fEngineStarted = False
  1004. if Carla.host.is_engine_running() and not Carla.host.engine_close():
  1005. print(cString(Carla.host.get_last_error()))
  1006. self.fBufferSize = 0
  1007. self.fSampleRate = 0.0
  1008. self.fPluginCount = 0
  1009. self.fPluginList = []
  1010. self.killTimer(self.fIdleTimerFast)
  1011. self.killTimer(self.fIdleTimerSlow)
  1012. patchcanvas.clear()
  1013. def setProperWindowTitle(self):
  1014. title = "%s" % os.getenv("LADISH_APP_NAME", "Carla")
  1015. if self.fProjectFilename:
  1016. title += " - %s" % os.path.basename(self.fProjectFilename)
  1017. if self.fSessionManagerName:
  1018. title += " (%s)" % self.fSessionManagerName
  1019. self.setWindowTitle(title)
  1020. def loadProject(self, filename):
  1021. self.fProjectFilename = filename
  1022. self.setProperWindowTitle()
  1023. self.fProjectLoading = True
  1024. Carla.host.load_project(filename)
  1025. self.fProjectLoading = False
  1026. def loadProjectLater(self, filename):
  1027. self.fProjectFilename = filename
  1028. self.setProperWindowTitle()
  1029. QTimer.singleShot(0, self, SLOT("slot_loadProjectLater()"))
  1030. def saveProject(self, filename):
  1031. self.fProjectFilename = filename
  1032. self.setProperWindowTitle()
  1033. Carla.host.save_project(filename)
  1034. def addPlugin(self, btype, ptype, filename, name, label, extraStuff):
  1035. if not self.fEngineStarted:
  1036. QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
  1037. return False
  1038. if not Carla.host.add_plugin(btype, ptype, filename, name, label, extraStuff):
  1039. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  1040. return False
  1041. return True
  1042. def removeAllPlugins(self):
  1043. while (self.ui.w_plugins.layout().takeAt(0)):
  1044. pass
  1045. self.ui.act_plugin_remove_all.setEnabled(False)
  1046. for i in range(self.fPluginCount):
  1047. pwidget = self.fPluginList[i]
  1048. if pwidget is None:
  1049. break
  1050. pwidget.ui.edit_dialog.close()
  1051. pwidget.close()
  1052. pwidget.deleteLater()
  1053. del pwidget
  1054. self.fPluginCount = 0
  1055. self.fPluginList = []
  1056. Carla.host.remove_all_plugins()
  1057. @pyqtSlot()
  1058. def slot_fileNew(self):
  1059. self.removeAllPlugins()
  1060. self.fProjectFilename = None
  1061. self.fProjectLoading = False
  1062. self.setProperWindowTitle()
  1063. @pyqtSlot()
  1064. def slot_fileOpen(self):
  1065. fileFilter = self.tr("Carla Project File (*.carxp)")
  1066. filenameTry = QFileDialog.getOpenFileName(self, self.tr("Open Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)
  1067. if filenameTry:
  1068. # FIXME - show dialog to user
  1069. self.removeAllPlugins()
  1070. self.loadProject(filenameTry)
  1071. @pyqtSlot()
  1072. def slot_fileSave(self, saveAs=False):
  1073. if self.fProjectFilename and not saveAs:
  1074. return self.saveProject(self.fProjectFilename)
  1075. fileFilter = self.tr("Carla Project File (*.carxp)")
  1076. filenameTry = QFileDialog.getSaveFileName(self, self.tr("Save Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)
  1077. if filenameTry:
  1078. if not filenameTry.endswith(".carxp"):
  1079. filenameTry += ".carxp"
  1080. self.saveProject(filenameTry)
  1081. @pyqtSlot()
  1082. def slot_fileSaveAs(self):
  1083. self.slot_fileSave(True)
  1084. @pyqtSlot()
  1085. def slot_loadProjectLater(self):
  1086. self.fProjectLoading = True
  1087. Carla.host.load_project(self.fProjectFilename)
  1088. self.fProjectLoading = False
  1089. @pyqtSlot()
  1090. def slot_engineStart(self):
  1091. self.startEngine()
  1092. check = Carla.host.is_engine_running()
  1093. self.ui.act_engine_start.setEnabled(not check)
  1094. self.ui.act_engine_stop.setEnabled(check)
  1095. if self.fSessionManagerName != "Non Session Manager":
  1096. self.ui.act_file_open.setEnabled(check)
  1097. if check:
  1098. self.fInfoText = "Engine running | SampleRate: %g | BufferSize: %i" % (self.fSampleRate, self.fBufferSize)
  1099. self.refreshTransport(True)
  1100. self.menuTransport(check)
  1101. @pyqtSlot()
  1102. def slot_engineStop(self):
  1103. self.stopEngine()
  1104. check = Carla.host.is_engine_running()
  1105. self.ui.act_engine_start.setEnabled(not check)
  1106. self.ui.act_engine_stop.setEnabled(check)
  1107. if self.fSessionManagerName != "Non Session Manager":
  1108. self.ui.act_file_open.setEnabled(check)
  1109. if not check:
  1110. self.fInfoText = ""
  1111. self.fInfoLabel.setText("Engine stopped")
  1112. self.menuTransport(check)
  1113. @pyqtSlot()
  1114. def slot_pluginAdd(self):
  1115. dialog = PluginDatabaseW(self)
  1116. if dialog.exec_():
  1117. btype = dialog.fRetPlugin['build']
  1118. ptype = dialog.fRetPlugin['type']
  1119. filename = dialog.fRetPlugin['binary']
  1120. label = dialog.fRetPlugin['label']
  1121. extraStuff = self.getExtraStuff(dialog.fRetPlugin)
  1122. self.addPlugin(btype, ptype, filename, None, label, extraStuff)
  1123. @pyqtSlot()
  1124. def slot_pluginRemoveAll(self):
  1125. self.removeAllPlugins()
  1126. def menuTransport(self, enabled):
  1127. self.ui.act_transport_play.setEnabled(enabled)
  1128. self.ui.act_transport_stop.setEnabled(enabled)
  1129. self.ui.act_transport_backwards.setEnabled(enabled)
  1130. self.ui.act_transport_forwards.setEnabled(enabled)
  1131. self.ui.menu_Transport.setEnabled(enabled)
  1132. def refreshTransport(self, forced = False):
  1133. if not self.fEngineStarted:
  1134. return
  1135. if self.fSampleRate == 0.0:
  1136. return
  1137. timeInfo = Carla.host.get_transport_info()
  1138. playing = timeInfo['playing']
  1139. time = timeInfo['frame'] / self.fSampleRate
  1140. secs = time % 60
  1141. mins = (time / 60) % 60
  1142. hrs = (time / 3600) % 60
  1143. textTransport = "Transport %s, at %02i:%02i:%02i" % ("playing" if playing else "stopped", hrs, mins, secs)
  1144. self.fInfoLabel.setText("%s | %s" % (self.fInfoText, textTransport))
  1145. if playing != self.fTransportWasPlaying or forced:
  1146. self.fTransportWasPlaying = playing
  1147. if playing:
  1148. icon = getIcon("media-playback-pause")
  1149. self.ui.act_transport_play.setChecked(True)
  1150. self.ui.act_transport_play.setIcon(icon)
  1151. self.ui.act_transport_play.setText(self.tr("&Pause"))
  1152. else:
  1153. icon = getIcon("media-playback-start")
  1154. self.ui.act_transport_play.setChecked(False)
  1155. self.ui.act_transport_play.setIcon(icon)
  1156. self.ui.act_transport_play.setText(self.tr("&Play"))
  1157. @pyqtSlot(bool)
  1158. def slot_transportPlayPause(self, toggled):
  1159. if not self.fEngineStarted:
  1160. return
  1161. if toggled:
  1162. Carla.host.transport_play()
  1163. else:
  1164. Carla.host.transport_pause()
  1165. self.refreshTransport()
  1166. @pyqtSlot()
  1167. def slot_transportStop(self):
  1168. if not self.fEngineStarted:
  1169. return
  1170. Carla.host.transport_pause()
  1171. Carla.host.transport_relocate(0)
  1172. self.refreshTransport()
  1173. @pyqtSlot()
  1174. def slot_transportBackwards(self):
  1175. if not self.fEngineStarted:
  1176. return
  1177. newFrame = Carla.host.get_current_transport_frame() - 100000
  1178. if newFrame < 0:
  1179. newFrame = 0
  1180. Carla.host.transport_relocate(newFrame)
  1181. @pyqtSlot()
  1182. def slot_transportForwards(self):
  1183. if not self.fEngineStarted:
  1184. return
  1185. newFrame = Carla.host.get_current_transport_frame() + 100000
  1186. Carla.host.transport_relocate(newFrame)
  1187. @pyqtSlot()
  1188. def slot_aboutCarla(self):
  1189. CarlaAboutW(self).exec_()
  1190. @pyqtSlot()
  1191. def slot_configureCarla(self):
  1192. dialog = CarlaSettingsW(self)
  1193. if dialog.exec_():
  1194. self.loadSettings(False)
  1195. patchcanvas.clear()
  1196. pOptions = patchcanvas.options_t()
  1197. pOptions.theme_name = self.fSavedSettings["Canvas/Theme"]
  1198. pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
  1199. pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
  1200. pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
  1201. pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
  1202. pFeatures = patchcanvas.features_t()
  1203. pFeatures.group_info = False
  1204. pFeatures.group_rename = False
  1205. pFeatures.port_info = False
  1206. pFeatures.port_rename = False
  1207. pFeatures.handle_group_pos = True
  1208. patchcanvas.setOptions(pOptions)
  1209. patchcanvas.setFeatures(pFeatures)
  1210. patchcanvas.init("Carla", self.scene, canvasCallback, False)
  1211. if self.fEngineStarted:
  1212. Carla.host.patchbay_refresh()
  1213. for pwidget in self.fPluginList:
  1214. if pwidget is None:
  1215. return
  1216. pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  1217. @pyqtSlot()
  1218. def slot_handleSIGUSR1(self):
  1219. print("Got SIGUSR1 -> Saving project now")
  1220. QTimer.singleShot(0, self, SLOT("slot_fileSave()"))
  1221. @pyqtSlot()
  1222. def slot_handleSIGTERM(self):
  1223. print("Got SIGTERM -> Closing now")
  1224. self.close()
  1225. @pyqtSlot(int, int, int, float, str)
  1226. def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
  1227. self.ui.pte_log.appendPlainText(valueStr.replace("", "DEBUG: ").replace("", "ERROR: ").replace("", "").replace("\n", ""))
  1228. @pyqtSlot(int)
  1229. def slot_handlePluginAddedCallback(self, pluginId):
  1230. pwidget = PluginWidget(self, pluginId)
  1231. pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  1232. self.ui.w_plugins.layout().addWidget(pwidget)
  1233. self.fPluginList.append(pwidget)
  1234. self.fPluginCount += 1
  1235. if not self.fProjectLoading:
  1236. pwidget.setActive(True, True, True)
  1237. if self.fPluginCount == 1:
  1238. self.ui.act_plugin_remove_all.setEnabled(True)
  1239. @pyqtSlot(int)
  1240. def slot_handlePluginRemovedCallback(self, pluginId):
  1241. if pluginId >= self.fPluginCount:
  1242. return
  1243. pwidget = self.fPluginList[pluginId]
  1244. if pwidget is None:
  1245. return
  1246. self.fPluginCount -= 1
  1247. self.fPluginList.pop(pluginId)
  1248. self.ui.w_plugins.layout().removeWidget(pwidget)
  1249. pwidget.ui.edit_dialog.close()
  1250. pwidget.close()
  1251. pwidget.deleteLater()
  1252. del pwidget
  1253. # push all plugins 1 slot back
  1254. for i in range(pluginId, self.fPluginCount):
  1255. self.fPluginList[i].setId(i)
  1256. if self.fPluginCount == 0:
  1257. self.ui.act_plugin_remove_all.setEnabled(False)
  1258. @pyqtSlot(int, str)
  1259. def slot_handlePluginRenamedCallback(self, pluginId, newName):
  1260. if pluginId >= self.fPluginCount:
  1261. return
  1262. pwidget = self.fPluginList[pluginId]
  1263. if pwidget is None:
  1264. return
  1265. pwidget.ui.label_name.setText(newName)
  1266. @pyqtSlot(int, int, float)
  1267. def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value):
  1268. if pluginId >= self.fPluginCount:
  1269. return
  1270. pwidget = self.fPluginList[pluginId]
  1271. if pwidget is None:
  1272. return
  1273. pwidget.setParameterValue(parameterId, value)
  1274. @pyqtSlot(int, int, float)
  1275. def slot_handleParameterDefaultChangedCallback(self, pluginId, parameterId, value):
  1276. if pluginId >= self.fPluginCount:
  1277. return
  1278. pwidget = self.fPluginList[pluginId]
  1279. if pwidget is None:
  1280. return
  1281. pwidget.setParameterDefault(parameterId, value)
  1282. @pyqtSlot(int, int, int)
  1283. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, parameterId, channel):
  1284. if pluginId >= self.fPluginCount:
  1285. return
  1286. pwidget = self.fPluginList[pluginId]
  1287. if pwidget is None:
  1288. return
  1289. pwidget.setParameterMidiChannel(parameterId, channel)
  1290. @pyqtSlot(int, int, int)
  1291. def slot_handleParameterMidiCcChangedCallback(self, pluginId, parameterId, cc):
  1292. if pluginId >= self.fPluginCount:
  1293. return
  1294. pwidget = self.fPluginList[pluginId]
  1295. if pwidget is None:
  1296. return
  1297. pwidget.setParameterMidiControl(parameterId, cc)
  1298. @pyqtSlot(int, int)
  1299. def slot_handleProgramChangedCallback(self, pluginId, programId):
  1300. if pluginId >= self.fPluginCount:
  1301. return
  1302. pwidget = self.fPluginList[pluginId]
  1303. if pwidget is None:
  1304. return
  1305. pwidget.setProgram(programId)
  1306. @pyqtSlot(int, int)
  1307. def slot_handleMidiProgramChangedCallback(self, pluginId, midiProgramId):
  1308. if pluginId >= self.fPluginCount:
  1309. return
  1310. pwidget = self.fPluginList[pluginId]
  1311. if pwidget is None:
  1312. return
  1313. pwidget.setMidiProgram(midiProgramId)
  1314. @pyqtSlot(int, int, int, int)
  1315. def slot_handleNoteOnCallback(self, pluginId, channel, note, velo):
  1316. if pluginId >= self.fPluginCount:
  1317. return
  1318. pwidget = self.fPluginList[pluginId]
  1319. if pwidget is None:
  1320. return
  1321. pwidget.sendNoteOn(channel, note)
  1322. @pyqtSlot(int, int, int)
  1323. def slot_handleNoteOffCallback(self, pluginId, channel, note):
  1324. if pluginId >= self.fPluginCount:
  1325. return
  1326. pwidget = self.fPluginList[pluginId]
  1327. if pwidget is None:
  1328. return
  1329. pwidget.sendNoteOff(channel, note)
  1330. @pyqtSlot(int, int)
  1331. def slot_handleShowGuiCallback(self, pluginId, show):
  1332. if pluginId >= self.fPluginCount:
  1333. return
  1334. pwidget = self.fPluginList[pluginId]
  1335. if pwidget is None:
  1336. return
  1337. if show == 0:
  1338. pwidget.ui.b_gui.setChecked(False)
  1339. pwidget.ui.b_gui.setEnabled(True)
  1340. elif show == 1:
  1341. pwidget.ui.b_gui.setChecked(True)
  1342. pwidget.ui.b_gui.setEnabled(True)
  1343. elif show == -1:
  1344. pwidget.ui.b_gui.setChecked(False)
  1345. pwidget.ui.b_gui.setEnabled(False)
  1346. @pyqtSlot(int)
  1347. def slot_handleUpdateCallback(self, pluginId):
  1348. if pluginId >= self.fPluginCount:
  1349. return
  1350. pwidget = self.fPluginList[pluginId]
  1351. if pwidget is None:
  1352. return
  1353. pwidget.ui.edit_dialog.updateInfo()
  1354. @pyqtSlot(int)
  1355. def slot_handleReloadInfoCallback(self, pluginId):
  1356. if pluginId >= self.fPluginCount:
  1357. return
  1358. pwidget = self.fPluginList[pluginId]
  1359. if pwidget is None:
  1360. return
  1361. pwidget.ui.edit_dialog.reloadInfo()
  1362. @pyqtSlot(int)
  1363. def slot_handleReloadParametersCallback(self, pluginId):
  1364. if pluginId >= self.fPluginCount:
  1365. return
  1366. pwidget = self.fPluginList[pluginId]
  1367. if pwidget is None:
  1368. return
  1369. pwidget.ui.edit_dialog.reloadParameters()
  1370. @pyqtSlot(int)
  1371. def slot_handleReloadProgramsCallback(self, pluginId):
  1372. if pluginId >= self.fPluginCount:
  1373. return
  1374. pwidget = self.fPluginList[pluginId]
  1375. if pwidget is None:
  1376. return
  1377. pwidget.ui.edit_dialog.reloadPrograms()
  1378. @pyqtSlot(int)
  1379. def slot_handleReloadAllCallback(self, pluginId):
  1380. if pluginId >= self.fPluginCount:
  1381. return
  1382. pwidget = self.fPluginList[pluginId]
  1383. if pwidget is None:
  1384. return
  1385. pwidget.ui.edit_dialog.reloadAll()
  1386. @pyqtSlot(int, str)
  1387. def slot_handlePatchbayClientAddedCallback(self, clientId, clientName):
  1388. patchcanvas.addGroup(clientId, clientName)
  1389. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1390. @pyqtSlot(int)
  1391. def slot_handlePatchbayClientRemovedCallback(self, clientId):
  1392. patchcanvas.removeGroup(clientId)
  1393. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1394. @pyqtSlot(int, str)
  1395. def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName):
  1396. patchcanvas.renameGroup(clientId, newClientName)
  1397. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1398. @pyqtSlot(int, int, int, str)
  1399. def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags, portName):
  1400. if (portFlags & PATCHBAY_PORT_IS_INPUT):
  1401. portMode = patchcanvas.PORT_MODE_INPUT
  1402. elif (portFlags & PATCHBAY_PORT_IS_OUTPUT):
  1403. portMode = patchcanvas.PORT_MODE_OUTPUT
  1404. else:
  1405. portMode = patchcanvas.PORT_MODE_NULL
  1406. if (portFlags & PATCHBAY_PORT_IS_AUDIO):
  1407. portType = patchcanvas.PORT_TYPE_AUDIO_JACK
  1408. elif (portFlags & PATCHBAY_PORT_IS_MIDI):
  1409. portType = patchcanvas.PORT_TYPE_MIDI_JACK
  1410. else:
  1411. portType = patchcanvas.PORT_TYPE_NULL
  1412. patchcanvas.addPort(clientId, portId, portName, portMode, portType)
  1413. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1414. @pyqtSlot(int)
  1415. def slot_handlePatchbayPortRemovedCallback(self, portId):
  1416. patchcanvas.removePort(portId)
  1417. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1418. @pyqtSlot(int, str)
  1419. def slot_handlePatchbayPortRenamedCallback(self, portId, newPortName):
  1420. patchcanvas.renamePort(portId, newPortName)
  1421. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1422. @pyqtSlot(int, int, int)
  1423. def slot_handlePatchbayConnectionAddedCallback(self, connectionId, portOutId, portInId):
  1424. patchcanvas.connectPorts(connectionId, portOutId, portInId)
  1425. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1426. @pyqtSlot(int)
  1427. def slot_handlePatchbayConnectionRemovedCallback(self, connectionId):
  1428. patchcanvas.disconnectPorts(connectionId)
  1429. QTimer.singleShot(0, self.ui.miniCanvasPreview, SLOT("update()"))
  1430. @pyqtSlot(int)
  1431. def slot_handleBufferSizeChangedCallback(self, newBufferSize):
  1432. self.fBufferSize = newBufferSize
  1433. self.fInfoText = "Engine running | SampleRate: %g | BufferSize: %i" % (self.fSampleRate, self.fBufferSize)
  1434. @pyqtSlot(float)
  1435. def slot_handleSampleRateChangedCallback(self, newSampleRate):
  1436. self.fSampleRate = newSampleRate
  1437. self.fInfoText = "Engine running | SampleRate: %g | BufferSize: %i" % (self.fSampleRate, self.fBufferSize)
  1438. @pyqtSlot(str)
  1439. def slot_handleErrorCallback(self, error):
  1440. QMessageBox.critical(self, self.tr("Error"), error)
  1441. @pyqtSlot()
  1442. def slot_handleQuitCallback(self):
  1443. CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  1444. self.tr("Engine has been stopped or crashed.\nPlease restart Carla"),
  1445. self.tr("You may want to save your session now..."), QMessageBox.Ok, QMessageBox.Ok)
  1446. def getExtraStuff(self, plugin):
  1447. ptype = plugin['type']
  1448. if ptype == PLUGIN_LADSPA:
  1449. uniqueId = plugin['uniqueId']
  1450. for rdfItem in self.fLadspaRdfList:
  1451. if rdfItem.UniqueID == uniqueId:
  1452. return pointer(rdfItem)
  1453. elif ptype == PLUGIN_DSSI:
  1454. if (plugin['hints'] & PLUGIN_HAS_GUI):
  1455. gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label'])
  1456. if gui:
  1457. return gui.encode("utf-8")
  1458. elif ptype in (PLUGIN_GIG, PLUGIN_SF2, PLUGIN_SFZ):
  1459. if plugin['name'].endswith(" (16 outputs)"):
  1460. # return a dummy non-null pointer
  1461. INTPOINTER = POINTER(c_int)
  1462. ptr = c_int(0x1)
  1463. addr = addressof(ptr)
  1464. return cast(addr, INTPOINTER)
  1465. return c_nullptr
  1466. def loadRDFs(self):
  1467. # Save RDF info for later
  1468. self.fLadspaRdfList = []
  1469. if not haveLRDF:
  1470. return
  1471. settingsDir = os.path.join(HOME, ".config", "falkTX")
  1472. frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db")
  1473. if os.path.exists(frLadspaFile):
  1474. frLadspa = open(frLadspaFile, 'r')
  1475. try:
  1476. self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa))
  1477. except:
  1478. pass
  1479. frLadspa.close()
  1480. def saveSettings(self):
  1481. settings = QSettings()
  1482. settings.setValue("Geometry", self.saveGeometry())
  1483. settings.setValue("SplitterState", self.ui.splitter.saveState())
  1484. settings.setValue("ShowToolbar", self.ui.toolBar.isVisible())
  1485. settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value())
  1486. settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value())
  1487. diskFolders = []
  1488. for i in range(self.ui.cb_disk.count()):
  1489. diskFolders.append(self.ui.cb_disk.itemData(i))
  1490. settings.setValue("DiskFolders", diskFolders)
  1491. def loadSettings(self, geometry):
  1492. settings = QSettings()
  1493. if geometry:
  1494. self.restoreGeometry(settings.value("Geometry", ""))
  1495. showToolbar = settings.value("ShowToolbar", True, type=bool)
  1496. self.ui.act_settings_show_toolbar.setChecked(showToolbar)
  1497. self.ui.toolBar.setVisible(showToolbar)
  1498. if settings.contains("SplitterState"):
  1499. self.ui.splitter.restoreState(settings.value("SplitterState", ""))
  1500. else:
  1501. self.ui.splitter.setSizes([99999, 210])
  1502. diskFolders = toList(settings.value("DiskFolders", [HOME]))
  1503. self.ui.cb_disk.setItemData(0, HOME)
  1504. for i in range(len(diskFolders)):
  1505. if i == 0: continue
  1506. folder = diskFolders[i]
  1507. self.ui.cb_disk.addItem(os.path.basename(folder), folder)
  1508. pal1 = app.palette().base().color()
  1509. pal2 = app.palette().button().color()
  1510. col1 = "stop:0 rgb(%i, %i, %i)" % (pal1.red(), pal1.green(), pal1.blue())
  1511. col2 = "stop:1 rgb(%i, %i, %i)" % (pal2.red(), pal2.green(), pal2.blue())
  1512. self.setStyleSheet("""
  1513. QWidget#w_plugins {
  1514. background-color: qlineargradient(spread:pad,
  1515. x1:0.0, y1:0.0,
  1516. x2:0.2, y2:1.0,
  1517. %s,
  1518. %s
  1519. );
  1520. }
  1521. """ % (col1, col2))
  1522. self.fSavedSettings = {
  1523. "Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", HOME, type=str),
  1524. "Main/RefreshInterval": settings.value("Main/RefreshInterval", 50, type=int),
  1525. "Canvas/Theme": settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str),
  1526. "Canvas/AutoHideGroups": settings.value("Canvas/AutoHideGroups", False, type=bool),
  1527. "Canvas/UseBezierLines": settings.value("Canvas/UseBezierLines", True, type=bool),
  1528. "Canvas/EyeCandy": settings.value("Canvas/EyeCandy", patchcanvas.EYECANDY_SMALL, type=int),
  1529. "Canvas/UseOpenGL": settings.value("Canvas/UseOpenGL", False, type=bool),
  1530. "Canvas/Antialiasing": settings.value("Canvas/Antialiasing", patchcanvas.ANTIALIASING_SMALL, type=int),
  1531. "Canvas/HighQualityAntialiasing": settings.value("Canvas/HighQualityAntialiasing", False, type=bool)
  1532. }
  1533. # ---------------------------------------------
  1534. # plugin checks
  1535. if settings.value("Engine/DisableChecks", False, type=bool):
  1536. os.environ["CARLA_DISCOVERY_NO_PROCESSING_CHECKS"] = "true"
  1537. elif os.getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"):
  1538. os.environ.pop("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
  1539. # ---------------------------------------------
  1540. # plugin paths
  1541. Carla.LADSPA_PATH = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH))
  1542. Carla.DSSI_PATH = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH))
  1543. Carla.LV2_PATH = toList(settings.value("Paths/LV2", Carla.LV2_PATH))
  1544. Carla.VST_PATH = toList(settings.value("Paths/VST", Carla.VST_PATH))
  1545. Carla.GIG_PATH = toList(settings.value("Paths/GIG", Carla.GIG_PATH))
  1546. Carla.SF2_PATH = toList(settings.value("Paths/SF2", Carla.SF2_PATH))
  1547. Carla.SFZ_PATH = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH))
  1548. os.environ["LADSPA_PATH"] = splitter.join(Carla.LADSPA_PATH)
  1549. os.environ["DSSI_PATH"] = splitter.join(Carla.DSSI_PATH)
  1550. os.environ["LV2_PATH"] = splitter.join(Carla.LV2_PATH)
  1551. os.environ["VST_PATH"] = splitter.join(Carla.VST_PATH)
  1552. os.environ["GIG_PATH"] = splitter.join(Carla.GIG_PATH)
  1553. os.environ["SF2_PATH"] = splitter.join(Carla.SF2_PATH)
  1554. os.environ["SFZ_PATH"] = splitter.join(Carla.SFZ_PATH)
  1555. def updateInfoLabelPos(self):
  1556. tabBar = self.ui.tabMain.tabBar()
  1557. y = tabBar.mapFromParent(self.ui.centralwidget.pos()).y()+tabBar.height()/4
  1558. if not self.ui.toolBar.isVisible():
  1559. y -= self.ui.toolBar.height()
  1560. self.fInfoLabel.move(self.fInfoLabel.x(), y)
  1561. def updateInfoLabelSize(self):
  1562. tabBar = self.ui.tabMain.tabBar()
  1563. self.fInfoLabel.resize(self.ui.tabMain.width()-tabBar.width()-20, self.fInfoLabel.height())
  1564. def dragEnterEvent(self, event):
  1565. if event.source() == self.ui.fileTreeView:
  1566. event.accept()
  1567. elif self.ui.tabMain.contentsRect().contains(event.pos()):
  1568. event.accept()
  1569. else:
  1570. QMainWindow.dragEnterEvent(self, event)
  1571. def dropEvent(self, event):
  1572. event.accept()
  1573. urls = event.mimeData().urls()
  1574. for url in urls:
  1575. filename = url.toLocalFile()
  1576. if not Carla.host.load_filename(filename):
  1577. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"),
  1578. self.tr("Failed to load file"),
  1579. cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  1580. def resizeEvent(self, event):
  1581. if self.ui.tabMain.currentIndex() == 0:
  1582. # Force update of 2nd tab
  1583. width = self.ui.tab_plugins.width()-4
  1584. height = self.ui.tab_plugins.height()-4
  1585. self.ui.miniCanvasPreview.setViewSize(float(width) / DEFAULT_CANVAS_WIDTH, float(height) / DEFAULT_CANVAS_HEIGHT)
  1586. else:
  1587. QTimer.singleShot(0, self, SLOT("slot_miniCanvasCheckSize()"))
  1588. self.updateInfoLabelSize()
  1589. QMainWindow.resizeEvent(self, event)
  1590. def timerEvent(self, event):
  1591. if event.timerId() == self.fIdleTimerFast:
  1592. if not self.fEngineStarted:
  1593. return
  1594. Carla.host.engine_idle()
  1595. for pwidget in self.fPluginList:
  1596. if pwidget is None:
  1597. break
  1598. pwidget.idleFast()
  1599. self.refreshTransport()
  1600. elif event.timerId() == self.fIdleTimerSlow:
  1601. if not self.fEngineStarted:
  1602. return
  1603. for pwidget in self.fPluginList:
  1604. if pwidget is None:
  1605. break
  1606. pwidget.idleSlow()
  1607. QMainWindow.timerEvent(self, event)
  1608. def closeEvent(self, event):
  1609. self.saveSettings()
  1610. if Carla.host.is_engine_running():
  1611. Carla.host.set_engine_about_to_close()
  1612. self.removeAllPlugins()
  1613. self.stopEngine()
  1614. QMainWindow.closeEvent(self, event)
  1615. # ------------------------------------------------------------------------------------------------
  1616. def canvasCallback(action, value1, value2, valueStr):
  1617. if action == patchcanvas.ACTION_GROUP_INFO:
  1618. pass
  1619. elif action == patchcanvas.ACTION_GROUP_RENAME:
  1620. pass
  1621. elif action == patchcanvas.ACTION_GROUP_SPLIT:
  1622. groupId = value1
  1623. patchcanvas.splitGroup(groupId)
  1624. Carla.gui.ui.miniCanvasPreview.update()
  1625. elif action == patchcanvas.ACTION_GROUP_JOIN:
  1626. groupId = value1
  1627. patchcanvas.joinGroup(groupId)
  1628. Carla.gui.ui.miniCanvasPreview.update()
  1629. elif action == patchcanvas.ACTION_PORT_INFO:
  1630. pass
  1631. elif action == patchcanvas.ACTION_PORT_RENAME:
  1632. pass
  1633. elif action == patchcanvas.ACTION_PORTS_CONNECT:
  1634. portIdA = value1
  1635. portIdB = value2
  1636. Carla.host.patchbay_connect(portIdA, portIdB)
  1637. elif action == patchcanvas.ACTION_PORTS_DISCONNECT:
  1638. connectionId = value1
  1639. Carla.host.patchbay_disconnect(connectionId)
  1640. def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr):
  1641. if pluginId < 0 or not Carla.gui:
  1642. return
  1643. if action == CALLBACK_DEBUG:
  1644. Carla.gui.emit(SIGNAL("DebugCallback(int, int, int, double, QString)"), pluginId, value1, value2, value3, cString(valueStr))
  1645. elif action == CALLBACK_PLUGIN_ADDED:
  1646. Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId)
  1647. elif action == CALLBACK_PLUGIN_REMOVED:
  1648. Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId)
  1649. elif action == CALLBACK_PLUGIN_RENAMED:
  1650. Carla.gui.emit(SIGNAL("PluginRenamedCallback(int, QString)"), pluginId, valueStr)
  1651. elif action == CALLBACK_PARAMETER_VALUE_CHANGED:
  1652. Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3)
  1653. elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED:
  1654. Carla.gui.emit(SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), pluginId, value1, value3)
  1655. elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  1656. Carla.gui.emit(SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), pluginId, value1, value2)
  1657. elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  1658. Carla.gui.emit(SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), pluginId, value1, value2)
  1659. elif action == CALLBACK_PROGRAM_CHANGED:
  1660. Carla.gui.emit(SIGNAL("ProgramChangedCallback(int, int)"), pluginId, value1)
  1661. elif action == CALLBACK_MIDI_PROGRAM_CHANGED:
  1662. Carla.gui.emit(SIGNAL("MidiProgramChangedCallback(int, int)"), pluginId, value1)
  1663. elif action == CALLBACK_NOTE_ON:
  1664. Carla.gui.emit(SIGNAL("NoteOnCallback(int, int, int, int)"), pluginId, value1, value2, value3)
  1665. elif action == CALLBACK_NOTE_OFF:
  1666. Carla.gui.emit(SIGNAL("NoteOffCallback(int, int, int)"), pluginId, value1, value2)
  1667. elif action == CALLBACK_SHOW_GUI:
  1668. Carla.gui.emit(SIGNAL("ShowGuiCallback(int, int)"), pluginId, value1)
  1669. elif action == CALLBACK_UPDATE:
  1670. Carla.gui.emit(SIGNAL("UpdateCallback(int)"), pluginId)
  1671. elif action == CALLBACK_RELOAD_INFO:
  1672. Carla.gui.emit(SIGNAL("ReloadInfoCallback(int)"), pluginId)
  1673. elif action == CALLBACK_RELOAD_PARAMETERS:
  1674. Carla.gui.emit(SIGNAL("ReloadParametersCallback(int)"), pluginId)
  1675. elif action == CALLBACK_RELOAD_PROGRAMS:
  1676. Carla.gui.emit(SIGNAL("ReloadProgramsCallback(int)"), pluginId)
  1677. elif action == CALLBACK_RELOAD_ALL:
  1678. Carla.gui.emit(SIGNAL("ReloadAllCallback(int)"), pluginId)
  1679. elif action == CALLBACK_PATCHBAY_CLIENT_ADDED:
  1680. Carla.gui.emit(SIGNAL("PatchbayClientAddedCallback(int, QString)"), value1, cString(valueStr))
  1681. elif action == CALLBACK_PATCHBAY_CLIENT_REMOVED:
  1682. Carla.gui.emit(SIGNAL("PatchbayClientRemovedCallback(int)"), value1)
  1683. elif action == CALLBACK_PATCHBAY_CLIENT_RENAMED:
  1684. Carla.gui.emit(SIGNAL("PatchbayClientRenamedCallback(int, QString)"), value1, cString(valueStr))
  1685. elif action == CALLBACK_PATCHBAY_PORT_ADDED:
  1686. Carla.gui.emit(SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), value1, value2, int(value3), cString(valueStr))
  1687. elif action == CALLBACK_PATCHBAY_PORT_REMOVED:
  1688. Carla.gui.emit(SIGNAL("PatchbayPortRemovedCallback(int)"), value1)
  1689. elif action == CALLBACK_PATCHBAY_PORT_RENAMED:
  1690. Carla.gui.emit(SIGNAL("PatchbayPortRenamedCallback(int, QString)"), value1, cString(valueStr))
  1691. elif action == CALLBACK_PATCHBAY_CONNECTION_ADDED:
  1692. Carla.gui.emit(SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), value1, value2, value3)
  1693. elif action == CALLBACK_PATCHBAY_CONNECTION_REMOVED:
  1694. Carla.gui.emit(SIGNAL("PatchbayConnectionRemovedCallback(int)"), value1)
  1695. elif action == CALLBACK_BUFFER_SIZE_CHANGED:
  1696. Carla.gui.emit(SIGNAL("BufferSizeChangedCallback(int)"), value1)
  1697. elif action == CALLBACK_SAMPLE_RATE_CHANGED:
  1698. Carla.gui.emit(SIGNAL("SampleRateChangedCallback(double)"), value3)
  1699. elif action == CALLBACK_NSM_ANNOUNCE:
  1700. Carla.gui.emit(SIGNAL("NSM_AnnounceCallback(QString)"), cString(valueStr))
  1701. elif action == CALLBACK_NSM_OPEN:
  1702. Carla.gui.emit(SIGNAL("NSM_OpenCallback(QString)"), cString(valueStr))
  1703. elif action == CALLBACK_NSM_SAVE:
  1704. Carla.gui.emit(SIGNAL("NSM_SaveCallback()"))
  1705. elif action == CALLBACK_ERROR:
  1706. Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), cString(valueStr))
  1707. elif action == CALLBACK_QUIT:
  1708. Carla.gui.emit(SIGNAL("QuitCallback()"))
  1709. #--------------- main ------------------
  1710. if __name__ == '__main__':
  1711. # App initialization
  1712. app = QApplication(sys.argv)
  1713. app.setApplicationName("Carla")
  1714. app.setApplicationVersion(VERSION)
  1715. app.setOrganizationName("falkTX")
  1716. app.setWindowIcon(QIcon(":/scalable/carla.svg"))
  1717. for i in range(len(app.arguments())):
  1718. if i == 0: continue
  1719. argument = app.arguments()[i]
  1720. if argument.startswith("--with-appname="):
  1721. appName = os.path.basename(argument.replace("--with-appname=", ""))
  1722. elif argument.startswith("--with-libprefix="):
  1723. libPrefix = argument.replace("--with-libprefix=", "")
  1724. elif os.path.exists(argument):
  1725. projectFilename = argument
  1726. if libPrefix is not None:
  1727. libPath = os.path.join(libPrefix, "lib", "carla")
  1728. libName = os.path.join(libPath, carla_libname)
  1729. else:
  1730. libPath = carla_library_path.replace(carla_libname, "")
  1731. libName = carla_library_path
  1732. # Init backend
  1733. Carla.host = Host(libName)
  1734. Carla.host.set_engine_callback(engineCallback)
  1735. Carla.host.set_engine_option(OPTION_PROCESS_NAME, 0, "carla")
  1736. # Change dir to where DLL and resources are
  1737. os.chdir(libPath)
  1738. # Set bridge paths
  1739. if carla_bridge_native:
  1740. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_NATIVE, 0, carla_bridge_native)
  1741. if carla_bridge_posix32:
  1742. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX32, 0, carla_bridge_posix32)
  1743. if carla_bridge_posix64:
  1744. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX64, 0, carla_bridge_posix64)
  1745. if carla_bridge_win32:
  1746. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32)
  1747. if carla_bridge_win64:
  1748. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64)
  1749. if WINDOWS:
  1750. if carla_bridge_lv2_windows:
  1751. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, carla_bridge_lv2_windows)
  1752. if carla_bridge_vst_hwnd:
  1753. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_HWND, 0, carla_bridge_vst_hwnd)
  1754. elif MACOS:
  1755. if carla_bridge_lv2_cocoa:
  1756. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_COCOA, 0, carla_bridge_lv2_cocoa)
  1757. if carla_bridge_vst_cocoa:
  1758. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_COCOA, 0, carla_bridge_vst_cocoa)
  1759. else:
  1760. if carla_bridge_lv2_gtk2:
  1761. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2)
  1762. if carla_bridge_lv2_gtk3:
  1763. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK3, 0, carla_bridge_lv2_gtk3)
  1764. if carla_bridge_lv2_qt4:
  1765. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4)
  1766. if carla_bridge_lv2_qt5:
  1767. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT5, 0, carla_bridge_lv2_qt5)
  1768. if carla_bridge_lv2_x11:
  1769. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11)
  1770. if carla_bridge_vst_x11:
  1771. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11)
  1772. # Create GUI and start engine
  1773. Carla.gui = CarlaMainW()
  1774. # Set-up custom signal handling
  1775. setUpSignals()
  1776. # Show GUI
  1777. Carla.gui.show()
  1778. # Load project file if set
  1779. if projectFilename and not os.getenv("NSM_URL"):
  1780. Carla.gui.loadProjectLater(projectFilename)
  1781. # App-Loop
  1782. ret = app.exec_()
  1783. # Exit properly
  1784. sys.exit(ret)