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.

723 lines
30KB

  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.QtWidgets import QApplication, QMainWindow
  21. except:
  22. from PyQt4.QtGui import QApplication, QMainWindow
  23. # ------------------------------------------------------------------------------------------------------------
  24. # Imports (Custom)
  25. import ui_carla_host
  26. from carla_database import *
  27. from carla_settings import *
  28. from carla_widgets import *
  29. # ------------------------------------------------------------------------------------------------------------
  30. # Dummy widget
  31. class CarlaDummyW(object):
  32. def __init__(self, parent):
  33. object.__init__(self)
  34. # -----------------------------------------------------------------
  35. def getPluginCount(self):
  36. return 0
  37. def getPlugin(self, pluginId):
  38. return None
  39. # -----------------------------------------------------------------
  40. def addPlugin(self, pluginId, isProjectLoading):
  41. pass
  42. def removePlugin(self, pluginId):
  43. pass
  44. def renamePlugin(self, pluginId, newName):
  45. pass
  46. def removeAllPlugins(self):
  47. pass
  48. # -----------------------------------------------------------------
  49. def setParameterValue(self, pluginId, index, value):
  50. pass
  51. def setParameterDefault(self, pluginId, index, value):
  52. pass
  53. def setParameterMidiChannel(self, pluginId, index, channel):
  54. pass
  55. def setParameterMidiCC(self, pluginId, index, cc):
  56. pass
  57. # -----------------------------------------------------------------
  58. def setProgram(self, pluginId, index):
  59. pass
  60. def setMidiProgram(self, pluginId, index):
  61. pass
  62. # -----------------------------------------------------------------
  63. def noteOn(self, pluginId, channel, note, velocity):
  64. pass
  65. def noteOff(self, pluginId, channel, note):
  66. pass
  67. # -----------------------------------------------------------------
  68. def setGuiState(self, pluginId, state):
  69. pass
  70. # -----------------------------------------------------------------
  71. def updateInfo(self, pluginId):
  72. pass
  73. def reloadInfo(self, pluginId):
  74. pass
  75. def reloadParameters(self, pluginId):
  76. pass
  77. def reloadPrograms(self, pluginId):
  78. pass
  79. def reloadAll(self, pluginId):
  80. pass
  81. # -----------------------------------------------------------------
  82. def patchbayClientAdded(self, clientId, clientIcon, clientName):
  83. pass
  84. def patchbayClientRemoved(self, clientId, clientName):
  85. pass
  86. def patchbayClientRenamed(self, clientId, newClientName):
  87. pass
  88. def patchbayPortAdded(self, clientId, portId, portFlags, portName):
  89. pass
  90. def patchbayPortRemoved(self, groupId, portId, fullPortName):
  91. pass
  92. def patchbayPortRenamed(self, groupId, portId, newPortName):
  93. pass
  94. def patchbayConnectionAdded(self, connectionId, portOutId, portInId):
  95. pass
  96. def patchbayConnectionRemoved(self, connectionId):
  97. pass
  98. def patchbayIconChanged(self, clientId, clientIcon):
  99. pass
  100. # -----------------------------------------------------------------
  101. def idleFast(self):
  102. pass
  103. def idleSlow(self):
  104. pass
  105. # ------------------------------------------------------------------------------------------------------------
  106. # Host Window
  107. class HostWindow(QMainWindow):
  108. # signals
  109. DebugCallback = pyqtSignal(int, int, int, float, str)
  110. PluginAddedCallback = pyqtSignal(int)
  111. PluginRemovedCallback = pyqtSignal(int)
  112. PluginRenamedCallback = pyqtSignal(int, str)
  113. ParameterValueChangedCallback = pyqtSignal(int, int, float)
  114. ParameterDefaultChangedCallback = pyqtSignal(int, int, float)
  115. ParameterMidiChannelChangedCallback = pyqtSignal(int, int, int)
  116. ParameterMidiCcChangedCallback = pyqtSignal(int, int, int)
  117. ProgramChangedCallback = pyqtSignal(int, int)
  118. MidiProgramChangedCallback = pyqtSignal(int, int)
  119. NoteOnCallback = pyqtSignal(int, int, int, int)
  120. NoteOffCallback = pyqtSignal(int, int, int)
  121. ShowGuiCallback = pyqtSignal(int, int)
  122. UpdateCallback = pyqtSignal(int)
  123. ReloadInfoCallback = pyqtSignal(int)
  124. ReloadParametersCallback = pyqtSignal(int)
  125. ReloadProgramsCallback = pyqtSignal(int)
  126. ReloadAllCallback = pyqtSignal(int)
  127. PatchbayClientAddedCallback = pyqtSignal(int, int, str)
  128. PatchbayClientRemovedCallback = pyqtSignal(int, str)
  129. PatchbayClientRenamedCallback = pyqtSignal(int, str)
  130. PatchbayPortAddedCallback = pyqtSignal(int, int, int, str)
  131. PatchbayPortRemovedCallback = pyqtSignal(int, int, str)
  132. PatchbayPortRenamedCallback = pyqtSignal(int, int, str)
  133. PatchbayConnectionAddedCallback = pyqtSignal(int, int, int)
  134. PatchbayConnectionRemovedCallback = pyqtSignal(int)
  135. PatchbayIconChangedCallback = pyqtSignal(int, int)
  136. BufferSizeChangedCallback = pyqtSignal(int)
  137. SampleRateChangedCallback = pyqtSignal(float)
  138. NSM_AnnounceCallback = pyqtSignal(str)
  139. NSM_OpenCallback = pyqtSignal(str)
  140. NSM_SaveCallback = pyqtSignal()
  141. ErrorCallback = pyqtSignal(str)
  142. QuitCallback = pyqtSignal()
  143. SIGTERM = pyqtSignal()
  144. SIGUSR1 = pyqtSignal()
  145. def __init__(self, parent):
  146. QMainWindow.__init__(self, parent)
  147. self.ui = ui_carla_host.Ui_CarlaHostW()
  148. self.ui.setupUi(self)
  149. # -------------------------------------------------------------
  150. # Set bridge paths
  151. if carla_bridge_native:
  152. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_NATIVE, 0, carla_bridge_native)
  153. if carla_bridge_posix32:
  154. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX32, 0, carla_bridge_posix32)
  155. if carla_bridge_posix64:
  156. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX64, 0, carla_bridge_posix64)
  157. if carla_bridge_win32:
  158. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32)
  159. if carla_bridge_win64:
  160. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64)
  161. if carla_bridge_lv2_external:
  162. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_EXTERNAL, 0, carla_bridge_lv2_external)
  163. if WINDOWS:
  164. if carla_bridge_lv2_windows:
  165. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, carla_bridge_lv2_windows)
  166. if carla_bridge_vst_hwnd:
  167. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_HWND, 0, carla_bridge_vst_hwnd)
  168. elif MACOS:
  169. if carla_bridge_lv2_cocoa:
  170. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_COCOA, 0, carla_bridge_lv2_cocoa)
  171. if carla_bridge_vst_mac:
  172. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_MAC, 0, carla_bridge_vst_mac)
  173. else:
  174. if carla_bridge_lv2_gtk2:
  175. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2)
  176. if carla_bridge_lv2_gtk3:
  177. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK3, 0, carla_bridge_lv2_gtk3)
  178. if carla_bridge_lv2_qt4:
  179. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4)
  180. if carla_bridge_lv2_qt5:
  181. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT5, 0, carla_bridge_lv2_qt5)
  182. if carla_bridge_lv2_x11:
  183. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11)
  184. if carla_bridge_vst_x11:
  185. Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11)
  186. # -------------------------------------------------------------
  187. # Set callback
  188. Carla.host.set_engine_callback(EngineCallback)
  189. # -------------------------------------------------------------
  190. # Set custom signal handling
  191. setUpSignals()
  192. # -------------------------------------------------------------
  193. # Internal stuff
  194. self.fIdleTimerFast = 0
  195. self.fIdleTimerSlow = 0
  196. self.fIsProjectLoading = False
  197. self.fLadspaRdfNeedsUpdate = True
  198. self.fLadspaRdfList = []
  199. self.fContainer = CarlaDummyW(self)
  200. # -------------------------------------------------------------
  201. # Connect actions to functions
  202. #self.connect(self.ui.act_file_new, SIGNAL("triggered()"), SLOT("slot_fileNew()"))
  203. #self.connect(self.ui.act_file_open, SIGNAL("triggered()"), SLOT("slot_fileOpen()"))
  204. #self.connect(self.ui.act_file_save, SIGNAL("triggered()"), SLOT("slot_fileSave()"))
  205. #self.connect(self.ui.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_fileSaveAs()"))
  206. ##self.connect(self.ui.act_file_export_lv2, SIGNAL("triggered()"), SLOT("slot_fileExportLv2Preset()"))
  207. #self.connect(self.ui.act_engine_start, SIGNAL("triggered()"), SLOT("slot_engineStart()"))
  208. #self.connect(self.ui.act_engine_stop, SIGNAL("triggered()"), SLOT("slot_engineStop()"))
  209. self.ui.act_plugin_add.triggered.connect(self.slot_pluginAdd)
  210. self.ui.act_plugin_add2.triggered.connect(self.slot_pluginAdd)
  211. self.ui.act_plugin_remove_all.triggered.connect(self.slot_pluginRemoveAll)
  212. #self.connect(self.ui.act_plugins_enable, SIGNAL("triggered()"), SLOT("slot_pluginsEnable()"))
  213. #self.connect(self.ui.act_plugins_disable, SIGNAL("triggered()"), SLOT("slot_pluginsDisable()"))
  214. #self.connect(self.ui.act_plugins_panic, SIGNAL("triggered()"), SLOT("slot_pluginsDisable()"))
  215. #self.connect(self.ui.act_plugins_volume100, SIGNAL("triggered()"), SLOT("slot_pluginsVolume100()"))
  216. #self.connect(self.ui.act_plugins_mute, SIGNAL("triggered()"), SLOT("slot_pluginsMute()"))
  217. #self.connect(self.ui.act_plugins_wet100, SIGNAL("triggered()"), SLOT("slot_pluginsWet100()"))
  218. #self.connect(self.ui.act_plugins_bypass, SIGNAL("triggered()"), SLOT("slot_pluginsBypass()"))
  219. #self.connect(self.ui.act_plugins_center, SIGNAL("triggered()"), SLOT("slot_pluginsCenter()"))
  220. #self.connect(self.ui.act_transport_play, SIGNAL("triggered(bool)"), SLOT("slot_transportPlayPause(bool)"))
  221. #self.connect(self.ui.act_transport_stop, SIGNAL("triggered()"), SLOT("slot_transportStop()"))
  222. #self.connect(self.ui.act_transport_backwards, SIGNAL("triggered()"), SLOT("slot_transportBackwards()"))
  223. #self.connect(self.ui.act_transport_forwards, SIGNAL("triggered()"), SLOT("slot_transportForwards()"))
  224. #self.ui.act_canvas_arrange.setEnabled(False) # TODO, later
  225. #self.connect(self.ui.act_canvas_arrange, SIGNAL("triggered()"), SLOT("slot_canvasArrange()"))
  226. #self.connect(self.ui.act_canvas_refresh, SIGNAL("triggered()"), SLOT("slot_canvasRefresh()"))
  227. #self.connect(self.ui.act_canvas_zoom_fit, SIGNAL("triggered()"), SLOT("slot_canvasZoomFit()"))
  228. #self.connect(self.ui.act_canvas_zoom_in, SIGNAL("triggered()"), SLOT("slot_canvasZoomIn()"))
  229. #self.connect(self.ui.act_canvas_zoom_out, SIGNAL("triggered()"), SLOT("slot_canvasZoomOut()"))
  230. #self.connect(self.ui.act_canvas_zoom_100, SIGNAL("triggered()"), SLOT("slot_canvasZoomReset()"))
  231. #self.connect(self.ui.act_canvas_print, SIGNAL("triggered()"), SLOT("slot_canvasPrint()"))
  232. #self.connect(self.ui.act_canvas_save_image, SIGNAL("triggered()"), SLOT("slot_canvasSaveImage()"))
  233. self.ui.act_settings_configure.triggered.connect(self.slot_configureCarla)
  234. self.ui.act_help_about.triggered.connect(self.slot_aboutCarla)
  235. self.ui.act_help_about_qt.triggered.connect(self.slot_aboutQt)
  236. #self.connect(self.ui.splitter, SIGNAL("splitterMoved.connect(self.slot_splitterMoved()"))
  237. #self.connect(self.ui.cb_disk, SIGNAL("currentIndexChanged.connect(self.slot_diskFolderChanged)
  238. #self.connect(self.ui.b_disk_add, SIGNAL("clicked()"), SLOT("slot_diskFolderAdd()"))
  239. #self.connect(self.ui.b_disk_remove, SIGNAL("clicked()"), SLOT("slot_diskFolderRemove()"))
  240. #self.connect(self.ui.fileTreeView, SIGNAL("doubleClicked(QModelIndex)"), SLOT("slot_fileTreeDoubleClicked(QModelIndex)"))
  241. #self.connect(self.ui.miniCanvasPreview, SIGNAL("miniCanvasMoved(double, double)"), SLOT("slot_miniCanvasMoved(double, double)"))
  242. #self.connect(self.ui.graphicsView.horizontalScrollBar(), SIGNAL("valueChanged.connect(self.slot_horizontalScrollBarChanged)
  243. #self.connect(self.ui.graphicsView.verticalScrollBar(), SIGNAL("valueChanged.connect(self.slot_verticalScrollBarChanged)
  244. #self.connect(self.scene, SIGNAL("sceneGroupMoved(int, int, QPointF)"), SLOT("slot_canvasItemMoved(int, int, QPointF)"))
  245. #self.connect(self.scene, SIGNAL("scaleChanged(double)"), SLOT("slot_canvasScaleChanged(double)"))
  246. self.DebugCallback.connect(self.slot_handleDebugCallback)
  247. self.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback)
  248. self.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback)
  249. self.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback)
  250. self.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback)
  251. self.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback)
  252. self.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback)
  253. self.ParameterMidiCcChangedCallback.connect(self.slot_handleParameterMidiCcChangedCallback)
  254. self.ProgramChangedCallback.connect(self.slot_handleProgramChangedCallback)
  255. self.MidiProgramChangedCallback.connect(self.slot_handleMidiProgramChangedCallback)
  256. self.NoteOnCallback.connect(self.slot_handleNoteOnCallback)
  257. self.NoteOffCallback.connect(self.slot_handleNoteOffCallback)
  258. self.ShowGuiCallback.connect(self.slot_handleShowGuiCallback)
  259. self.UpdateCallback.connect(self.slot_handleUpdateCallback)
  260. self.ReloadInfoCallback.connect(self.slot_handleReloadInfoCallback)
  261. self.ReloadParametersCallback.connect(self.slot_handleReloadParametersCallback)
  262. self.ReloadProgramsCallback.connect(self.slot_handleReloadProgramsCallback)
  263. self.ReloadAllCallback.connect(self.slot_handleReloadAllCallback)
  264. self.PatchbayClientAddedCallback.connect(self.slot_handlePatchbayClientAddedCallback)
  265. self.PatchbayClientRemovedCallback.connect(self.slot_handlePatchbayClientRemovedCallback)
  266. self.PatchbayClientRenamedCallback.connect(self.slot_handlePatchbayClientRenamedCallback)
  267. self.PatchbayPortAddedCallback.connect(self.slot_handlePatchbayPortAddedCallback)
  268. self.PatchbayPortRemovedCallback.connect(self.slot_handlePatchbayPortRemovedCallback)
  269. self.PatchbayPortRenamedCallback.connect(self.slot_handlePatchbayPortRenamedCallback)
  270. self.PatchbayConnectionAddedCallback.connect(self.slot_handlePatchbayConnectionAddedCallback)
  271. self.PatchbayConnectionRemovedCallback.connect(self.slot_handlePatchbayConnectionRemovedCallback)
  272. self.PatchbayIconChangedCallback.connect(self.slot_handlePatchbayIconChangedCallback)
  273. #self.BufferSizeChangedCallback.connect(self.slot_handleBufferSizeChangedCallback)
  274. #self.SampleRateChangedCallback(double)"), SLOT("slot_handleSampleRateChangedCallback(double)"))
  275. #self.NSM_AnnounceCallback(QString)"), SLOT("slot_handleNSM_AnnounceCallback(QString)"))
  276. #self.NSM_OpenCallback(QString)"), SLOT("slot_handleNSM_OpenCallback(QString)"))
  277. #self.NSM_SaveCallback()"), SLOT("slot_handleNSM_SaveCallback()"))
  278. #self.ErrorCallback(QString)"), SLOT("slot_handleErrorCallback(QString)"))
  279. #self.QuitCallback()"), SLOT("slot_handleQuitCallback()"))
  280. self.SIGUSR1.connect(self.slot_handleSIGUSR1)
  281. self.SIGTERM.connect(self.slot_handleSIGTERM)
  282. # -----------------------------------------------------------------
  283. def init(self):
  284. self.fIdleTimerFast = self.startTimer(50)
  285. self.fIdleTimerSlow = self.startTimer(50*2)
  286. def getExtraStuff(self, plugin):
  287. ptype = plugin['type']
  288. if ptype == PLUGIN_LADSPA:
  289. uniqueId = plugin['uniqueId']
  290. self.maybeLoadRDFs()
  291. for rdfItem in self.fLadspaRdfList:
  292. if rdfItem.UniqueID == uniqueId:
  293. return pointer(rdfItem)
  294. elif ptype in (PLUGIN_GIG, PLUGIN_SF2, PLUGIN_SFZ):
  295. if plugin['name'].lower().endswith(" (16 outputs)"):
  296. # return a dummy non-null pointer
  297. INTPOINTER = POINTER(c_int)
  298. int1 = c_int(0x1)
  299. addr = addressof(int1)
  300. return cast(addr, INTPOINTER)
  301. return c_nullptr
  302. def maybeLoadRDFs(self):
  303. if not self.fLadspaRdfNeedsUpdate:
  304. return
  305. self.fLadspaRdfNeedsUpdate = False
  306. self.fLadspaRdfList = []
  307. if not haveLRDF:
  308. return
  309. settingsDir = os.path.join(HOME, ".config", "falkTX")
  310. frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db")
  311. if os.path.exists(frLadspaFile):
  312. frLadspa = open(frLadspaFile, 'r')
  313. try:
  314. self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa))
  315. except:
  316. pass
  317. frLadspa.close()
  318. def setLoadRDFsNeeded(self):
  319. self.fLadspaRdfNeedsUpdate = True
  320. # -----------------------------------------------------------------
  321. @pyqtSlot()
  322. def slot_pluginAdd(self):
  323. dialog = PluginDatabaseW(self)
  324. if not dialog.exec_():
  325. return
  326. if not Carla.host.is_engine_running():
  327. QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped"))
  328. return
  329. btype = dialog.fRetPlugin['build']
  330. ptype = dialog.fRetPlugin['type']
  331. filename = dialog.fRetPlugin['binary']
  332. label = dialog.fRetPlugin['label']
  333. extraStuff = self.getExtraStuff(dialog.fRetPlugin)
  334. if not Carla.host.add_plugin(btype, ptype, filename, None, label, c_nullptr):
  335. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok)
  336. return
  337. @pyqtSlot()
  338. def slot_pluginRemoveAll(self):
  339. self.fContainer.removeAllPlugins()
  340. Carla.host.remove_all_plugins()
  341. @pyqtSlot()
  342. def slot_configureCarla(self):
  343. dialog = CarlaSettingsW(self, False) # TODO - hasGL
  344. if not dialog.exec_():
  345. return
  346. #self.loadSettings(False)
  347. #patchcanvas.clear()
  348. #pOptions = patchcanvas.options_t()
  349. #pOptions.theme_name = self.fSavedSettings["Canvas/Theme"]
  350. #pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"]
  351. #pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"]
  352. #pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"]
  353. #pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"]
  354. #pFeatures = patchcanvas.features_t()
  355. #pFeatures.group_info = False
  356. #pFeatures.group_rename = False
  357. #pFeatures.port_info = False
  358. #pFeatures.port_rename = False
  359. #pFeatures.handle_group_pos = True
  360. #patchcanvas.setOptions(pOptions)
  361. #patchcanvas.setFeatures(pFeatures)
  362. #patchcanvas.init("Carla", self.scene, canvasCallback, False)
  363. #if self.fEngineStarted:
  364. #Carla.host.patchbay_refresh()
  365. @pyqtSlot()
  366. def slot_aboutCarla(self):
  367. CarlaAboutW(self).exec_()
  368. @pyqtSlot()
  369. def slot_aboutQt(self):
  370. QApplication.instance().aboutQt()
  371. # -----------------------------------------------------------------
  372. @pyqtSlot(int, int, int, float, str)
  373. def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
  374. print("DEBUG:", pluginId, value1, value2, value3, valueStr)
  375. #self.ui.pte_log.appendPlainText(valueStr.replace("", "DEBUG: ").replace("", "ERROR: ").replace("", "").replace("\n", ""))
  376. @pyqtSlot(int)
  377. def slot_handlePluginAddedCallback(self, pluginId):
  378. self.fContainer.addPlugin(pluginId, self.fIsProjectLoading)
  379. if self.fContainer.getPluginCount() == 1:
  380. self.ui.act_plugin_remove_all.setEnabled(True)
  381. @pyqtSlot(int)
  382. def slot_handlePluginRemovedCallback(self, pluginId):
  383. self.fContainer.removePlugin(pluginId)
  384. if self.fContainer.getPluginCount() == 0:
  385. self.ui.act_plugin_remove_all.setEnabled(False)
  386. @pyqtSlot(int, str)
  387. def slot_handlePluginRenamedCallback(self, pluginId, newName):
  388. self.fContainer.renamePlugin(pluginId, newName)
  389. @pyqtSlot(int, int, float)
  390. def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value):
  391. self.fContainer.setParameterValue(parameterId, value)
  392. @pyqtSlot(int, int, float)
  393. def slot_handleParameterDefaultChangedCallback(self, pluginId, parameterId, value):
  394. self.fContainer.setParameterDefault(parameterId, value)
  395. @pyqtSlot(int, int, int)
  396. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, parameterId, channel):
  397. self.fContainer.setParameterMidiChannel(parameterId, channel)
  398. @pyqtSlot(int, int, int)
  399. def slot_handleParameterMidiCcChangedCallback(self, pluginId, parameterId, cc):
  400. self.fContainer.setParameterMidiCC(parameterId, cc)
  401. @pyqtSlot(int, int)
  402. def slot_handleProgramChangedCallback(self, pluginId, programId):
  403. self.fContainer.setProgram(programId)
  404. @pyqtSlot(int, int)
  405. def slot_handleMidiProgramChangedCallback(self, pluginId, midiProgramId):
  406. self.fContainer.setMidiProgram(midiProgramId)
  407. @pyqtSlot(int, int, int, int)
  408. def slot_handleNoteOnCallback(self, pluginId, channel, note, velo):
  409. self.fContainer.noteOn(channel, note)
  410. @pyqtSlot(int, int, int)
  411. def slot_handleNoteOffCallback(self, pluginId, channel, note):
  412. self.fContainer.noteOff(channel, note)
  413. @pyqtSlot(int, int)
  414. def slot_handleShowGuiCallback(self, pluginId, state):
  415. self.fContainer.setGuiState(pluginId, state)
  416. @pyqtSlot(int)
  417. def slot_handleUpdateCallback(self, pluginId):
  418. self.fContainer.updateInfo(pluginId)
  419. @pyqtSlot(int)
  420. def slot_handleReloadInfoCallback(self, pluginId):
  421. self.fContainer.reloadInfo(pluginId)
  422. @pyqtSlot(int)
  423. def slot_handleReloadParametersCallback(self, pluginId):
  424. self.fContainer.reloadParameters(pluginId)
  425. @pyqtSlot(int)
  426. def slot_handleReloadProgramsCallback(self, pluginId):
  427. self.fContainer.reloadPrograms(pluginId)
  428. @pyqtSlot(int)
  429. def slot_handleReloadAllCallback(self, pluginId):
  430. self.fContainer.reloadAll(pluginId)
  431. @pyqtSlot(int, int, str)
  432. def slot_handlePatchbayClientAddedCallback(self, clientId, clientIcon, clientName):
  433. self.fContainer.patchbayClientAdded(clientId, clientIcon, clientName)
  434. @pyqtSlot(int, str)
  435. def slot_handlePatchbayClientRemovedCallback(self, clientId, clientName):
  436. self.fContainer.patchbayClientRemoved(clientId, clientName)
  437. @pyqtSlot(int, str)
  438. def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName):
  439. self.fContainer.patchbayClientRenamed(clientId, newClientName)
  440. @pyqtSlot(int, int, int, str)
  441. def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags, portName):
  442. self.fContainer.patchbayPortAdded(clientId, portId, portFlags, portName)
  443. @pyqtSlot(int, int, str)
  444. def slot_handlePatchbayPortRemovedCallback(self, groupId, portId, fullPortName):
  445. self.fContainer.patchbayPortRemoved(groupId, portId, fullPortName)
  446. @pyqtSlot(int, int, str)
  447. def slot_handlePatchbayPortRenamedCallback(self, groupId, portId, newPortName):
  448. self.fContainer.patchbayPortRenamed(groupId, portId, newPortName)
  449. @pyqtSlot(int, int, int)
  450. def slot_handlePatchbayConnectionAddedCallback(self, connectionId, portOutId, portInId):
  451. self.fContainer.patchbayConnectionAdded(connectionId, portOutId, portInId)
  452. @pyqtSlot(int)
  453. def slot_handlePatchbayConnectionRemovedCallback(self, connectionId):
  454. self.fContainer.patchbayConnectionRemoved(connectionId)
  455. @pyqtSlot(int, int)
  456. def slot_handlePatchbayIconChangedCallback(self, clientId, clientIcon):
  457. self.fContainer.patchbayIconChanged(clientId, clientIcon)
  458. # -----------------------------------------------------------------
  459. @pyqtSlot()
  460. def slot_handleSIGUSR1(self):
  461. print("Got SIGUSR1 -> Saving project now")
  462. #QTimer.singleShot(0, self, SLOT("slot_fileSave()"))
  463. @pyqtSlot()
  464. def slot_handleSIGTERM(self):
  465. print("Got SIGTERM -> Closing now")
  466. self.close()
  467. # -----------------------------------------------------------------
  468. def timerEvent(self, event):
  469. if event.timerId() == self.fIdleTimerFast:
  470. Carla.host.engine_idle()
  471. self.fContainer.idleFast()
  472. elif event.timerId() == self.fIdleTimerSlow:
  473. self.fContainer.idleSlow()
  474. QMainWindow.timerEvent(self, event)
  475. def closeEvent(self, event):
  476. if self.fIdleTimerFast != 0:
  477. self.killTimer(self.fIdleTimerFast)
  478. self.fIdleTimerFast = 0
  479. if self.fIdleTimerSlow != 0:
  480. self.killTimer(self.fIdleTimerSlow)
  481. self.fIdleTimerSlow = 0
  482. QMainWindow.closeEvent(self, event)
  483. # ------------------------------------------------------------------------------------------------------------
  484. # Engine callback
  485. def EngineCallback(ptr, action, pluginId, value1, value2, value3, valueStr):
  486. if pluginId < 0 or not Carla.gui:
  487. return
  488. if action == CALLBACK_DEBUG:
  489. Carla.gui.DebugCallback.emit(pluginId, value1, value2, value3, cString(valueStr))
  490. elif action == CALLBACK_PLUGIN_ADDED:
  491. Carla.gui.PluginAddedCallback.emit(pluginId)
  492. elif action == CALLBACK_PLUGIN_REMOVED:
  493. Carla.gui.PluginRemovedCallback.emit(pluginId)
  494. elif action == CALLBACK_PLUGIN_RENAMED:
  495. Carla.gui.PluginRenamedCallback.emit(pluginId, valueStr)
  496. elif action == CALLBACK_PARAMETER_VALUE_CHANGED:
  497. Carla.gui.ParameterValueChangedCallback.emit(pluginId, value1, value3)
  498. elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED:
  499. Carla.gui.ParameterDefaultChangedCallback.emit(pluginId, value1, value3)
  500. elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  501. Carla.gui.ParameterMidiChannelChangedCallback.emit(pluginId, value1, value2)
  502. elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  503. Carla.gui.ParameterMidiCcChangedCallback.emit(pluginId, value1, value2)
  504. elif action == CALLBACK_PROGRAM_CHANGED:
  505. Carla.gui.ProgramChangedCallback.emit(pluginId, value1)
  506. elif action == CALLBACK_MIDI_PROGRAM_CHANGED:
  507. Carla.gui.MidiProgramChangedCallback.emit(pluginId, value1)
  508. elif action == CALLBACK_NOTE_ON:
  509. Carla.gui.NoteOnCallback.emit(pluginId, value1, value2, value3)
  510. elif action == CALLBACK_NOTE_OFF:
  511. Carla.gui.NoteOffCallback.emit(pluginId, value1, value2)
  512. elif action == CALLBACK_SHOW_GUI:
  513. Carla.gui.ShowGuiCallback.emit(pluginId, value1)
  514. elif action == CALLBACK_UPDATE:
  515. Carla.gui.UpdateCallback.emit(pluginId)
  516. elif action == CALLBACK_RELOAD_INFO:
  517. Carla.gui.ReloadInfoCallback.emit(pluginId)
  518. elif action == CALLBACK_RELOAD_PARAMETERS:
  519. Carla.gui.ReloadParametersCallback.emit(pluginId)
  520. elif action == CALLBACK_RELOAD_PROGRAMS:
  521. Carla.gui.ReloadProgramsCallback.emit(pluginId)
  522. elif action == CALLBACK_RELOAD_ALL:
  523. Carla.gui.ReloadAllCallback.emit(pluginId)
  524. elif action == CALLBACK_PATCHBAY_CLIENT_ADDED:
  525. Carla.gui.PatchbayClientAddedCallback.emit(value1, value2, cString(valueStr))
  526. elif action == CALLBACK_PATCHBAY_CLIENT_REMOVED:
  527. Carla.gui.PatchbayClientRemovedCallback.emit(value1, cString(valueStr))
  528. elif action == CALLBACK_PATCHBAY_CLIENT_RENAMED:
  529. Carla.gui.PatchbayClientRenamedCallback.emit(value1, cString(valueStr))
  530. elif action == CALLBACK_PATCHBAY_PORT_ADDED:
  531. Carla.gui.PatchbayPortAddedCallback.emit(value1, value2, int(value3), cString(valueStr))
  532. elif action == CALLBACK_PATCHBAY_PORT_REMOVED:
  533. Carla.gui.PatchbayPortRemovedCallback.emit(value1, value2, cString(valueStr))
  534. elif action == CALLBACK_PATCHBAY_PORT_RENAMED:
  535. Carla.gui.PatchbayPortRenamedCallback.emit(value1, value2, cString(valueStr))
  536. elif action == CALLBACK_PATCHBAY_CONNECTION_ADDED:
  537. Carla.gui.PatchbayConnectionAddedCallback.emit(value1, value2, value3)
  538. elif action == CALLBACK_PATCHBAY_CONNECTION_REMOVED:
  539. Carla.gui.PatchbayConnectionRemovedCallback.emit(value1)
  540. elif action == CALLBACK_PATCHBAY_ICON_CHANGED:
  541. Carla.gui.PatchbayIconChangedCallback.emit(value1, value2)
  542. elif action == CALLBACK_BUFFER_SIZE_CHANGED:
  543. Carla.gui.BufferSizeChangedCallback.emit(value1)
  544. elif action == CALLBACK_SAMPLE_RATE_CHANGED:
  545. Carla.gui.SampleRateChangedCallback.emit(value3)
  546. elif action == CALLBACK_NSM_ANNOUNCE:
  547. Carla.gui.NSM_AnnounceCallback.emit(cString(valueStr))
  548. elif action == CALLBACK_NSM_OPEN:
  549. Carla.gui.NSM_OpenCallback.emit(cString(valueStr))
  550. elif action == CALLBACK_NSM_SAVE:
  551. Carla.gui.NSM_SaveCallback.emit()
  552. elif action == CALLBACK_ERROR:
  553. Carla.gui.ErrorCallback.emit(cString(valueStr))
  554. elif action == CALLBACK_QUIT:
  555. Carla.gui.QuitCallback.emit()