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.

508 lines
15KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla rack widget 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. from PyQt4.QtCore import QSize, QTimer
  20. from PyQt4.QtGui import QApplication, QListWidget, QListWidgetItem
  21. # ------------------------------------------------------------------------------------------------------------
  22. # Imports (Custom Stuff)
  23. from carla_widgets import *
  24. # ------------------------------------------------------------------------------------------------------------
  25. # Rack widget item
  26. class CarlaRackItem(QListWidgetItem):
  27. kRackItemType = QListWidgetItem.UserType + 1
  28. kStaticHeight = 32
  29. def __init__(self, parent, pluginId):
  30. QListWidgetItem.__init__(self, parent, self.kRackItemType)
  31. self.widget = PluginWidget(parent, pluginId)
  32. self.widget.setFixedHeight(self.kStaticHeight)
  33. self.setSizeHint(QSize(300, self.kStaticHeight))
  34. parent.setItemWidget(self, self.widget)
  35. # -----------------------------------------------------------------
  36. def close(self):
  37. self.widget.ui.edit_dialog.close()
  38. #def setId(self, idx):
  39. #self.widget.setId(idx)
  40. #def setName(self, newName):
  41. #self.widget.ui.label_name.setText(newName)
  42. #self.widget.ui.edit_dialog.setName(newName)
  43. # ------------------------------------------------------------------------------------------------------------
  44. # Rack widget
  45. class CarlaRackW(QListWidget):
  46. def __init__(self, parent, doSetup = True):
  47. QListWidget.__init__(self, parent)
  48. # -------------------------------------------------------------
  49. # Internal stuff
  50. self.fParent = parent
  51. self.fPluginCount = 0
  52. self.fPluginList = []
  53. # -------------------------------------------------------------
  54. # Set-up GUI stuff
  55. #self.setMnimumWidth(800)
  56. self.setSortingEnabled(False)
  57. app = QApplication.instance()
  58. pal1 = app.palette().base().color()
  59. pal2 = app.palette().button().color()
  60. col1 = "stop:0 rgb(%i, %i, %i)" % (pal1.red(), pal1.green(), pal1.blue())
  61. col2 = "stop:1 rgb(%i, %i, %i)" % (pal2.red(), pal2.green(), pal2.blue())
  62. self.setStyleSheet("""
  63. QListWidget {
  64. background-color: qlineargradient(spread:pad,
  65. x1:0.0, y1:0.0,
  66. x2:0.2, y2:1.0,
  67. %s,
  68. %s
  69. );
  70. }
  71. """ % (col1, col2))
  72. # -------------------------------------------------------------
  73. # Connect actions to functions
  74. if not doSetup: return
  75. parent.ui.menu_Canvas.hide()
  76. parent.ui.act_plugins_enable.triggered.connect(self.slot_pluginsEnable)
  77. parent.ui.act_plugins_disable.triggered.connect(self.slot_pluginsDisable)
  78. parent.ui.act_plugins_volume100.triggered.connect(self.slot_pluginsVolume100)
  79. parent.ui.act_plugins_mute.triggered.connect(self.slot_pluginsMute)
  80. parent.ui.act_plugins_wet100.triggered.connect(self.slot_pluginsWet100)
  81. parent.ui.act_plugins_bypass.triggered.connect(self.slot_pluginsBypass)
  82. parent.ui.act_plugins_center.triggered.connect(self.slot_pluginsCenter)
  83. parent.ui.act_plugins_panic.triggered.connect(self.slot_pluginsDisable)
  84. parent.ui.act_settings_configure.triggered.connect(self.slot_configureCarla)
  85. parent.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback)
  86. parent.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback)
  87. parent.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback)
  88. parent.ParameterMidiCcChangedCallback.connect(self.slot_handleParameterMidiCcChangedCallback)
  89. parent.ProgramChangedCallback.connect(self.slot_handleProgramChangedCallback)
  90. parent.MidiProgramChangedCallback.connect(self.slot_handleMidiProgramChangedCallback)
  91. parent.UiStateChangedCallback.connect(self.slot_handleUiStateChangedCallback)
  92. parent.NoteOnCallback.connect(self.slot_handleNoteOnCallback)
  93. parent.NoteOffCallback.connect(self.slot_handleNoteOffCallback)
  94. parent.UpdateCallback.connect(self.slot_handleUpdateCallback)
  95. parent.ReloadInfoCallback.connect(self.slot_handleReloadInfoCallback)
  96. parent.ReloadParametersCallback.connect(self.slot_handleReloadParametersCallback)
  97. parent.ReloadProgramsCallback.connect(self.slot_handleReloadProgramsCallback)
  98. parent.ReloadAllCallback.connect(self.slot_handleReloadAllCallback)
  99. # -----------------------------------------------------------------
  100. def getPluginCount(self):
  101. return self.fPluginCount
  102. # -----------------------------------------------------------------
  103. def addPlugin(self, pluginId, isProjectLoading):
  104. pitem = CarlaRackItem(self, pluginId)
  105. self.fPluginList.append(pitem)
  106. self.fPluginCount += 1
  107. if not isProjectLoading:
  108. pitem.widget.setActive(True, True, True)
  109. def removePlugin(self, pluginId):
  110. if pluginId >= self.fPluginCount:
  111. return
  112. pitem = self.fPluginList[pluginId]
  113. if pitem is None:
  114. return
  115. self.fPluginCount -= 1
  116. self.fPluginList.pop(pluginId)
  117. self.takeItem(pluginId)
  118. pitem.close()
  119. del pitem
  120. # push all plugins 1 slot back
  121. for i in range(pluginId, self.fPluginCount):
  122. pitem = self.fPluginList[i]
  123. pitem.widget.setId(i)
  124. def renamePlugin(self, pluginId, newName):
  125. if pluginId >= self.fPluginCount:
  126. return
  127. pitem = self.fPluginList[pluginId]
  128. if pitem is None:
  129. return
  130. pitem.widget.setName(newName)
  131. def disablePlugin(self, pluginId, errorMsg):
  132. if pluginId >= self.fPluginCount:
  133. return
  134. pitem = self.fPluginList[pluginId]
  135. if pitem is None:
  136. return
  137. def removeAllPlugins(self):
  138. while (self.takeItem(0)):
  139. pass
  140. for i in range(self.fPluginCount):
  141. pitem = self.fPluginList[i]
  142. if pitem is None:
  143. break
  144. pitem.close()
  145. del pitem
  146. self.fPluginCount = 0
  147. self.fPluginList = []
  148. # -----------------------------------------------------------------
  149. def engineStarted(self):
  150. pass
  151. def engineStopped(self):
  152. pass
  153. def engineChanged(self):
  154. pass
  155. # -----------------------------------------------------------------
  156. def idleFast(self):
  157. for i in range(self.fPluginCount):
  158. pitem = self.fPluginList[i]
  159. if pitem is None:
  160. break
  161. pitem.widget.idleFast()
  162. def idleSlow(self):
  163. for i in range(self.fPluginCount):
  164. pitem = self.fPluginList[i]
  165. if pitem is None:
  166. break
  167. pitem.widget.idleSlow()
  168. # -----------------------------------------------------------------
  169. def saveSettings(self, settings):
  170. pass
  171. # -----------------------------------------------------------------
  172. @pyqtSlot()
  173. def slot_pluginsEnable(self):
  174. if not Carla.host.is_engine_running():
  175. return
  176. for i in range(self.fPluginCount):
  177. pitem = self.fPluginList[i]
  178. if pitem is None:
  179. break
  180. pitem.widget.setActive(True, True, True)
  181. @pyqtSlot()
  182. def slot_pluginsDisable(self):
  183. if not Carla.host.is_engine_running():
  184. return
  185. for i in range(self.fPluginCount):
  186. pitem = self.fPluginList[i]
  187. if pitem is None:
  188. break
  189. pitem.widget.setActive(False, True, True)
  190. @pyqtSlot()
  191. def slot_pluginsVolume100(self):
  192. if not Carla.host.is_engine_running():
  193. return
  194. for i in range(self.fPluginCount):
  195. pitem = self.fPluginList[i]
  196. if pitem is None:
  197. break
  198. pitem.widget.setInternalParameter(PLUGIN_CAN_VOLUME, 1.0)
  199. @pyqtSlot()
  200. def slot_pluginsMute(self):
  201. if not Carla.host.is_engine_running():
  202. return
  203. for i in range(self.fPluginCount):
  204. pitem = self.fPluginList[i]
  205. if pitem is None:
  206. break
  207. pitem.widget.setInternalParameter(PLUGIN_CAN_VOLUME, 0.0)
  208. @pyqtSlot()
  209. def slot_pluginsWet100(self):
  210. if not Carla.host.is_engine_running():
  211. return
  212. for i in range(self.fPluginCount):
  213. pitem = self.fPluginList[i]
  214. if pitem is None:
  215. break
  216. pitem.widget.setInternalParameter(PLUGIN_CAN_DRYWET, 1.0)
  217. @pyqtSlot()
  218. def slot_pluginsBypass(self):
  219. if not Carla.host.is_engine_running():
  220. return
  221. for i in range(self.fPluginCount):
  222. pitem = self.fPluginList[i]
  223. if pitem is None:
  224. break
  225. pitem.widget.setInternalParameter(PLUGIN_CAN_DRYWET, 0.0)
  226. @pyqtSlot()
  227. def slot_pluginsCenter(self):
  228. if not Carla.host.is_engine_running():
  229. return
  230. for i in range(self.fPluginCount):
  231. pitem = self.fPluginList[i]
  232. if pitem is None:
  233. break
  234. pitem.widget.setInternalParameter(PARAMETER_BALANCE_LEFT, -1.0)
  235. pitem.widget.setInternalParameter(PARAMETER_BALANCE_RIGHT, 1.0)
  236. pitem.widget.setInternalParameter(PARAMETER_PANNING, 0.0)
  237. # -----------------------------------------------------------------
  238. @pyqtSlot()
  239. def slot_configureCarla(self):
  240. if self.fParent is None or not self.fParent.openSettingsWindow(False, False):
  241. return
  242. self.fParent.loadSettings(False)
  243. # -----------------------------------------------------------------
  244. @pyqtSlot(int, int, float)
  245. def slot_handleParameterValueChangedCallback(self, pluginId, index, value):
  246. if pluginId >= self.fPluginCount:
  247. return
  248. pitem = self.fPluginList[pluginId]
  249. if pitem is None:
  250. return
  251. pitem.widget.setParameterValue(index, value)
  252. @pyqtSlot(int, int, float)
  253. def slot_handleParameterDefaultChangedCallback(self, pluginId, index, value):
  254. if pluginId >= self.fPluginCount:
  255. return
  256. pitem = self.fPluginList[pluginId]
  257. if pitem is None:
  258. return
  259. pitem.widget.setParameterDefault(index, value)
  260. @pyqtSlot(int, int, int)
  261. def slot_handleParameterMidiCcChangedCallback(self, pluginId, index, cc):
  262. if pluginId >= self.fPluginCount:
  263. return
  264. pitem = self.fPluginList[pluginId]
  265. if pitem is None:
  266. return
  267. pitem.widget.setParameterMidiControl(index, cc)
  268. @pyqtSlot(int, int, int)
  269. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, index, channel):
  270. if pluginId >= self.fPluginCount:
  271. return
  272. pitem = self.fPluginList[pluginId]
  273. if pitem is None:
  274. return
  275. pitem.widget.setParameterMidiChannel(index, channel)
  276. # -----------------------------------------------------------------
  277. @pyqtSlot(int, int)
  278. def slot_handleProgramChangedCallback(self, pluginId, index):
  279. if pluginId >= self.fPluginCount:
  280. return
  281. pitem = self.fPluginList[pluginId]
  282. if pitem is None:
  283. return
  284. pitem.widget.setProgram(index)
  285. @pyqtSlot(int, int)
  286. def slot_handleMidiProgramChangedCallback(self, pluginId, index):
  287. if pluginId >= self.fPluginCount:
  288. return
  289. pitem = self.fPluginList[pluginId]
  290. if pitem is None:
  291. return
  292. pitem.widget.setMidiProgram(index)
  293. # -----------------------------------------------------------------
  294. @pyqtSlot(int, int)
  295. def slot_handleUiStateChangedCallback(self, pluginId, state):
  296. if pluginId >= self.fPluginCount:
  297. return
  298. pitem = self.fPluginList[pluginId]
  299. if pitem is None:
  300. return
  301. # TODO
  302. if state == 0:
  303. pitem.widget.ui.b_gui.setChecked(False)
  304. pitem.widget.ui.b_gui.setEnabled(True)
  305. elif state == 1:
  306. pitem.widget.ui.b_gui.setChecked(True)
  307. pitem.widget.ui.b_gui.setEnabled(True)
  308. elif state == -1:
  309. pitem.widget.ui.b_gui.setChecked(False)
  310. pitem.widget.ui.b_gui.setEnabled(False)
  311. # -----------------------------------------------------------------
  312. @pyqtSlot(int, int, int, int)
  313. def slot_handleNoteOnCallback(self, pluginId, channel, note, velo):
  314. if pluginId >= self.fPluginCount:
  315. return
  316. pitem = self.fPluginList[pluginId]
  317. if pitem is None:
  318. return
  319. pitem.widget.sendNoteOn(channel, note)
  320. @pyqtSlot(int, int, int)
  321. def slot_handleNoteOffCallback(self, pluginId, channel, note):
  322. if pluginId >= self.fPluginCount:
  323. return
  324. pitem = self.fPluginList[pluginId]
  325. if pitem is None:
  326. return
  327. pitem.widget.sendNoteOff(channel, note)
  328. # -----------------------------------------------------------------
  329. @pyqtSlot(int)
  330. def slot_handleUpdateCallback(self, pluginId):
  331. if pluginId >= self.fPluginCount:
  332. return
  333. pitem = self.fPluginList[pluginId]
  334. if pitem is None:
  335. return
  336. pitem.widget.ui.edit_dialog.updateInfo()
  337. @pyqtSlot(int)
  338. def slot_handleReloadInfoCallback(self, pluginId):
  339. if pluginId >= self.fPluginCount:
  340. return
  341. pitem = self.fPluginList[pluginId]
  342. if pitem is None:
  343. return
  344. pitem.widget.ui.edit_dialog.reloadInfo()
  345. @pyqtSlot(int)
  346. def slot_handleReloadParametersCallback(self, pluginId):
  347. if pluginId >= self.fPluginCount:
  348. return
  349. pitem = self.fPluginList[pluginId]
  350. if pitem is None:
  351. return
  352. pitem.widget.ui.edit_dialog.reloadParameters()
  353. @pyqtSlot(int)
  354. def slot_handleReloadProgramsCallback(self, pluginId):
  355. if pluginId >= self.fPluginCount:
  356. return
  357. pitem = self.fPluginList[pluginId]
  358. if pitem is None:
  359. return
  360. pitem.widget.ui.edit_dialog.reloadPrograms()
  361. @pyqtSlot(int)
  362. def slot_handleReloadAllCallback(self, pluginId):
  363. if pluginId >= self.fPluginCount:
  364. return
  365. pitem = self.fPluginList[pluginId]
  366. if pitem is None:
  367. return
  368. pitem.widget.ui.edit_dialog.reloadAll()
  369. # -----------------------------------------------------------------