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_host.py 43KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla host code
  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 doc/GPL.txt file.
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. try:
  20. from PyQt5.QtCore import QModelIndex, QTimer
  21. from PyQt5.QtGui import QPalette
  22. from PyQt5.QtWidgets import QApplication, QFileSystemModel, QMainWindow
  23. except:
  24. from PyQt4.QtCore import QModelIndex, QTimer
  25. from PyQt4.QtGui import QApplication, QFileSystemModel, QMainWindow, QPalette
  26. # ------------------------------------------------------------------------------------------------------------
  27. # Imports (Custom)
  28. import ui_carla_host
  29. from carla_database import *
  30. from carla_settings import *
  31. from carla_style import *
  32. from carla_widgets import *
  33. # ------------------------------------------------------------------------------------------------------------
  34. # PatchCanvas defines
  35. CANVAS_ANTIALIASING_SMALL = 1
  36. CANVAS_EYECANDY_SMALL = 1
  37. # ------------------------------------------------------------------------------------------------------------
  38. # Session Management support
  39. LADISH_APP_NAME = os.getenv("LADISH_APP_NAME")
  40. NSM_URL = os.getenv("NSM_URL")
  41. # ------------------------------------------------------------------------------------------------------------
  42. # Dummy widget
  43. class CarlaDummyW(object):
  44. def __init__(self, parent):
  45. object.__init__(self)
  46. # -----------------------------------------------------------------
  47. def getPluginCount(self):
  48. return 0
  49. # -----------------------------------------------------------------
  50. def addPlugin(self, pluginId, isProjectLoading):
  51. pass
  52. def removePlugin(self, pluginId):
  53. pass
  54. def renamePlugin(self, pluginId, newName):
  55. pass
  56. def removeAllPlugins(self):
  57. pass
  58. # -----------------------------------------------------------------
  59. def engineStarted(self):
  60. pass
  61. def engineStopped(self):
  62. pass
  63. def engineChanged(self):
  64. pass
  65. # -----------------------------------------------------------------
  66. def idleFast(self):
  67. pass
  68. def idleSlow(self):
  69. pass
  70. # -----------------------------------------------------------------
  71. def saveSettings(self, settings):
  72. pass
  73. # ------------------------------------------------------------------------------------------------------------
  74. # Host Window
  75. class HostWindow(QMainWindow):
  76. # signals
  77. DebugCallback = pyqtSignal(int, int, int, float, str)
  78. PluginAddedCallback = pyqtSignal(int)
  79. PluginRemovedCallback = pyqtSignal(int)
  80. PluginRenamedCallback = pyqtSignal(int, str)
  81. ParameterValueChangedCallback = pyqtSignal(int, int, float)
  82. ParameterDefaultChangedCallback = pyqtSignal(int, int, float)
  83. ParameterMidiChannelChangedCallback = pyqtSignal(int, int, int)
  84. ParameterMidiCcChangedCallback = pyqtSignal(int, int, int)
  85. ProgramChangedCallback = pyqtSignal(int, int)
  86. MidiProgramChangedCallback = pyqtSignal(int, int)
  87. NoteOnCallback = pyqtSignal(int, int, int, int)
  88. NoteOffCallback = pyqtSignal(int, int, int)
  89. ShowGuiCallback = pyqtSignal(int, int)
  90. UpdateCallback = pyqtSignal(int)
  91. ReloadInfoCallback = pyqtSignal(int)
  92. ReloadParametersCallback = pyqtSignal(int)
  93. ReloadProgramsCallback = pyqtSignal(int)
  94. ReloadAllCallback = pyqtSignal(int)
  95. PatchbayClientAddedCallback = pyqtSignal(int, int, str)
  96. PatchbayClientRemovedCallback = pyqtSignal(int, str)
  97. PatchbayClientRenamedCallback = pyqtSignal(int, str)
  98. PatchbayPortAddedCallback = pyqtSignal(int, int, int, str)
  99. PatchbayPortRemovedCallback = pyqtSignal(int, int, str)
  100. PatchbayPortRenamedCallback = pyqtSignal(int, int, str)
  101. PatchbayConnectionAddedCallback = pyqtSignal(int, int, int)
  102. PatchbayConnectionRemovedCallback = pyqtSignal(int)
  103. PatchbayIconChangedCallback = pyqtSignal(int, int)
  104. BufferSizeChangedCallback = pyqtSignal(int)
  105. SampleRateChangedCallback = pyqtSignal(float)
  106. ProcessModeChangedCallback = pyqtSignal(int)
  107. EngineStartedCallback = pyqtSignal(str)
  108. EngineStoppedChangedCallback = pyqtSignal()
  109. NSM_AnnounceCallback = pyqtSignal(str)
  110. NSM_OpenCallback = pyqtSignal(str)
  111. NSM_SaveCallback = pyqtSignal()
  112. ErrorCallback = pyqtSignal(str)
  113. QuitCallback = pyqtSignal()
  114. SIGTERM = pyqtSignal()
  115. SIGUSR1 = pyqtSignal()
  116. def __init__(self, parent):
  117. QMainWindow.__init__(self, parent)
  118. self.ui = ui_carla_host.Ui_CarlaHostW()
  119. self.ui.setupUi(self)
  120. if False:
  121. Carla.gui = self
  122. self.fContainer = CarlaDummyW(self)
  123. # -------------------------------------------------------------
  124. # Set callback
  125. Carla.host.set_engine_callback(EngineCallback)
  126. # -------------------------------------------------------------
  127. # Internal stuff
  128. self.fBufferSize = 0
  129. self.fSampleRate = 0.0
  130. self.fIdleTimerFast = 0
  131. self.fIdleTimerSlow = 0
  132. self.fIsProjectLoading = False
  133. self.fProjectFilename = ""
  134. self.fLadspaRdfNeedsUpdate = True
  135. self.fLadspaRdfList = []
  136. self.fLastTransportFrame = 0
  137. self.fLastTransportState = False
  138. self.fTextTransport = ""
  139. self.fSavedSettings = {}
  140. if LADISH_APP_NAME:
  141. self.fClientName = LADISH_APP_NAME
  142. self.fSessionManagerName = "LADISH"
  143. elif NSM_URL:
  144. self.fClientName = "Carla.tmp"
  145. self.fSessionManagerName = "Non Session Manager"
  146. else:
  147. self.fClientName = "Carla"
  148. self.fSessionManagerName = ""
  149. # -------------------------------------------------------------
  150. # Load Settings
  151. self.loadSettings(True)
  152. # -------------------------------------------------------------
  153. # Set up GUI (engine stopped)
  154. if Carla.isPlugin:
  155. self.ui.act_file_new.setEnabled(False)
  156. self.ui.act_file_open.setEnabled(False)
  157. self.ui.act_engine_start.setEnabled(False)
  158. self.ui.act_engine_stop.setEnabled(False)
  159. self.ui.menu_Engine.setEnabled(False)
  160. else:
  161. self.ui.act_engine_start.setEnabled(True)
  162. self.ui.act_file_save.setEnabled(False)
  163. self.ui.act_file_save_as.setEnabled(False)
  164. self.ui.act_engine_stop.setEnabled(False)
  165. self.ui.act_plugin_remove_all.setEnabled(False)
  166. self.ui.menu_PluginMacros.setEnabled(False)
  167. self.ui.menu_Canvas.setEnabled(False)
  168. self.setTransportMenuEnabled(False)
  169. # -------------------------------------------------------------
  170. # Set up GUI (right panel)
  171. self.fDirModel = QFileSystemModel(self)
  172. self.fDirModel.setNameFilters(cString(Carla.host.get_supported_file_types()).split(";"))
  173. self.fDirModel.setRootPath(HOME)
  174. self.ui.fileTreeView.setModel(self.fDirModel)
  175. self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME))
  176. self.ui.fileTreeView.setColumnHidden(1, True)
  177. self.ui.fileTreeView.setColumnHidden(2, True)
  178. self.ui.fileTreeView.setColumnHidden(3, True)
  179. self.ui.fileTreeView.setHeaderHidden(True)
  180. self.setProperWindowTitle()
  181. # -------------------------------------------------------------
  182. # Connect actions to functions
  183. self.ui.act_file_new.triggered.connect(self.slot_fileNew)
  184. self.ui.act_file_open.triggered.connect(self.slot_fileOpen)
  185. self.ui.act_file_save.triggered.connect(self.slot_fileSave)
  186. self.ui.act_file_save_as.triggered.connect(self.slot_fileSaveAs)
  187. self.ui.act_engine_start.triggered.connect(self.slot_engineStart)
  188. self.ui.act_engine_stop.triggered.connect(self.slot_engineStop)
  189. self.ui.act_plugin_add.triggered.connect(self.slot_pluginAdd)
  190. self.ui.act_plugin_add2.triggered.connect(self.slot_pluginAdd)
  191. self.ui.act_plugin_remove_all.triggered.connect(self.slot_pluginRemoveAll)
  192. self.ui.act_transport_play.triggered.connect(self.slot_transportPlayPause)
  193. self.ui.act_transport_stop.triggered.connect(self.slot_transportStop)
  194. self.ui.act_transport_backwards.triggered.connect(self.slot_transportBackwards)
  195. self.ui.act_transport_forwards.triggered.connect(self.slot_transportForwards)
  196. self.ui.act_help_about.triggered.connect(self.slot_aboutCarla)
  197. self.ui.act_help_about_qt.triggered.connect(self.slot_aboutQt)
  198. self.ui.cb_disk.currentIndexChanged.connect(self.slot_diskFolderChanged)
  199. self.ui.b_disk_add.clicked.connect(self.slot_diskFolderAdd)
  200. self.ui.b_disk_remove.clicked.connect(self.slot_diskFolderRemove)
  201. self.ui.fileTreeView.doubleClicked.connect(self.slot_fileTreeDoubleClicked)
  202. self.DebugCallback.connect(self.slot_handleDebugCallback)
  203. self.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback)
  204. self.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback)
  205. self.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback)
  206. self.BufferSizeChangedCallback.connect(self.slot_handleBufferSizeChangedCallback)
  207. self.SampleRateChangedCallback.connect(self.slot_handleSampleRateChangedCallback)
  208. self.EngineStartedCallback.connect(self.slot_handleEngineStartedCallback)
  209. self.EngineStoppedChangedCallback.connect(self.slot_handleEngineStoppedCallback)
  210. #self.NSM_AnnounceCallback.connect(self.slot_handleNSM_AnnounceCallback)
  211. #self.NSM_OpenCallback.connect(self.slot_handleNSM_OpenCallback)
  212. #self.NSM_SaveCallback.connect(self.slot_handleNSM_SaveCallback)
  213. #self.ErrorCallback.connect(self.slot_handleErrorCallback)
  214. #self.QuitCallback.connect(self.slot_handleQuitCallback)
  215. self.SIGUSR1.connect(self.slot_handleSIGUSR1)
  216. self.SIGTERM.connect(self.slot_handleSIGTERM)
  217. # -------------------------------------------------------------
  218. # Final setup
  219. if Carla.isPlugin:
  220. QTimer.singleShot(0, self.slot_engineStart)
  221. elif NSM_URL:
  222. Carla.host.nsm_ready()
  223. # -----------------------------------------------------------------
  224. # Called by containers
  225. def openSettingsWindow(self, hasCanvas, hasCanvasGL):
  226. dialog = CarlaSettingsW(self, hasCanvas, hasCanvasGL)
  227. return dialog.exec_()
  228. def setupContainer(self, showMiniCanvas):
  229. if showMiniCanvas:
  230. CARLA_DEFAULT_CANVAS_WIDTH = 3100
  231. CARLA_DEFAULT_CANVAS_HEIGHT = 2400
  232. self.ui.miniCanvasPreview.setRealParent(self)
  233. #self.ui.miniCanvasPreview.setViewTheme(patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color())
  234. self.ui.miniCanvasPreview.init(self.fContainer.scene, CARLA_DEFAULT_CANVAS_WIDTH, CARLA_DEFAULT_CANVAS_HEIGHT, self.fSavedSettings["UseCustomMiniCanvasPaint"])
  235. else:
  236. self.ui.miniCanvasPreview.hide()
  237. self.ui.mainwidget.hide()
  238. self.ui.splitter.insertWidget(0, self.fContainer)
  239. del self.ui.mainwidget
  240. # -----------------------------------------------------------------
  241. # Internal stuff (files)
  242. def loadProjectNow(self):
  243. if not self.fProjectFilename:
  244. return qCritical("ERROR: loading project without filename set")
  245. # TESTING
  246. if not Carla.host.is_engine_running():
  247. self.slot_engineStart()
  248. self.fIsProjectLoading = True
  249. Carla.host.load_project(self.fProjectFilename)
  250. self.fIsProjectLoading = False
  251. @pyqtSlot()
  252. def slot_loadProjectNow(self):
  253. self.loadProjectNow()
  254. def loadProjectLater(self, filename):
  255. self.fProjectFilename = filename
  256. self.setProperWindowTitle()
  257. QTimer.singleShot(0, self.slot_loadProjectNow)
  258. def saveProjectNow(self):
  259. if not self.fProjectFilename:
  260. return qCritical("ERROR: saving project without filename set")
  261. Carla.host.save_project(self.fProjectFilename)
  262. # -----------------------------------------------------------------
  263. # Internal stuff (engine)
  264. def setEngineSettings(self, settings = None):
  265. if Carla.isPlugin:
  266. return "Plugin"
  267. if settings is None: settings = QSettings()
  268. forceStereo = settings.value("Engine/ForceStereo", CARLA_DEFAULT_FORCE_STEREO, type=bool)
  269. preferPluginBridges = settings.value("Engine/PreferPluginBridges", CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool)
  270. preferUiBridges = settings.value("Engine/PreferUiBridges", CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool)
  271. uisAlwaysOnTop = settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_UIS_ALWAYS_ON_TOP, type=bool)
  272. uiBridgesTimeout = settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_UI_BRIDGES_TIMEOUT, type=int)
  273. Carla.maxParameters = settings.value("Engine/MaxParameters", CARLA_DEFAULT_MAX_PARAMETERS, type=int)
  274. audioDriver = settings.value("Engine/AudioDriver", CARLA_DEFAULT_AUDIO_DRIVER, type=str)
  275. if audioDriver == "JACK":
  276. #transportMode = settings.value("Engine/TransportMode", TRANSPORT_MODE_JACK, type=int)
  277. transportMode = TRANSPORT_MODE_JACK
  278. else:
  279. transportMode = TRANSPORT_MODE_INTERNAL
  280. audioNumPeriods = settings.value("Engine/AudioBufferSize", CARLA_DEFAULT_AUDIO_NUM_PERIODS, type=int)
  281. audioBufferSize = settings.value("Engine/AudioBufferSize", CARLA_DEFAULT_AUDIO_BUFFER_SIZE, type=int)
  282. audioSampleRate = settings.value("Engine/AudioSampleRate", CARLA_DEFAULT_AUDIO_SAMPLE_RATE, type=int)
  283. audioDevice = settings.value("Engine/AudioDevice", "", type=str)
  284. Carla.host.set_engine_option(OPTION_AUDIO_NUM_PERIODS, audioNumPeriods, "")
  285. Carla.host.set_engine_option(OPTION_AUDIO_BUFFER_SIZE, audioBufferSize, "")
  286. Carla.host.set_engine_option(OPTION_AUDIO_SAMPLE_RATE, audioSampleRate, "")
  287. Carla.host.set_engine_option(OPTION_AUDIO_DEVICE, 0, audioDevice)
  288. if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK:
  289. forceStereo = True
  290. elif Carla.processMode == PROCESS_MODE_MULTIPLE_CLIENTS and LADISH_APP_NAME:
  291. print("LADISH detected but using multiple clients (not allowed), forcing single client now")
  292. Carla.processMode = PROCESS_MODE_SINGLE_CLIENT
  293. Carla.host.set_engine_option(OPTION_FORCE_STEREO, forceStereo, "")
  294. Carla.host.set_engine_option(OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "")
  295. Carla.host.set_engine_option(OPTION_PREFER_UI_BRIDGES, preferUiBridges, "")
  296. Carla.host.set_engine_option(OPTION_UIS_ALWAYS_ON_TOP, uisAlwaysOnTop, "")
  297. Carla.host.set_engine_option(OPTION_UI_BRIDGES_TIMEOUT, uiBridgesTimeout, "")
  298. Carla.host.set_engine_option(OPTION_PROCESS_MODE, Carla.processMode, "")
  299. Carla.host.set_engine_option(OPTION_MAX_PARAMETERS, Carla.maxParameters, "")
  300. Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, transportMode, "")
  301. return audioDriver
  302. def startEngine(self):
  303. audioDriver = self.setEngineSettings()
  304. if not Carla.host.engine_init(audioDriver, self.fClientName):
  305. #if self.fFirstEngineInit:
  306. #self.fFirstEngineInit = False
  307. #return
  308. audioError = cString(Carla.host.get_last_error())
  309. if audioError:
  310. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver, audioError)))
  311. else:
  312. QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver))
  313. return
  314. self.fBufferSize = Carla.host.get_buffer_size()
  315. self.fSampleRate = Carla.host.get_sample_rate()
  316. #self.fFirstEngineInit = False
  317. # Peaks and TimeInfo
  318. self.fIdleTimerFast = self.startTimer(30) #self.fSavedSettings["Main/RefreshInterval"])
  319. # LEDs and edit dialog parameters
  320. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  321. def stopEngine(self):
  322. if self.fContainer.getPluginCount() > 0:
  323. 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"
  324. "Do you want to do this now?"),
  325. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  326. if ask != QMessageBox.Yes:
  327. return
  328. self.ui.act_plugin_remove_all.setEnabled(False)
  329. self.fContainer.removeAllPlugins()
  330. if Carla.host.is_engine_running() and not Carla.host.engine_close():
  331. print(cString(Carla.host.get_last_error()))
  332. self.fBufferSize = 0
  333. self.fSampleRate = 0.0
  334. if self.fIdleTimerFast != 0:
  335. self.killTimer(self.fIdleTimerFast)
  336. self.fIdleTimerFast = 0
  337. if self.fIdleTimerSlow != 0:
  338. self.killTimer(self.fIdleTimerSlow)
  339. self.fIdleTimerSlow = 0
  340. # -----------------------------------------------------------------
  341. # Internal stuff (plugins)
  342. def getExtraStuff(self, plugin):
  343. ptype = plugin['type']
  344. if ptype == PLUGIN_LADSPA:
  345. uniqueId = plugin['uniqueId']
  346. self.maybeLoadRDFs()
  347. for rdfItem in self.fLadspaRdfList:
  348. if rdfItem.UniqueID == uniqueId:
  349. return pointer(rdfItem)
  350. elif ptype in (PLUGIN_GIG, PLUGIN_SF2, PLUGIN_SFZ):
  351. if plugin['name'].lower().endswith(" (16 outputs)"):
  352. # return a dummy non-null pointer
  353. INTPOINTER = POINTER(c_int)
  354. int1 = c_int(0x1)
  355. addr = addressof(int1)
  356. return cast(addr, INTPOINTER)
  357. return c_nullptr
  358. def maybeLoadRDFs(self):
  359. if not self.fLadspaRdfNeedsUpdate:
  360. return
  361. self.fLadspaRdfNeedsUpdate = False
  362. self.fLadspaRdfList = []
  363. if not haveLRDF:
  364. return
  365. settingsDir = os.path.join(HOME, ".config", "falkTX")
  366. frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db")
  367. if os.path.exists(frLadspaFile):
  368. frLadspa = open(frLadspaFile, 'r')
  369. try:
  370. self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa))
  371. except:
  372. pass
  373. frLadspa.close()
  374. def setLoadRDFsNeeded(self):
  375. self.fLadspaRdfNeedsUpdate = True
  376. # -----------------------------------------------------------------
  377. # Internal stuff (transport)
  378. def refreshTransport(self, forced = False):
  379. if not Carla.host.is_engine_running():
  380. return
  381. if self.fSampleRate == 0.0:
  382. return
  383. timeInfo = Carla.host.get_transport_info()
  384. playing = bool(timeInfo['playing'])
  385. frame = int(timeInfo['frame'])
  386. if playing != self.fLastTransportState or forced:
  387. if playing:
  388. icon = getIcon("media-playback-pause")
  389. self.ui.act_transport_play.setChecked(True)
  390. self.ui.act_transport_play.setIcon(icon)
  391. self.ui.act_transport_play.setText(self.tr("&Pause"))
  392. else:
  393. icon = getIcon("media-playback-start")
  394. self.ui.act_transport_play.setChecked(False)
  395. self.ui.act_transport_play.setIcon(icon)
  396. self.ui.act_transport_play.setText(self.tr("&Play"))
  397. self.fLastTransportState = playing
  398. if frame != self.fLastTransportFrame or forced:
  399. time = frame / self.fSampleRate
  400. secs = time % 60
  401. mins = (time / 60) % 60
  402. hrs = (time / 3600) % 60
  403. self.fTextTransport = "Transport %s, at %02i:%02i:%02i" % ("playing" if playing else "stopped", hrs, mins, secs)
  404. self.fLastTransportFrame = frame
  405. def setTransportMenuEnabled(self, enabled):
  406. self.ui.act_transport_play.setEnabled(enabled)
  407. self.ui.act_transport_stop.setEnabled(enabled)
  408. self.ui.act_transport_backwards.setEnabled(enabled)
  409. self.ui.act_transport_forwards.setEnabled(enabled)
  410. self.ui.menu_Transport.setEnabled(enabled)
  411. # -----------------------------------------------------------------
  412. # Internal stuff (settings)
  413. def loadSettings(self, firstTime):
  414. settings = QSettings()
  415. if firstTime:
  416. self.restoreGeometry(settings.value("Geometry", ""))
  417. showToolbar = settings.value("ShowToolbar", True, type=bool)
  418. self.ui.act_settings_show_toolbar.setChecked(showToolbar)
  419. self.ui.toolBar.setVisible(showToolbar)
  420. #if settings.contains("SplitterState"):
  421. #self.ui.splitter.restoreState(settings.value("SplitterState", ""))
  422. #else:
  423. self.ui.splitter.setSizes([99999, 210])
  424. diskFolders = toList(settings.value("DiskFolders", [HOME]))
  425. self.ui.cb_disk.setItemData(0, HOME)
  426. for i in range(len(diskFolders)):
  427. if i == 0: continue
  428. folder = diskFolders[i]
  429. self.ui.cb_disk.addItem(os.path.basename(folder), folder)
  430. if MACOS and not settings.value("Main/UseProTheme", True, type=bool):
  431. self.setUnifiedTitleAndToolBarOnMac(True)
  432. # ---------------------------------------------
  433. # plugin checks
  434. if settings.value("Engine/DisableChecks", False, type=bool):
  435. os.environ["CARLA_DISCOVERY_NO_PROCESSING_CHECKS"] = "true"
  436. elif os.getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"):
  437. os.environ.pop("CARLA_DISCOVERY_NO_PROCESSING_CHECKS")
  438. # ---------------------------------------------
  439. if not Carla.isPlugin:
  440. # engine
  441. self.setEngineSettings(settings)
  442. # plugin paths
  443. LADSPA_PATH = toList(settings.value("Paths/LADSPA", Carla.DEFAULT_LADSPA_PATH))
  444. DSSI_PATH = toList(settings.value("Paths/DSSI", Carla.DEFAULT_DSSI_PATH))
  445. LV2_PATH = toList(settings.value("Paths/LV2", Carla.DEFAULT_LV2_PATH))
  446. VST_PATH = toList(settings.value("Paths/VST", Carla.DEFAULT_VST_PATH))
  447. AU_PATH = toList(settings.value("Paths/AU", Carla.DEFAULT_AU_PATH))
  448. CSOUND_PATH = toList(settings.value("Paths/CSOUND", Carla.DEFAULT_CSOUND_PATH))
  449. GIG_PATH = toList(settings.value("Paths/GIG", Carla.DEFAULT_GIG_PATH))
  450. SF2_PATH = toList(settings.value("Paths/SF2", Carla.DEFAULT_SF2_PATH))
  451. SFZ_PATH = toList(settings.value("Paths/SFZ", Carla.DEFAULT_SFZ_PATH))
  452. os.environ["LADSPA_PATH"] = splitter.join(LADSPA_PATH)
  453. os.environ["DSSI_PATH"] = splitter.join(DSSI_PATH)
  454. os.environ["LV2_PATH"] = splitter.join(LV2_PATH)
  455. os.environ["VST_PATH"] = splitter.join(VST_PATH)
  456. os.environ["AU_PATH"] = splitter.join(AU_PATH)
  457. os.environ["CSOUND_PATH"] = splitter.join(CSOUND_PATH)
  458. os.environ["GIG_PATH"] = splitter.join(GIG_PATH)
  459. os.environ["SF2_PATH"] = splitter.join(SF2_PATH)
  460. os.environ["SFZ_PATH"] = splitter.join(SFZ_PATH)
  461. # ---------------------------------------------
  462. # TODO
  463. self.fSavedSettings = {
  464. "Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", HOME, type=str),
  465. "Main/RefreshInterval": settings.value("Main/RefreshInterval", 50, type=int),
  466. CARLA_KEY_CANVAS_THEME: settings.value(CARLA_KEY_CANVAS_THEME, CARLA_DEFAULT_CANVAS_THEME, type=str),
  467. CARLA_KEY_CANVAS_SIZE: settings.value(CARLA_KEY_CANVAS_SIZE, CARLA_DEFAULT_CANVAS_SIZE, type=str),
  468. CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS: settings.value(CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS, CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS, type=bool),
  469. CARLA_KEY_CANVAS_USE_BEZIER_LINES: settings.value(CARLA_KEY_CANVAS_USE_BEZIER_LINES, CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES, type=bool),
  470. CARLA_KEY_CANVAS_EYE_CANDY: settings.value(CARLA_KEY_CANVAS_EYE_CANDY, CARLA_DEFAULT_CANVAS_EYE_CANDY, type=int),
  471. CARLA_KEY_CANVAS_USE_OPENGL: settings.value(CARLA_KEY_CANVAS_USE_OPENGL, CARLA_DEFAULT_CANVAS_USE_OPENGL, type=bool),
  472. CARLA_KEY_CANVAS_ANTIALIASING: settings.value(CARLA_KEY_CANVAS_ANTIALIASING, CARLA_DEFAULT_CANVAS_ANTIALIASING, type=int),
  473. CARLA_KEY_CANVAS_HQ_ANTIALIASING: settings.value(CARLA_KEY_CANVAS_HQ_ANTIALIASING, CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING, type=bool),
  474. "UseCustomMiniCanvasPaint": (settings.value("Main/UseProTheme", True, type=bool) and
  475. settings.value("Main/ProThemeColor", "Black", type=str).lower() == "black")
  476. }
  477. # ---------------------------------------------
  478. if self.fIdleTimerFast != 0:
  479. self.killTimer(self.fIdleTimerFast)
  480. self.fIdleTimerFast = self.startTimer(30) #self.fSavedSettings["Main/RefreshInterval"])
  481. if self.fIdleTimerSlow != 0:
  482. self.killTimer(self.fIdleTimerSlow)
  483. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  484. def saveSettings(self):
  485. settings = QSettings()
  486. settings.setValue("Geometry", self.saveGeometry())
  487. settings.setValue("SplitterState", self.ui.splitter.saveState())
  488. settings.setValue("ShowToolbar", self.ui.toolBar.isVisible())
  489. #settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value())
  490. #settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value())
  491. diskFolders = []
  492. for i in range(self.ui.cb_disk.count()):
  493. diskFolders.append(self.ui.cb_disk.itemData(i))
  494. settings.setValue("DiskFolders", diskFolders)
  495. self.fContainer.saveSettings(settings)
  496. # -----------------------------------------------------------------
  497. # Internal stuff (gui)
  498. def setProperWindowTitle(self):
  499. title = self.fClientName
  500. if self.fProjectFilename:
  501. title += " - %s" % os.path.basename(self.fProjectFilename)
  502. if self.fSessionManagerName:
  503. title += " (%s)" % self.fSessionManagerName
  504. self.setWindowTitle(title)
  505. # -----------------------------------------------------------------
  506. @pyqtSlot()
  507. def slot_fileNew(self):
  508. self.fContainer.removeAllPlugins()
  509. self.fProjectFilename = ""
  510. self.setProperWindowTitle()
  511. @pyqtSlot()
  512. def slot_fileOpen(self):
  513. fileFilter = self.tr("Carla Project File (*.carxp)")
  514. filenameTry = QFileDialog.getOpenFileName(self, self.tr("Open Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)[0]
  515. if not filenameTry:
  516. return
  517. newFile = True
  518. if self.fContainer.getPluginCount() > 0:
  519. ask = QMessageBox.question(self, self.tr("Question"), self.tr("There are some plugins loaded, do you want to remove them now?"),
  520. QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
  521. newFile = ask == QMessageBox.Yes
  522. if newFile:
  523. self.fContainer.removeAllPlugins()
  524. self.fProjectFilename = filenameTry
  525. self.setProperWindowTitle()
  526. self.loadProjectNow()
  527. else:
  528. filenameOld = self.fProjectFilename
  529. self.fProjectFilename = filenameTry
  530. self.loadProjectNow()
  531. self.fProjectFilename = filenameOld
  532. @pyqtSlot()
  533. def slot_fileSave(self, saveAs=False):
  534. if self.fProjectFilename and not saveAs:
  535. return self.saveProjectNow()
  536. fileFilter = self.tr("Carla Project File (*.carxp)")
  537. filenameTry = QFileDialog.getSaveFileName(self, self.tr("Save Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter)[0]
  538. if not filenameTry:
  539. return
  540. if not filenameTry.endswith(".carxp"):
  541. filenameTry += ".carxp"
  542. if self.fProjectFilename != filenameTry:
  543. self.fProjectFilename = filenameTry
  544. self.setProperWindowTitle()
  545. self.saveProjectNow()
  546. @pyqtSlot()
  547. def slot_fileSaveAs(self):
  548. self.slot_fileSave(True)
  549. # -----------------------------------------------------------------
  550. @pyqtSlot()
  551. def slot_engineStart(self, doStart = True):
  552. if doStart: self.startEngine()
  553. check = Carla.host.is_engine_running()
  554. self.ui.menu_PluginMacros.setEnabled(check)
  555. self.ui.menu_Canvas.setEnabled(check)
  556. if not Carla.isPlugin:
  557. self.ui.act_file_save.setEnabled(check)
  558. self.ui.act_engine_start.setEnabled(not check)
  559. self.ui.act_engine_stop.setEnabled(check)
  560. if self.fSessionManagerName != "Non Session Manager":
  561. self.ui.act_file_open.setEnabled(check)
  562. self.ui.act_file_save_as.setEnabled(check)
  563. self.setTransportMenuEnabled(check)
  564. if check:
  565. if not Carla.isPlugin:
  566. self.refreshTransport(True)
  567. self.fContainer.engineStarted()
  568. @pyqtSlot()
  569. def slot_engineStop(self, doStop = True):
  570. if doStop: self.stopEngine()
  571. check = Carla.host.is_engine_running()
  572. self.ui.menu_PluginMacros.setEnabled(check)
  573. self.ui.menu_Canvas.setEnabled(check)
  574. if not Carla.isPlugin:
  575. self.ui.act_file_save.setEnabled(check)
  576. self.ui.act_engine_start.setEnabled(not check)
  577. self.ui.act_engine_stop.setEnabled(check)
  578. if self.fSessionManagerName != "Non Session Manager":
  579. self.ui.act_file_open.setEnabled(check)
  580. self.ui.act_file_save_as.setEnabled(check)
  581. self.setTransportMenuEnabled(check)
  582. if not check:
  583. self.fTextTransport = ""
  584. self.fContainer.engineStopped()
  585. # -----------------------------------------------------------------
  586. @pyqtSlot()
  587. def slot_pluginAdd(self):
  588. dialog = PluginDatabaseW(self)
  589. if not dialog.exec_():
  590. return
  591. if not Carla.host.is_engine_running():
  592. QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
  593. return
  594. btype = dialog.fRetPlugin['build']
  595. ptype = dialog.fRetPlugin['type']
  596. filename = dialog.fRetPlugin['binary']
  597. label = dialog.fRetPlugin['label']
  598. extraStuff = self.getExtraStuff(dialog.fRetPlugin)
  599. if not Carla.host.add_plugin(btype, ptype, filename, None, label, c_nullptr):
  600. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  601. return
  602. @pyqtSlot()
  603. def slot_pluginRemoveAll(self):
  604. self.ui.act_plugin_remove_all.setEnabled(False)
  605. self.fContainer.removeAllPlugins()
  606. Carla.host.remove_all_plugins()
  607. # -----------------------------------------------------------------
  608. @pyqtSlot(bool)
  609. def slot_transportPlayPause(self, toggled):
  610. if not Carla.host.is_engine_running():
  611. return
  612. if toggled:
  613. Carla.host.transport_play()
  614. else:
  615. Carla.host.transport_pause()
  616. self.refreshTransport()
  617. @pyqtSlot()
  618. def slot_transportStop(self):
  619. if not Carla.host.is_engine_running():
  620. return
  621. Carla.host.transport_pause()
  622. Carla.host.transport_relocate(0)
  623. self.refreshTransport()
  624. @pyqtSlot()
  625. def slot_transportBackwards(self):
  626. if not Carla.host.is_engine_running():
  627. return
  628. newFrame = Carla.host.get_current_transport_frame() - 100000
  629. if newFrame < 0:
  630. newFrame = 0
  631. Carla.host.transport_relocate(newFrame)
  632. @pyqtSlot()
  633. def slot_transportForwards(self):
  634. if not Carla.host.is_engine_running():
  635. return
  636. newFrame = Carla.host.get_current_transport_frame() + 100000
  637. Carla.host.transport_relocate(newFrame)
  638. # -----------------------------------------------------------------
  639. @pyqtSlot()
  640. def slot_aboutCarla(self):
  641. CarlaAboutW(self).exec_()
  642. @pyqtSlot()
  643. def slot_aboutQt(self):
  644. QApplication.instance().aboutQt()
  645. # -----------------------------------------------------------------
  646. @pyqtSlot(int)
  647. def slot_diskFolderChanged(self, index):
  648. if index < 0:
  649. return
  650. elif index == 0:
  651. filename = HOME
  652. self.ui.b_disk_remove.setEnabled(False)
  653. else:
  654. filename = self.ui.cb_disk.itemData(index)
  655. self.ui.b_disk_remove.setEnabled(True)
  656. self.fDirModel.setRootPath(filename)
  657. self.ui.fileTreeView.setRootIndex(self.fDirModel.index(filename))
  658. @pyqtSlot()
  659. def slot_diskFolderAdd(self):
  660. newPath = QFileDialog.getExistingDirectory(self, self.tr("New Folder"), "", QFileDialog.ShowDirsOnly)
  661. if newPath:
  662. if newPath[-1] == os.sep:
  663. newPath = newPath[:-1]
  664. self.ui.cb_disk.addItem(os.path.basename(newPath), newPath)
  665. self.ui.cb_disk.setCurrentIndex(self.ui.cb_disk.count()-1)
  666. self.ui.b_disk_remove.setEnabled(True)
  667. @pyqtSlot()
  668. def slot_diskFolderRemove(self):
  669. index = self.ui.cb_disk.currentIndex()
  670. if index <= 0:
  671. return
  672. self.ui.cb_disk.removeItem(index)
  673. if self.ui.cb_disk.currentIndex() == 0:
  674. self.ui.b_disk_remove.setEnabled(False)
  675. @pyqtSlot(QModelIndex)
  676. def slot_fileTreeDoubleClicked(self, modelIndex):
  677. filename = self.fDirModel.filePath(modelIndex)
  678. if not Carla.host.load_filename(filename):
  679. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"),
  680. self.tr("Failed to load file"),
  681. cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  682. # -----------------------------------------------------------------
  683. @pyqtSlot(int, int, int, float, str)
  684. def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
  685. print("DEBUG:", pluginId, value1, value2, value3, valueStr)
  686. #self.ui.pte_log.appendPlainText(valueStr.replace("", "DEBUG: ").replace("", "ERROR: ").replace("", "").replace("\n", ""))
  687. @pyqtSlot(int)
  688. def slot_handlePluginAddedCallback(self, pluginId):
  689. self.fContainer.addPlugin(pluginId, self.fIsProjectLoading)
  690. if self.fContainer.getPluginCount() == 1:
  691. self.ui.act_plugin_remove_all.setEnabled(True)
  692. @pyqtSlot(int)
  693. def slot_handlePluginRemovedCallback(self, pluginId):
  694. self.fContainer.removePlugin(pluginId)
  695. if self.fContainer.getPluginCount() == 0:
  696. self.ui.act_plugin_remove_all.setEnabled(False)
  697. @pyqtSlot(int, str)
  698. def slot_handlePluginRenamedCallback(self, pluginId, newName):
  699. self.fContainer.renamePlugin(pluginId, newName)
  700. @pyqtSlot(int)
  701. def slot_handleBufferSizeChangedCallback(self, newBufferSize):
  702. self.fBufferSize = newBufferSize
  703. self.fContainer.engineChanged()
  704. @pyqtSlot(float)
  705. def slot_handleSampleRateChangedCallback(self, newSampleRate):
  706. self.fSampleRate = newSampleRate
  707. self.fContainer.engineChanged()
  708. # -----------------------------------------------------------------
  709. @pyqtSlot(str)
  710. def slot_handleEngineStartedCallback(self, driverName):
  711. self.fBufferSize = Carla.host.get_buffer_size()
  712. self.fSampleRate = Carla.host.get_sample_rate()
  713. if self.fIdleTimerFast == 0:
  714. self.fIdleTimerFast = self.startTimer(30) #self.fSavedSettings["Main/RefreshInterval"])
  715. if self.fIdleTimerSlow == 0:
  716. self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2)
  717. self.slot_engineStart(False)
  718. @pyqtSlot()
  719. def slot_handleEngineStoppedCallback(self):
  720. self.fBufferSize = 0
  721. self.fSampleRate = 0.0
  722. if self.fIdleTimerFast != 0:
  723. self.killTimer(self.fIdleTimerFast)
  724. self.fIdleTimerFast = 0
  725. if self.fIdleTimerSlow != 0:
  726. self.killTimer(self.fIdleTimerSlow)
  727. self.fIdleTimerSlow = 0
  728. if self.fContainer.getPluginCount() > 0:
  729. self.ui.act_plugin_remove_all.setEnabled(False)
  730. self.fContainer.removeAllPlugins() # FIXME?
  731. self.slot_engineStop(False)
  732. # -----------------------------------------------------------------
  733. @pyqtSlot()
  734. def slot_handleSIGUSR1(self):
  735. print("Got SIGUSR1 -> Saving project now")
  736. #QTimer.singleShot(0, self, SLOT("slot_fileSave)
  737. @pyqtSlot()
  738. def slot_handleSIGTERM(self):
  739. print("Got SIGTERM -> Closing now")
  740. self.close()
  741. # -----------------------------------------------------------------
  742. def timerEvent(self, event):
  743. if event.timerId() == self.fIdleTimerFast:
  744. if not Carla.isPlugin:
  745. Carla.host.engine_idle()
  746. self.refreshTransport()
  747. self.fContainer.idleFast()
  748. elif event.timerId() == self.fIdleTimerSlow:
  749. self.fContainer.idleSlow()
  750. QMainWindow.timerEvent(self, event)
  751. def closeEvent(self, event):
  752. if self.fIdleTimerFast != 0:
  753. self.killTimer(self.fIdleTimerFast)
  754. self.fIdleTimerFast = 0
  755. if self.fIdleTimerSlow != 0:
  756. self.killTimer(self.fIdleTimerSlow)
  757. self.fIdleTimerSlow = 0
  758. self.saveSettings()
  759. if Carla.host.is_engine_running():
  760. Carla.host.set_engine_about_to_close()
  761. self.ui.act_plugin_remove_all.setEnabled(False)
  762. self.fContainer.removeAllPlugins()
  763. self.stopEngine()
  764. QMainWindow.closeEvent(self, event)
  765. # ------------------------------------------------------------------------------------------------------------
  766. # Engine callback
  767. def EngineCallback(ptr, action, pluginId, value1, value2, value3, valueStr):
  768. if pluginId < 0 or not Carla.gui:
  769. return
  770. if action == CALLBACK_DEBUG:
  771. Carla.gui.DebugCallback.emit(pluginId, value1, value2, value3, cString(valueStr))
  772. elif action == CALLBACK_PLUGIN_ADDED:
  773. Carla.gui.PluginAddedCallback.emit(pluginId)
  774. elif action == CALLBACK_PLUGIN_REMOVED:
  775. Carla.gui.PluginRemovedCallback.emit(pluginId)
  776. elif action == CALLBACK_PLUGIN_RENAMED:
  777. Carla.gui.PluginRenamedCallback.emit(pluginId, valueStr)
  778. elif action == CALLBACK_PARAMETER_VALUE_CHANGED:
  779. Carla.gui.ParameterValueChangedCallback.emit(pluginId, value1, value3)
  780. elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED:
  781. Carla.gui.ParameterDefaultChangedCallback.emit(pluginId, value1, value3)
  782. elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  783. Carla.gui.ParameterMidiChannelChangedCallback.emit(pluginId, value1, value2)
  784. elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  785. Carla.gui.ParameterMidiCcChangedCallback.emit(pluginId, value1, value2)
  786. elif action == CALLBACK_PROGRAM_CHANGED:
  787. Carla.gui.ProgramChangedCallback.emit(pluginId, value1)
  788. elif action == CALLBACK_MIDI_PROGRAM_CHANGED:
  789. Carla.gui.MidiProgramChangedCallback.emit(pluginId, value1)
  790. elif action == CALLBACK_NOTE_ON:
  791. Carla.gui.NoteOnCallback.emit(pluginId, value1, value2, value3)
  792. elif action == CALLBACK_NOTE_OFF:
  793. Carla.gui.NoteOffCallback.emit(pluginId, value1, value2)
  794. elif action == CALLBACK_SHOW_GUI:
  795. Carla.gui.ShowGuiCallback.emit(pluginId, value1)
  796. elif action == CALLBACK_UPDATE:
  797. Carla.gui.UpdateCallback.emit(pluginId)
  798. elif action == CALLBACK_RELOAD_INFO:
  799. Carla.gui.ReloadInfoCallback.emit(pluginId)
  800. elif action == CALLBACK_RELOAD_PARAMETERS:
  801. Carla.gui.ReloadParametersCallback.emit(pluginId)
  802. elif action == CALLBACK_RELOAD_PROGRAMS:
  803. Carla.gui.ReloadProgramsCallback.emit(pluginId)
  804. elif action == CALLBACK_RELOAD_ALL:
  805. Carla.gui.ReloadAllCallback.emit(pluginId)
  806. elif action == CALLBACK_PATCHBAY_CLIENT_ADDED:
  807. Carla.gui.PatchbayClientAddedCallback.emit(value1, value2, cString(valueStr))
  808. elif action == CALLBACK_PATCHBAY_CLIENT_REMOVED:
  809. Carla.gui.PatchbayClientRemovedCallback.emit(value1, cString(valueStr))
  810. elif action == CALLBACK_PATCHBAY_CLIENT_RENAMED:
  811. Carla.gui.PatchbayClientRenamedCallback.emit(value1, cString(valueStr))
  812. elif action == CALLBACK_PATCHBAY_PORT_ADDED:
  813. Carla.gui.PatchbayPortAddedCallback.emit(value1, value2, int(value3), cString(valueStr))
  814. elif action == CALLBACK_PATCHBAY_PORT_REMOVED:
  815. Carla.gui.PatchbayPortRemovedCallback.emit(value1, value2, cString(valueStr))
  816. elif action == CALLBACK_PATCHBAY_PORT_RENAMED:
  817. Carla.gui.PatchbayPortRenamedCallback.emit(value1, value2, cString(valueStr))
  818. elif action == CALLBACK_PATCHBAY_CONNECTION_ADDED:
  819. Carla.gui.PatchbayConnectionAddedCallback.emit(value1, value2, value3)
  820. elif action == CALLBACK_PATCHBAY_CONNECTION_REMOVED:
  821. Carla.gui.PatchbayConnectionRemovedCallback.emit(value1)
  822. elif action == CALLBACK_PATCHBAY_ICON_CHANGED:
  823. Carla.gui.PatchbayIconChangedCallback.emit(value1, value2)
  824. elif action == CALLBACK_BUFFER_SIZE_CHANGED:
  825. Carla.gui.BufferSizeChangedCallback.emit(value1)
  826. elif action == CALLBACK_SAMPLE_RATE_CHANGED:
  827. Carla.gui.SampleRateChangedCallback.emit(value3)
  828. elif action == CALLBACK_PROCESS_MODE_CHANGED:
  829. Carla.gui.ProcessModeChangedCallback.emit(value1)
  830. elif action == CALLBACK_ENGINE_STARTED:
  831. Carla.gui.EngineStartedCallback.emit(cString(valueStr))
  832. elif action == CALLBACK_ENGINE_STOPPED:
  833. Carla.gui.EngineStoppedChangedCallback.emit()
  834. elif action == CALLBACK_NSM_ANNOUNCE:
  835. Carla.gui.NSM_AnnounceCallback.emit(cString(valueStr))
  836. elif action == CALLBACK_NSM_OPEN:
  837. Carla.gui.NSM_OpenCallback.emit(cString(valueStr))
  838. elif action == CALLBACK_NSM_SAVE:
  839. Carla.gui.NSM_SaveCallback.emit()
  840. elif action == CALLBACK_ERROR:
  841. Carla.gui.ErrorCallback.emit(cString(valueStr))
  842. elif action == CALLBACK_QUIT:
  843. Carla.gui.QuitCallback.emit()