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_rack.py 15KB

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