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.

610 lines
26KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin host
  4. # Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the GPL.txt file
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from PyQt4.QtCore import QSize
  20. from PyQt4.QtGui import QApplication, QListWidgetItem, QMainWindow
  21. # ------------------------------------------------------------------------------------------------------------
  22. # Imports (Custom Stuff)
  23. import ui_carla
  24. from carla_backend import *
  25. from carla_shared import *
  26. # FIXME, remove later
  27. #from shared_settings import *
  28. # ------------------------------------------------------------------------------------------------------------
  29. # Main Window
  30. class CarlaMainW(QMainWindow):
  31. def __init__(self, parent=None):
  32. QMainWindow.__init__(self, parent)
  33. self.ui = ui_carla.Ui_CarlaMainW()
  34. self.ui.setupUi(self)
  35. # -------------------------------------------------------------
  36. # Load Settings
  37. self.loadSettings(True)
  38. self.loadRDFs()
  39. self.setStyleSheet("""
  40. QWidget#centralwidget {
  41. background-color: qlineargradient(spread:pad,
  42. x1:0.0, y1:0.0,
  43. x2:0.2, y2:1.0,
  44. stop:0 rgb( 7, 7, 7),
  45. stop:1 rgb(28, 28, 28)
  46. );
  47. }
  48. """)
  49. # -------------------------------------------------------------
  50. # Internal stuff
  51. self.fEngineStarted = False
  52. self.fFirstEngineInit = False
  53. self.fPluginCount = 0
  54. self.fPluginList = []
  55. self.fIdleTimerFast = 0
  56. self.fIdleTimerSlow = 0
  57. #self.m_project_filename = None
  58. #self._nsmAnnounce2str = ""
  59. #self._nsmOpen1str = ""
  60. #self._nsmOpen2str = ""
  61. #self.nsm_server = None
  62. #self.nsm_url = None
  63. # -------------------------------------------------------------
  64. # Set-up GUI stuff
  65. self.ui.act_engine_start.setEnabled(False)
  66. self.ui.act_engine_stop.setEnabled(False)
  67. self.ui.act_plugin_remove_all.setEnabled(False)
  68. self.resize(self.width(), 0)
  69. #self.m_fakeEdit = PluginEdit(self, -1)
  70. #self.m_curEdit = self.m_fakeEdit
  71. #self.w_edit.layout().addWidget(self.m_curEdit)
  72. #self.w_edit.layout().addStretch()
  73. # -------------------------------------------------------------
  74. # Connect actions to functions
  75. #self.connect(self.act_file_new, SIGNAL("triggered()"), SLOT("slot_file_new()"))
  76. #self.connect(self.act_file_open, SIGNAL("triggered()"), SLOT("slot_file_open()"))
  77. #self.connect(self.act_file_save, SIGNAL("triggered()"), SLOT("slot_file_save()"))
  78. #self.connect(self.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_file_save_as()"))
  79. self.connect(self.ui.act_engine_start, SIGNAL("triggered()"), SLOT("slot_startEngine()"))
  80. self.connect(self.ui.act_engine_stop, SIGNAL("triggered()"), SLOT("slot_stopEngine()"))
  81. self.connect(self.ui.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_addPlugin()"))
  82. #self.connect(self.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_remove_all()"))
  83. #self.connect(self.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()"))
  84. self.connect(self.ui.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarla()"))
  85. self.connect(self.ui.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  86. #self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_handleSIGUSR1()"))
  87. self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)"))
  88. self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)"))
  89. self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)"))
  90. self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)"))
  91. self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)"))
  92. self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)"))
  93. self.connect(self, SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiCcChangedCallback(int, int, int)"))
  94. self.connect(self, SIGNAL("ProgramChangedCallback(int, int)"), SLOT("slot_handleProgramChangedCallback(int, int)"))
  95. self.connect(self, SIGNAL("MidiProgramChangedCallback(int, int)"), SLOT("slot_handleMidiProgramChangedCallback(int, int)"))
  96. self.connect(self, SIGNAL("NoteOnCallback(int, int, int, int)"), SLOT("slot_handleNoteOnCallback(int, int, int, int)"))
  97. self.connect(self, SIGNAL("NoteOffCallback(int, int, int)"), SLOT("slot_handleNoteOffCallback(int, int, int)"))
  98. self.connect(self, SIGNAL("ShowGuiCallback(int, int)"), SLOT("slot_handleShowGuiCallback(int, int)"))
  99. self.connect(self, SIGNAL("UpdateCallback(int)"), SLOT("slot_handleUpdateCallback(int)"))
  100. self.connect(self, SIGNAL("ReloadInfoCallback(int)"), SLOT("slot_handleReloadInfoCallback(int)"))
  101. self.connect(self, SIGNAL("ReloadParametersCallback(int)"), SLOT("slot_handleReloadParametersCallback(int)"))
  102. self.connect(self, SIGNAL("ReloadProgramsCallback(int)"), SLOT("slot_handleReloadProgramsCallback(int)"))
  103. self.connect(self, SIGNAL("ReloadAllCallback(int)"), SLOT("slot_handleReloadAllCallback(int)"))
  104. #self.connect(self, SIGNAL("NSM_AnnounceCallback()"), SLOT("slot_handleNSM_AnnounceCallback()"))
  105. #self.connect(self, SIGNAL("NSM_Open1Callback()"), SLOT("slot_handleNSM_Open1Callback()"))
  106. #self.connect(self, SIGNAL("NSM_Open2Callback()"), SLOT("slot_handleNSM_Open2Callback()"))
  107. #self.connect(self, SIGNAL("NSM_SaveCallback()"), SLOT("slot_handleNSM_SaveCallback()"))
  108. self.connect(self, SIGNAL("ErrorCallback(QString)"), SLOT("slot_handleErrorCallback(QString)"))
  109. self.connect(self, SIGNAL("QuitCallback()"), SLOT("slot_handleQuitCallback()"))
  110. #NSM_URL = os.getenv("NSM_URL")
  111. #if NSM_URL:
  112. #Carla.host.nsm_announce(NSM_URL, os.getpid())
  113. #else:
  114. QTimer.singleShot(0, self, SLOT("slot_startEngine()"))
  115. def startEngine(self, clientName = "Carla"):
  116. # ---------------------------------------------
  117. # Engine settings
  118. settings = QSettings()
  119. Carla.processMode = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int)
  120. Carla.maxParameters = settings.value("Engine/MaxParameters", MAX_DEFAULT_PARAMETERS, type=int)
  121. forceStereo = settings.value("Engine/ForceStereo", False, type=bool)
  122. preferPluginBridges = settings.value("Engine/PreferPluginBridges", False, type=bool)
  123. preferUiBridges = settings.value("Engine/PreferUiBridges", True, type=bool)
  124. useDssiVstChunks = settings.value("Engine/UseDssiVstChunks", False, type=bool)
  125. oscUiTimeout = settings.value("Engine/OscUiTimeout", 40, type=int)
  126. preferredBufferSize = settings.value("Engine/PreferredBufferSize", 512, type=int)
  127. preferredSampleRate = settings.value("Engine/PreferredSampleRate", 44100, type=int)
  128. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  129. forceStereo = True
  130. elif Carla.processMode == PROCESS_MODE_MULTIPLE_CLIENTS and os.getenv("LADISH_APP_NAME"):
  131. print("LADISH detected but using multiple clients (not allowed), forcing single client now")
  132. Carla.processMode = PROCESS_MODE_SINGLE_CLIENT
  133. Carla.host.set_option(OPTION_PROCESS_MODE, Carla.processMode, "")
  134. Carla.host.set_option(OPTION_MAX_PARAMETERS, Carla.maxParameters, "")
  135. Carla.host.set_option(OPTION_FORCE_STEREO, forceStereo, "")
  136. Carla.host.set_option(OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "")
  137. Carla.host.set_option(OPTION_PREFER_UI_BRIDGES, preferUiBridges, "")
  138. Carla.host.set_option(OPTION_USE_DSSI_VST_CHUNKS, useDssiVstChunks, "")
  139. Carla.host.set_option(OPTION_OSC_UI_TIMEOUT, oscUiTimeout, "")
  140. Carla.host.set_option(OPTION_PREFERRED_BUFFER_SIZE, preferredBufferSize, "")
  141. Carla.host.set_option(OPTION_PREFERRED_SAMPLE_RATE, preferredSampleRate, "")
  142. # ---------------------------------------------
  143. # start
  144. audioDriver = settings.value("Engine/AudioDriver", "JACK", type=str)
  145. if not Carla.host.engine_init(audioDriver, clientName):
  146. if self.fFirstEngineInit:
  147. self.fFirstEngineInit = False
  148. return
  149. self.ui.act_engine_start.setEnabled(True)
  150. self.ui.act_engine_stop.setEnabled(False)
  151. audioError = cString(Carla.host.get_last_error())
  152. if audioError:
  153. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons: %s" % (audioDriver, audioError)))
  154. else:
  155. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver))
  156. return
  157. self.fEngineStarted = True
  158. self.fFirstEngineInit = False
  159. self.fPluginCount = 0
  160. self.fPluginList = []
  161. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  162. maxCount = MAX_RACK_PLUGINS
  163. elif Carla.processMode == PROCESS_MODE_PATCHBAY:
  164. maxCount = MAX_PATCHBAY_PLUGINS
  165. else:
  166. maxCount = MAX_DEFAULT_PLUGINS
  167. for x in range(maxCount):
  168. self.fPluginList.append(None)
  169. # Peaks
  170. self.fIdleTimerFast = self.startTimer(self.fSavedSettings["Main/RefreshInterval"])
  171. # LEDs and edit dialog parameters
  172. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  173. def stopEngine(self):
  174. if self.fPluginCount > 0:
  175. 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"
  176. "Do you want to do this now?"),
  177. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  178. if ask != QMessageBox.Yes:
  179. return
  180. #self.slot_remove_all()
  181. if Carla.host.is_engine_running() and not Carla.host.engine_close():
  182. print(cString(Carla.host.get_last_error()))
  183. self.fEngineStarted = False
  184. self.fPluginCount = 0
  185. self.fPluginList = []
  186. self.killTimer(self.fIdleTimerFast)
  187. self.killTimer(self.fIdleTimerSlow)
  188. def addPlugin(self, btype, ptype, filename, name, label, extraStuff):
  189. if not self.fEngineStarted:
  190. QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
  191. return False
  192. if not Carla.host.add_plugin(btype, ptype, filename, name, label, extraStuff):
  193. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  194. return False
  195. return True
  196. @pyqtSlot()
  197. def slot_startEngine(self):
  198. self.startEngine()
  199. check = Carla.host.is_engine_running()
  200. self.ui.act_file_open.setEnabled(check)
  201. self.ui.act_engine_start.setEnabled(not check)
  202. self.ui.act_engine_stop.setEnabled(check)
  203. @pyqtSlot()
  204. def slot_stopEngine(self):
  205. self.stopEngine()
  206. check = Carla.host.is_engine_running()
  207. self.ui.act_file_open.setEnabled(check)
  208. self.ui.act_engine_start.setEnabled(not check)
  209. self.ui.act_engine_stop.setEnabled(check)
  210. @pyqtSlot()
  211. def slot_handleSIGUSR1(self):
  212. print("Got SIGUSR1 -> Saving project now")
  213. #QTimer.singleShot(0, self, SLOT("slot_file_save()"))
  214. @pyqtSlot(int, int, int, float, str)
  215. def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
  216. print("DEBUG :: %i, %i, %i, %f, \"%s\")" % (pluginId, value1, value2, value3, valueStr))
  217. @pyqtSlot(int)
  218. def slot_handlePluginAddedCallback(self, pluginId, pluginName="todo"):
  219. pwidgetItem = QListWidgetItem(self.ui.listWidget)
  220. pwidgetItem.setSizeHint(QSize(pwidgetItem.sizeHint().width(), 48))
  221. pwidget = PluginWidget(self, pwidgetItem, pluginId)
  222. pwidget.ui.peak_in.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  223. pwidget.ui.peak_out.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"])
  224. self.ui.listWidget.setItemWidget(pwidgetItem, pwidget)
  225. self.fPluginCount += 1
  226. self.fPluginList[pluginId] = pwidget
  227. if self.fPluginCount == 1:
  228. self.ui.act_plugin_remove_all.setEnabled(True)
  229. @pyqtSlot(int)
  230. def slot_handlePluginRemovedCallback(self, pluginId):
  231. pwidget = self.fPluginList[pluginId]
  232. if pwidget is None:
  233. return
  234. self.fPluginList[pluginId] = None
  235. self.fPluginCount -= 1
  236. pwidget.ui.edit_dialog.close()
  237. pwidget.close()
  238. del pwidget
  239. self.ui.listWidget.takeItem(pluginId)
  240. #self.ui.listWidget.removeItemWidget(pwidget.getListWidgetItem())
  241. if self.fPluginCount == 0:
  242. self.ui.act_plugin_remove_all.setEnabled(False)
  243. @pyqtSlot(int, int, float)
  244. def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value):
  245. pwidget = self.fPluginList[pluginId]
  246. if pwidget is None:
  247. return
  248. pwidget.setParameterValue(value, True, False)
  249. @pyqtSlot(str)
  250. def slot_handleErrorCallback(self, error):
  251. QMessageBox.critical(self, self.tr("Error"), error)
  252. @pyqtSlot()
  253. def slot_handleQuitCallback(self):
  254. CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"),
  255. self.tr("Engine has been stopped or crashed.\nPlease restart Carla"),
  256. self.tr("You may want to save your session now..."), QMessageBox.Ok, QMessageBox.Ok)
  257. @pyqtSlot()
  258. def slot_addPlugin(self):
  259. dialog = PluginDatabaseW(self)
  260. if dialog.exec_():
  261. btype = dialog.fRetPlugin['build']
  262. ptype = dialog.fRetPlugin['type']
  263. filename = dialog.fRetPlugin['binary']
  264. label = dialog.fRetPlugin['label']
  265. extraStuff = self.getExtraStuff(dialog.fRetPlugin)
  266. self.addPlugin(btype, ptype, filename, None, label, extraStuff)
  267. @pyqtSlot()
  268. def slot_aboutCarla(self):
  269. CarlaAboutW(self).exec_()
  270. def getExtraStuff(self, plugin):
  271. ptype = plugin['type']
  272. if ptype == PLUGIN_LADSPA:
  273. uniqueId = plugin['uniqueId']
  274. for rdfItem in self.fLadspaRdfList:
  275. if rdfItem.UniqueID == uniqueId:
  276. return pointer(rdfItem)
  277. elif ptype == PLUGIN_DSSI:
  278. if plugin['hints'] & PLUGIN_HAS_GUI:
  279. gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label'])
  280. if gui:
  281. return gui.encode("utf-8")
  282. return c_nullptr
  283. def loadRDFs(self):
  284. # Save RDF info for later
  285. self.fLadspaRdfList = []
  286. if haveLRDF:
  287. settingsDir = os.path.join(HOME, ".config", "Cadence")
  288. frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db")
  289. if os.path.exists(frLadspaFile):
  290. frLadspa = open(frLadspaFile, 'r')
  291. try:
  292. self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa))
  293. except:
  294. pass
  295. frLadspa.close()
  296. def saveSettings(self):
  297. settings = QSettings()
  298. settings.setValue("Geometry", self.saveGeometry())
  299. settings.setValue("ShowToolbar", self.ui.toolBar.isVisible())
  300. def loadSettings(self, geometry):
  301. settings = QSettings()
  302. if geometry:
  303. self.restoreGeometry(settings.value("Geometry", ""))
  304. showToolbar = settings.value("ShowToolbar", True, type=bool)
  305. self.ui.act_settings_show_toolbar.setChecked(showToolbar)
  306. self.ui.toolBar.setVisible(showToolbar)
  307. self.fSavedSettings = {
  308. "Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", HOME, type=str),
  309. "Main/RefreshInterval": settings.value("Main/RefreshInterval", 120, type=int)
  310. }
  311. # ---------------------------------------------
  312. # plugin checks
  313. if settings.value("Engine/DisableChecks", False, type=bool):
  314. os.environ["CARLA_DISCOVERY_NO_PROCESSING_CHECKS"] = "true"
  315. elif os.getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"):
  316. os.environ.pop("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
  317. # ---------------------------------------------
  318. # plugin paths
  319. global LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, GIG_PATH, SF2_PATH, SFZ_PATH
  320. LADSPA_PATH = toList(settings.value("Paths/LADSPA", LADSPA_PATH))
  321. DSSI_PATH = toList(settings.value("Paths/DSSI", DSSI_PATH))
  322. LV2_PATH = toList(settings.value("Paths/LV2", LV2_PATH))
  323. VST_PATH = toList(settings.value("Paths/VST", VST_PATH))
  324. GIG_PATH = toList(settings.value("Paths/GIG", GIG_PATH))
  325. SF2_PATH = toList(settings.value("Paths/SF2", SF2_PATH))
  326. SFZ_PATH = toList(settings.value("Paths/SFZ", SFZ_PATH))
  327. os.environ["LADSPA_PATH"] = splitter.join(LADSPA_PATH)
  328. os.environ["DSSI_PATH"] = splitter.join(DSSI_PATH)
  329. os.environ["LV2_PATH"] = splitter.join(LV2_PATH)
  330. os.environ["VST_PATH"] = splitter.join(VST_PATH)
  331. os.environ["GIG_PATH"] = splitter.join(GIG_PATH)
  332. os.environ["SF2_PATH"] = splitter.join(SF2_PATH)
  333. os.environ["SFZ_PATH"] = splitter.join(SFZ_PATH)
  334. def timerEvent(self, event):
  335. if event.timerId() == self.fIdleTimerFast:
  336. Carla.host.engine_idle()
  337. for pwidget in self.fPluginList:
  338. if pwidget is not None:
  339. pwidget.idleFast()
  340. elif event.timerId() == self.fIdleTimerSlow:
  341. for pwidget in self.fPluginList:
  342. if pwidget is not None:
  343. pwidget.idleSlow()
  344. QMainWindow.timerEvent(self, event)
  345. def closeEvent(self, event):
  346. #if self.nsm_server:
  347. #self.nsm_server.stop()
  348. self.saveSettings()
  349. #self.slot_remove_all()
  350. self.stopEngine()
  351. QMainWindow.closeEvent(self, event)
  352. # ------------------------------------------------------------------------------------------------
  353. def callbackFunction(ptr, action, pluginId, value1, value2, value3, valueStr):
  354. if pluginId < 0 or not Carla.gui:
  355. return
  356. if action == CALLBACK_DEBUG:
  357. return Carla.gui.emit(SIGNAL("DebugCallback(int, int, int, double, QString)"), pluginId, value1, value2, value3, cString(valueStr))
  358. elif action == CALLBACK_PLUGIN_ADDED:
  359. return Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId)
  360. elif action == CALLBACK_PLUGIN_REMOVED:
  361. return Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId)
  362. elif action == CALLBACK_PARAMETER_VALUE_CHANGED:
  363. return Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3)
  364. elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED:
  365. return Carla.gui.emit(SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), pluginId, value1, value3)
  366. elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  367. return Carla.gui.emit(SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), pluginId, value1, value2)
  368. elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  369. return Carla.gui.emit(SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), pluginId, value1, value2)
  370. elif action == CALLBACK_PROGRAM_CHANGED:
  371. return Carla.gui.emit(SIGNAL("ProgramChangedCallback(int, int)"), pluginId, value1)
  372. elif action == CALLBACK_MIDI_PROGRAM_CHANGED:
  373. return Carla.gui.emit(SIGNAL("MidiProgramChangedCallback(int, int)"), pluginId, value1)
  374. elif action == CALLBACK_NOTE_ON:
  375. return Carla.gui.emit(SIGNAL("NoteOnCallback(int, int, int, int)"), pluginId, value1, value2, value3)
  376. elif action == CALLBACK_NOTE_OFF:
  377. return Carla.gui.emit(SIGNAL("NoteOffCallback(int, int, int)"), pluginId, value1, value2)
  378. elif action == CALLBACK_SHOW_GUI:
  379. return Carla.gui.emit(SIGNAL("ShowGuiCallback(int, int)"), pluginId, value1)
  380. elif action == CALLBACK_UPDATE:
  381. return Carla.gui.emit(SIGNAL("UpdateCallback(int)"), pluginId)
  382. elif action == CALLBACK_RELOAD_INFO:
  383. return Carla.gui.emit(SIGNAL("ReloadInfoCallback(int)"), pluginId)
  384. elif action == CALLBACK_RELOAD_PARAMETERS:
  385. return Carla.gui.emit(SIGNAL("ReloadParametersCallback(int)"), pluginId)
  386. elif action == CALLBACK_RELOAD_PROGRAMS:
  387. return Carla.gui.emit(SIGNAL("ReloadProgramsCallback(int)"), pluginId)
  388. elif action == CALLBACK_RELOAD_ALL:
  389. return Carla.gui.emit(SIGNAL("ReloadAllCallback(int)"), pluginId)
  390. #elif action == CALLBACK_NSM_ANNOUNCE:
  391. #Carla.gui._nsmAnnounce2str = cString(Carla.host.get_last_error())
  392. #Carla.gui.emit(SIGNAL("NSM_AnnounceCallback()"))
  393. #return
  394. #elif action == CALLBACK_NSM_OPEN1:
  395. #Carla.gui._nsmOpen1str = cString(valueStr)
  396. #Carla.gui.emit(SIGNAL("NSM_Open1Callback()"))
  397. #return
  398. #elif action == CALLBACK_NSM_OPEN2:
  399. #Carla.gui._nsmOpen2str = cString(valueStr)
  400. #Carla.gui.emit(SIGNAL("NSM_Open2Callback()"))
  401. #return
  402. #elif action == CALLBACK_NSM_SAVE:
  403. #return Carla.gui.emit(SIGNAL("NSM_SaveCallback()"))
  404. elif action == CALLBACK_ERROR:
  405. return Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), valueStr)
  406. elif action == CALLBACK_QUIT:
  407. return Carla.gui.emit(SIGNAL("QuitCallback()"))
  408. #--------------- main ------------------
  409. if __name__ == '__main__':
  410. # App initialization
  411. app = QApplication(sys.argv)
  412. app.setApplicationName("Carla")
  413. app.setApplicationVersion(VERSION)
  414. app.setOrganizationName("Cadence")
  415. app.setWindowIcon(QIcon(":/scalable/carla.svg"))
  416. libPrefix = None
  417. projectFilename = None
  418. for i in range(len(app.arguments())):
  419. if i == 0: continue
  420. argument = app.arguments()[i]
  421. if argument.startswith("--with-libprefix="):
  422. libPrefix = argument.replace("--with-libprefix=", "")
  423. elif os.path.exists(argument):
  424. projectFilename = argument
  425. # Init backend
  426. Carla.host = Host(libPrefix)
  427. Carla.host.set_callback_function(callbackFunction)
  428. Carla.host.set_option(OPTION_PROCESS_NAME, 0, "carla")
  429. # Set bridge paths
  430. if carla_bridge_native:
  431. Carla.host.set_option(OPTION_PATH_BRIDGE_NATIVE, 0, carla_bridge_native)
  432. if carla_bridge_posix32:
  433. Carla.host.set_option(OPTION_PATH_BRIDGE_POSIX32, 0, carla_bridge_posix32)
  434. if carla_bridge_posix64:
  435. Carla.host.set_option(OPTION_PATH_BRIDGE_POSIX64, 0, carla_bridge_posix64)
  436. if carla_bridge_win32:
  437. Carla.host.set_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32)
  438. if carla_bridge_win64:
  439. Carla.host.set_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64)
  440. if WINDOWS:
  441. if carla_bridge_lv2_windows:
  442. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, carla_bridge_lv2_windows)
  443. if carla_bridge_vst_hwnd:
  444. Carla.host.set_option(OPTION_PATH_BRIDGE_VST_HWND, 0, carla_bridge_vst_hwnd)
  445. elif MACOS:
  446. if carla_bridge_lv2_cocoa:
  447. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_COCOA, 0, carla_bridge_lv2_cocoa)
  448. if carla_bridge_vst_cocoa:
  449. Carla.host.set_option(OPTION_PATH_BRIDGE_VST_COCOA, 0, carla_bridge_vst_cocoa)
  450. else:
  451. if carla_bridge_lv2_gtk2:
  452. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2)
  453. if carla_bridge_lv2_gtk3:
  454. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_GTK3, 0, carla_bridge_lv2_gtk3)
  455. if carla_bridge_lv2_qt4:
  456. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4)
  457. if carla_bridge_lv2_qt5:
  458. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_QT5, 0, carla_bridge_lv2_qt5)
  459. if carla_bridge_lv2_x11:
  460. Carla.host.set_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11)
  461. if carla_bridge_vst_x11:
  462. Carla.host.set_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11)
  463. # Create GUI and start engine
  464. Carla.gui = CarlaMainW()
  465. # Set-up custom signal handling
  466. #setUpSignals(Carla.gui)
  467. # Show GUI
  468. Carla.gui.show()
  469. # Load project file if set
  470. #if projectFilename:
  471. #Carla.gui.m_project_filename = projectFilename
  472. #Carla.gui.loadProjectLater()
  473. #Carla.gui.setWindowTitle("Carla - %s" % os.path.basename(projectFilename)) # FIXME - put in loadProject
  474. # App-Loop
  475. ret = app.exec_()
  476. # Exit properly
  477. sys.exit(ret)