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
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  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. # -----------------------------------------------------------------