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.

974 lines
36KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin/slot skin code
  4. # Copyright (C) 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.QtGui import QFrame
  20. # ------------------------------------------------------------------------------------------------------------
  21. # Imports (Custom)
  22. import ui_carla_plugin_default
  23. import ui_carla_plugin_calf
  24. import ui_carla_plugin_zynfx
  25. from carla_widgets import *
  26. from pixmapdial import PixmapDial
  27. # ------------------------------------------------------------------------------------------------------------
  28. class PluginSlot(QFrame):
  29. def __init__(self, parent, pluginId):
  30. QFrame.__init__(self, parent)
  31. # -------------------------------------------------------------
  32. # Internal stuff
  33. self.fPluginId = pluginId
  34. self.fPluginInfo = Carla.host.get_plugin_info(self.fPluginId) if Carla.host is not None else gFakePluginInfo
  35. self.fPluginInfo['filename'] = charPtrToString(self.fPluginInfo['filename'])
  36. self.fPluginInfo['name'] = charPtrToString(self.fPluginInfo['name'])
  37. self.fPluginInfo['label'] = charPtrToString(self.fPluginInfo['label'])
  38. self.fPluginInfo['maker'] = charPtrToString(self.fPluginInfo['maker'])
  39. self.fPluginInfo['copyright'] = charPtrToString(self.fPluginInfo['copyright'])
  40. self.fPluginInfo['iconName'] = charPtrToString(self.fPluginInfo['iconName'])
  41. self.fParameterIconTimer = ICON_STATE_NULL
  42. if not Carla.isLocal:
  43. self.fPluginInfo['hints'] &= ~PLUGIN_HAS_CUSTOM_UI
  44. if Carla.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK or Carla.host is None:
  45. self.fPeaksInputCount = 2
  46. self.fPeaksOutputCount = 2
  47. else:
  48. audioCountInfo = Carla.host.get_audio_port_count_info(self.fPluginId)
  49. self.fPeaksInputCount = int(audioCountInfo['ins'])
  50. self.fPeaksOutputCount = int(audioCountInfo['outs'])
  51. if self.fPeaksInputCount > 2:
  52. self.fPeaksInputCount = 2
  53. if self.fPeaksOutputCount > 2:
  54. self.fPeaksOutputCount = 2
  55. # -------------------------------------------------------------
  56. # Set-up GUI
  57. self.fEditDialog = PluginEdit(self, self.fPluginId)
  58. self.fEditDialog.hide()
  59. #------------------------------------------------------------------
  60. def getFixedHeight(self):
  61. return 32
  62. def getHints(self):
  63. return self.fPluginInfo['hints']
  64. #------------------------------------------------------------------
  65. def recheckPluginHints(self, hints):
  66. self.fPluginInfo['hints'] = hints
  67. def setId(self, idx):
  68. self.fPluginId = idx
  69. self.fEditDialog.setId(idx)
  70. def setName(self, name):
  71. self.fEditDialog.setName(name)
  72. #------------------------------------------------------------------
  73. def setActive(self, active, sendGui=False, sendCallback=True):
  74. if sendGui: self.activeChanged(active)
  75. if sendCallback: Carla.host.set_active(self.fPluginId, active)
  76. if active:
  77. self.fEditDialog.clearNotes()
  78. self.midiActivityChanged(False)
  79. # called from rack, checks if param is possible first
  80. def setInternalParameter(self, parameterId, value):
  81. if parameterId <= PARAMETER_MAX or parameterId >= PARAMETER_NULL:
  82. return
  83. if parameterId == PARAMETER_ACTIVE:
  84. return self.setActive(bool(value), True, True)
  85. elif parameterId == PARAMETER_DRYWET:
  86. if (self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) == 0: return
  87. Carla.host.set_drywet(self.fPluginId, value)
  88. elif parameterId == PARAMETER_VOLUME:
  89. if (self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) == 0: return
  90. Carla.host.set_volume(self.fPluginId, value)
  91. elif parameterId == PARAMETER_BALANCE_LEFT:
  92. if (self.fPluginInfo['hints'] & PLUGIN_CAN_BALANCE) == 0: return
  93. Carla.host.set_balance_left(self.fPluginId, value)
  94. elif parameterId == PARAMETER_BALANCE_RIGHT:
  95. if (self.fPluginInfo['hints'] & PLUGIN_CAN_BALANCE) == 0: return
  96. Carla.host.set_balance_right(self.fPluginId, value)
  97. elif parameterId == PARAMETER_PANNING:
  98. if (self.fPluginInfo['hints'] & PLUGIN_CAN_PANNING) == 0: return
  99. Carla.host.set_panning(self.fPluginId, value)
  100. elif parameterId == PARAMETER_CTRL_CHANNEL:
  101. Carla.host.set_ctrl_channel(self.fPluginId, value)
  102. self.fEditDialog.setParameterValue(parameterId, value)
  103. #------------------------------------------------------------------
  104. def setParameterValue(self, parameterId, value):
  105. self.fParameterIconTimer = ICON_STATE_ON
  106. if parameterId == PARAMETER_ACTIVE:
  107. return self.setActive(bool(value), True, False)
  108. self.fEditDialog.setParameterValue(parameterId, value)
  109. def setParameterDefault(self, parameterId, value):
  110. self.fEditDialog.setParameterDefault(parameterId, value)
  111. def setParameterMidiControl(self, parameterId, control):
  112. self.fEditDialog.setParameterMidiControl(parameterId, control)
  113. def setParameterMidiChannel(self, parameterId, channel):
  114. self.fEditDialog.setParameterMidiChannel(parameterId, channel)
  115. #------------------------------------------------------------------
  116. def setProgram(self, index):
  117. self.fParameterIconTimer = ICON_STATE_ON
  118. self.fEditDialog.setProgram(index)
  119. def setMidiProgram(self, index):
  120. self.fParameterIconTimer = ICON_STATE_ON
  121. self.fEditDialog.setMidiProgram(index)
  122. #------------------------------------------------------------------
  123. def sendNoteOn(self, channel, note):
  124. if self.fEditDialog.sendNoteOn(channel, note):
  125. self.midiActivityChanged(True)
  126. def sendNoteOff(self, channel, note):
  127. if self.fEditDialog.sendNoteOff(channel, note):
  128. self.midiActivityChanged(False)
  129. #------------------------------------------------------------------
  130. def activeChanged(self, onOff):
  131. pass
  132. def editDialogChanged(self, visible):
  133. pass
  134. def customUiStateChanged(self, state):
  135. pass
  136. def parameterActivityChanged(self, onOff):
  137. pass
  138. def midiActivityChanged(self, onOff):
  139. pass
  140. def parameterValueChanged(self, parameterId, value):
  141. pass
  142. def programChanged(self, index):
  143. pass
  144. def midiProgramChanged(self, index):
  145. pass
  146. def notePressed(self, note):
  147. pass
  148. def noteReleased(self, note):
  149. pass
  150. #------------------------------------------------------------------
  151. def idleFast(self):
  152. pass
  153. def idleSlow(self):
  154. if self.fParameterIconTimer == ICON_STATE_ON:
  155. self.fParameterIconTimer = ICON_STATE_WAIT
  156. self.parameterActivityChanged(True)
  157. elif self.fParameterIconTimer == ICON_STATE_WAIT:
  158. self.fParameterIconTimer = ICON_STATE_OFF
  159. elif self.fParameterIconTimer == ICON_STATE_OFF:
  160. self.fParameterIconTimer = ICON_STATE_NULL
  161. self.parameterActivityChanged(False)
  162. self.fEditDialog.idleSlow()
  163. #------------------------------------------------------------------
  164. def showDefaultMenu(self, isEnabled, bEdit = None, bGui = None):
  165. menu = QMenu(self)
  166. actActive = menu.addAction(self.tr("Disable") if isEnabled else self.tr("Enable"))
  167. menu.addSeparator()
  168. if bEdit is not None:
  169. actEdit = menu.addAction(self.tr("Edit"))
  170. actEdit.setCheckable(True)
  171. actEdit.setChecked(bEdit.isChecked())
  172. else:
  173. actEdit = None
  174. if bGui is not None:
  175. actGui = menu.addAction(self.tr("Show Custom UI"))
  176. actGui.setCheckable(True)
  177. actGui.setChecked(bGui.isChecked())
  178. actGui.setEnabled(bGui.isEnabled())
  179. else:
  180. actGui = None
  181. menu.addSeparator()
  182. actClone = menu.addAction(self.tr("Clone"))
  183. actRename = menu.addAction(self.tr("Rename..."))
  184. actRemove = menu.addAction(self.tr("Remove"))
  185. actSel = menu.exec_(QCursor.pos())
  186. if not actSel:
  187. return
  188. if actSel == actActive:
  189. self.setActive(not isEnabled, True, True)
  190. elif actSel == actGui:
  191. bGui.click()
  192. elif actSel == actEdit:
  193. bEdit.click()
  194. elif actSel == actClone:
  195. if Carla.host is not None and not Carla.host.clone_plugin(self.fPluginId):
  196. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  197. Carla.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  198. elif actSel == actRename:
  199. oldName = self.fPluginInfo['name']
  200. newNameTry = QInputDialog.getText(self, self.tr("Rename Plugin"), self.tr("New plugin name:"), QLineEdit.Normal, oldName)
  201. if not (newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]):
  202. return
  203. newName = newNameTry[0]
  204. if Carla.host is None or Carla.host.rename_plugin(self.fPluginId, newName):
  205. self.setName(newName)
  206. else:
  207. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  208. Carla.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  209. elif actSel == actRemove:
  210. if Carla.host is not None and not Carla.host.remove_plugin(self.fPluginId):
  211. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  212. Carla.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  213. #------------------------------------------------------------------
  214. @pyqtSlot(bool)
  215. def slot_showCustomUi(self, show):
  216. Carla.host.show_custom_ui(self.fPluginId, show)
  217. @pyqtSlot(bool)
  218. def slot_showEditDialog(self, show):
  219. self.fEditDialog.setVisible(show)
  220. @pyqtSlot()
  221. def slot_removePlugin(self):
  222. Carla.host.remove_plugin(self.fPluginId)
  223. # ------------------------------------------------------------------------------------------------------------
  224. class PluginSlot_Default(PluginSlot):
  225. def __init__(self, parent, pluginId):
  226. PluginSlot.__init__(self, parent, pluginId)
  227. self.ui = ui_carla_plugin_default.Ui_PluginWidget()
  228. self.ui.setupUi(self)
  229. # -------------------------------------------------------------
  230. # Internal stuff
  231. self.fLastGreenLedState = False
  232. self.fLastBlueLedState = False
  233. if self.palette().window().color().lightness() > 100:
  234. # Light background
  235. labelColor = "333"
  236. isLight = True
  237. self.fColorTop = QColor(60, 60, 60)
  238. self.fColorBottom = QColor(47, 47, 47)
  239. self.fColorSeprtr = QColor(70, 70, 70)
  240. else:
  241. # Dark background
  242. labelColor = "BBB"
  243. isLight = False
  244. self.fColorTop = QColor(60, 60, 60)
  245. self.fColorBottom = QColor(47, 47, 47)
  246. self.fColorSeprtr = QColor(70, 70, 70)
  247. # -------------------------------------------------------------
  248. # Set-up GUI
  249. self.setStyleSheet("""
  250. QLabel#label_name {
  251. color: #%s;
  252. }""" % labelColor)
  253. if isLight:
  254. self.ui.b_enable.setPixmaps(":/bitmaps/button_off2.png", ":/bitmaps/button_on2.png", ":/bitmaps/button_off2.png")
  255. self.ui.b_edit.setPixmaps(":/bitmaps/button_edit2.png", ":/bitmaps/button_edit_down2.png", ":/bitmaps/button_edit_hover2.png")
  256. if self.fPluginInfo['iconName'] == "distrho":
  257. self.ui.b_gui.setPixmaps(":/bitmaps/button_distrho2.png", ":/bitmaps/button_distrho_down2.png", ":/bitmaps/button_distrho_hover2.png")
  258. elif self.fPluginInfo['iconName'] == "file":
  259. self.ui.b_gui.setPixmaps(":/bitmaps/button_file2.png", ":/bitmaps/button_file_down2.png", ":/bitmaps/button_file_hover2.png")
  260. else:
  261. self.ui.b_gui.setPixmaps(":/bitmaps/button_gui2.png", ":/bitmaps/button_gui_down2.png", ":/bitmaps/button_gui_hover2.png")
  262. else:
  263. self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png")
  264. self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png")
  265. if self.fPluginInfo['iconName'] == "distrho":
  266. self.ui.b_gui.setPixmaps(":/bitmaps/button_distrho.png", ":/bitmaps/button_distrho_down.png", ":/bitmaps/button_distrho_hover.png")
  267. elif self.fPluginInfo['iconName'] == "file":
  268. self.ui.b_gui.setPixmaps(":/bitmaps/button_file.png", ":/bitmaps/button_file_down.png", ":/bitmaps/button_file_hover.png")
  269. else:
  270. self.ui.b_gui.setPixmaps(":/bitmaps/button_gui.png", ":/bitmaps/button_gui_down.png", ":/bitmaps/button_gui_hover.png")
  271. self.ui.b_gui.setEnabled((self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI) != 0)
  272. self.ui.led_control.setColor(self.ui.led_control.YELLOW)
  273. self.ui.led_control.setEnabled(False)
  274. self.ui.led_midi.setColor(self.ui.led_midi.RED)
  275. self.ui.led_midi.setEnabled(False)
  276. self.ui.led_audio_in.setColor(self.ui.led_audio_in.GREEN)
  277. self.ui.led_audio_in.setEnabled(False)
  278. self.ui.led_audio_out.setColor(self.ui.led_audio_out.BLUE)
  279. self.ui.led_audio_out.setEnabled(False)
  280. self.ui.peak_in.setColor(self.ui.peak_in.GREEN)
  281. self.ui.peak_in.setChannels(self.fPeaksInputCount)
  282. self.ui.peak_in.setOrientation(self.ui.peak_in.HORIZONTAL)
  283. self.ui.peak_out.setColor(self.ui.peak_in.BLUE)
  284. self.ui.peak_out.setChannels(self.fPeaksOutputCount)
  285. self.ui.peak_out.setOrientation(self.ui.peak_out.HORIZONTAL)
  286. self.ui.label_name.setText(self.fPluginInfo['name'])
  287. # -------------------------------------------------------------
  288. # Set-up connections
  289. self.ui.b_enable.clicked.connect(self.slot_enableClicked)
  290. self.ui.b_gui.clicked.connect(self.slot_showCustomUi)
  291. self.ui.b_edit.clicked.connect(self.slot_showEditDialog)
  292. self.customContextMenuRequested.connect(self.slot_showCustomMenu)
  293. #------------------------------------------------------------------
  294. def getFixedHeight(self):
  295. return 48
  296. #------------------------------------------------------------------
  297. def recheckPluginHints(self, hints):
  298. self.ui.b_gui.setEnabled(hints & PLUGIN_HAS_CUSTOM_UI)
  299. PluginSlot.recheckPluginHints(self, hints)
  300. def setName(self, name):
  301. self.ui.label_name.setText(name)
  302. PluginSlot.setName(self, name)
  303. #------------------------------------------------------------------
  304. def activeChanged(self, onOff):
  305. self.ui.b_enable.blockSignals(True)
  306. self.ui.b_enable.setChecked(onOff)
  307. self.ui.b_enable.blockSignals(False)
  308. def editDialogChanged(self, visible):
  309. self.ui.b_edit.blockSignals(True)
  310. self.ui.b_edit.setChecked(visible)
  311. self.ui.b_edit.blockSignals(False)
  312. def customUiStateChanged(self, state):
  313. self.ui.b_gui.blockSignals(True)
  314. if state == 0:
  315. self.ui.b_gui.setChecked(False)
  316. self.ui.b_gui.setEnabled(True)
  317. elif state == 1:
  318. self.ui.b_gui.setChecked(True)
  319. self.ui.b_gui.setEnabled(True)
  320. elif state == -1:
  321. self.ui.b_gui.setChecked(False)
  322. self.ui.b_gui.setEnabled(False)
  323. self.ui.b_gui.blockSignals(False)
  324. def parameterActivityChanged(self, onOff):
  325. self.ui.led_control.setChecked(onOff)
  326. def midiActivityChanged(self, onOff):
  327. self.ui.led_midi.setChecked(onOff)
  328. #------------------------------------------------------------------
  329. def idleFast(self):
  330. # Input peaks
  331. if self.fPeaksInputCount > 0:
  332. if self.fPeaksInputCount > 1:
  333. peak1 = Carla.host.get_input_peak_value(self.fPluginId, True)
  334. peak2 = Carla.host.get_input_peak_value(self.fPluginId, False)
  335. ledState = bool(peak1 != 0.0 or peak2 != 0.0)
  336. self.ui.peak_in.displayMeter(1, peak1)
  337. self.ui.peak_in.displayMeter(2, peak2)
  338. else:
  339. peak = Carla.host.get_input_peak_value(self.fPluginId, True)
  340. ledState = bool(peak != 0.0)
  341. self.ui.peak_in.displayMeter(1, peak)
  342. if self.fLastGreenLedState != ledState:
  343. self.fLastGreenLedState = ledState
  344. self.ui.led_audio_in.setChecked(ledState)
  345. # Output peaks
  346. if self.fPeaksOutputCount > 0:
  347. if self.fPeaksOutputCount > 1:
  348. peak1 = Carla.host.get_output_peak_value(self.fPluginId, True)
  349. peak2 = Carla.host.get_output_peak_value(self.fPluginId, False)
  350. ledState = bool(peak1 != 0.0 or peak2 != 0.0)
  351. self.ui.peak_out.displayMeter(1, peak1)
  352. self.ui.peak_out.displayMeter(2, peak2)
  353. else:
  354. peak = Carla.host.get_output_peak_value(self.fPluginId, True)
  355. ledState = bool(peak != 0.0)
  356. self.ui.peak_out.displayMeter(1, peak)
  357. if self.fLastBlueLedState != ledState:
  358. self.fLastBlueLedState = ledState
  359. self.ui.led_audio_out.setChecked(ledState)
  360. #------------------------------------------------------------------
  361. @pyqtSlot(bool)
  362. def slot_enableClicked(self, yesNo):
  363. self.setActive(yesNo, False, True)
  364. @pyqtSlot()
  365. def slot_showCustomMenu(self):
  366. self.showDefaultMenu(self.ui.b_enable.isChecked(), self.ui.b_edit, self.ui.b_gui)
  367. #------------------------------------------------------------------
  368. def paintEvent(self, event):
  369. painter = QPainter(self)
  370. painter.save()
  371. areaX = self.ui.area_right.x()+7
  372. width = self.width()
  373. height = self.height()
  374. painter.setPen(self.fColorSeprtr.lighter(110))
  375. painter.setBrush(self.fColorBottom)
  376. painter.setRenderHint(QPainter.Antialiasing, True)
  377. # name -> leds arc
  378. path = QPainterPath()
  379. path.moveTo(areaX-20, height-4)
  380. path.cubicTo(areaX, height-5, areaX-20, 4.75, areaX, 4.75)
  381. path.lineTo(areaX, height-5)
  382. painter.drawPath(path)
  383. painter.setPen(self.fColorSeprtr)
  384. painter.setRenderHint(QPainter.Antialiasing, False)
  385. # separator lines
  386. painter.drawLine(0, height-5, areaX-20, height-5)
  387. painter.drawLine(areaX, 4, width, 4)
  388. painter.setPen(self.fColorBottom)
  389. painter.setBrush(self.fColorBottom)
  390. # top, bottom and left lines
  391. painter.drawLine(0, 0, width, 0)
  392. painter.drawRect(0, height-4, areaX, 4)
  393. painter.drawRoundedRect(areaX-20, height-5, areaX, 5, 22, 22)
  394. painter.drawLine(0, 0, 0, height)
  395. # fill the rest
  396. painter.drawRect(areaX-1, 5, width, height)
  397. # bottom 1px line
  398. painter.setPen(self.fColorSeprtr)
  399. painter.drawLine(0, height-1, width, height-1)
  400. painter.restore()
  401. PluginSlot.paintEvent(self, event)
  402. # ------------------------------------------------------------------------------------------------------------
  403. class PluginSlot_Calf(PluginSlot):
  404. def __init__(self, parent, pluginId):
  405. PluginSlot.__init__(self, parent, pluginId)
  406. self.ui = ui_carla_plugin_calf.Ui_PluginWidget()
  407. self.ui.setupUi(self)
  408. # -------------------------------------------------------------
  409. # Internal stuff
  410. self.fIsActive = False
  411. # -------------------------------------------------------------
  412. # Set-up GUI
  413. self.setStyleSheet("""
  414. * {
  415. color: black;
  416. }
  417. QFrame#PluginWidget {
  418. background-image: url(:/bitmaps/background_calf.png);
  419. background-repeat: repeat-xy;
  420. }""")
  421. #self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png")
  422. self.ui.b_gui.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png")
  423. self.ui.b_edit.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png")
  424. self.ui.b_remove.setPixmaps(":/bitmaps/button_calf1.png", ":/bitmaps/button_calf1_down.png", ":/bitmaps/button_calf1_hover.png")
  425. self.ui.b_gui.setEnabled((self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI) != 0)
  426. self.ui.led_midi.setColor(self.ui.led_midi.RED)
  427. self.ui.led_midi.setEnabled(False)
  428. self.ui.peak_in.setColor(self.ui.peak_in.GREEN)
  429. self.ui.peak_in.setChannels(self.fPeaksInputCount)
  430. self.ui.peak_in.setOrientation(self.ui.peak_in.HORIZONTAL)
  431. self.ui.peak_out.setColor(self.ui.peak_in.BLUE)
  432. self.ui.peak_out.setChannels(self.fPeaksOutputCount)
  433. self.ui.peak_out.setOrientation(self.ui.peak_out.HORIZONTAL)
  434. self.ui.label_name.setText(self.fPluginInfo['name'])
  435. # -------------------------------------------------------------
  436. # Set-up connections
  437. #self.ui.b_enable.clicked.connect(self.slot_enableClicked)
  438. self.ui.b_gui.clicked.connect(self.slot_showCustomUi)
  439. self.ui.b_edit.clicked.connect(self.slot_showEditDialog)
  440. self.ui.b_remove.clicked.connect(self.slot_removePlugin)
  441. self.customContextMenuRequested.connect(self.slot_showCustomMenu)
  442. #------------------------------------------------------------------
  443. def getFixedHeight(self):
  444. return 80
  445. #------------------------------------------------------------------
  446. def recheckPluginHints(self, hints):
  447. self.ui.b_gui.setEnabled(hints & PLUGIN_HAS_CUSTOM_UI)
  448. PluginSlot.recheckPluginHints(self, hints)
  449. def setName(self, name):
  450. self.ui.label_name.setText(name)
  451. PluginSlot.setName(self, name)
  452. #------------------------------------------------------------------
  453. def activeChanged(self, onOff):
  454. self.fIsActive = onOff
  455. def editDialogChanged(self, visible):
  456. self.ui.b_edit.blockSignals(True)
  457. self.ui.b_edit.setChecked(visible)
  458. self.ui.b_edit.blockSignals(False)
  459. def customUiStateChanged(self, state):
  460. self.ui.b_gui.blockSignals(True)
  461. if state == 0:
  462. self.ui.b_gui.setChecked(False)
  463. self.ui.b_gui.setEnabled(True)
  464. elif state == 1:
  465. self.ui.b_gui.setChecked(True)
  466. self.ui.b_gui.setEnabled(True)
  467. elif state == -1:
  468. self.ui.b_gui.setChecked(False)
  469. self.ui.b_gui.setEnabled(False)
  470. self.ui.b_gui.blockSignals(False)
  471. def midiActivityChanged(self, onOff):
  472. self.ui.led_midi.setChecked(onOff)
  473. #------------------------------------------------------------------
  474. def idleFast(self):
  475. # Input peaks
  476. if self.fPeaksInputCount > 0:
  477. if self.fPeaksInputCount > 1:
  478. peak1 = Carla.host.get_input_peak_value(self.fPluginId, True)
  479. peak2 = Carla.host.get_input_peak_value(self.fPluginId, False)
  480. self.ui.peak_in.displayMeter(1, peak1)
  481. self.ui.peak_in.displayMeter(2, peak2)
  482. else:
  483. peak = Carla.host.get_input_peak_value(self.fPluginId, True)
  484. self.ui.peak_in.displayMeter(1, peak)
  485. # Output peaks
  486. if self.fPeaksOutputCount > 0:
  487. if self.fPeaksOutputCount > 1:
  488. peak1 = Carla.host.get_output_peak_value(self.fPluginId, True)
  489. peak2 = Carla.host.get_output_peak_value(self.fPluginId, False)
  490. self.ui.peak_out.displayMeter(1, peak1)
  491. self.ui.peak_out.displayMeter(2, peak2)
  492. else:
  493. peak = Carla.host.get_output_peak_value(self.fPluginId, True)
  494. self.ui.peak_out.displayMeter(1, peak)
  495. #------------------------------------------------------------------
  496. @pyqtSlot(bool)
  497. def slot_enableClicked(self, yesNo):
  498. self.fIsActive = yesNo
  499. @pyqtSlot()
  500. def slot_showCustomMenu(self):
  501. self.showDefaultMenu(self.fIsActive, self.ui.b_edit, self.ui.b_gui)
  502. # ------------------------------------------------------------------------------------------------------------
  503. class PluginSlot_ZynFX(PluginSlot):
  504. def __init__(self, parent, pluginId):
  505. PluginSlot.__init__(self, parent, pluginId)
  506. self.ui = ui_carla_plugin_zynfx.Ui_PluginWidget()
  507. self.ui.setupUi(self)
  508. # -------------------------------------------------------------
  509. # Set-up GUI
  510. self.setStyleSheet("""
  511. QFrame#PluginWidget {
  512. background-image: url(:/bitmaps/background_zynfx.png);
  513. background-repeat: repeat-xy;
  514. }""")
  515. self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png")
  516. self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png")
  517. self.ui.peak_in.setColor(self.ui.peak_in.GREEN)
  518. self.ui.peak_in.setChannels(self.fPeaksInputCount)
  519. self.ui.peak_in.setLinesEnabled(False)
  520. self.ui.peak_in.setOrientation(self.ui.peak_in.VERTICAL)
  521. self.ui.peak_out.setColor(self.ui.peak_in.BLUE)
  522. self.ui.peak_out.setChannels(self.fPeaksOutputCount)
  523. self.ui.peak_out.setLinesEnabled(False)
  524. self.ui.peak_out.setOrientation(self.ui.peak_out.VERTICAL)
  525. self.ui.label_name.setText(self.fPluginInfo['name'])
  526. # -------------------------------------------------------------
  527. # Set-up parameters
  528. self.fParameterList = [] # index, widget
  529. parameterCount = Carla.host.get_parameter_count(self.fPluginId)
  530. index = 0
  531. for i in range(parameterCount):
  532. paramInfo = Carla.host.get_parameter_info(self.fPluginId, i)
  533. paramData = Carla.host.get_parameter_data(self.fPluginId, i)
  534. paramRanges = Carla.host.get_parameter_ranges(self.fPluginId, i)
  535. paramValue = Carla.host.get_current_parameter_value(self.fPluginId, i)
  536. if paramData['type'] != PARAMETER_INPUT:
  537. continue
  538. paramName = charPtrToString(paramInfo['name'])
  539. paramLow = paramName.lower()
  540. # real zyn fx plugins
  541. if self.fPluginInfo['label'] == "zynAlienWah":
  542. if i == 0: paramName = "Freq"
  543. elif i == 1: paramName = "Rnd"
  544. elif i == 2: paramName = "L type" # combobox
  545. elif i == 3: paramName = "St.df"
  546. elif i == 5: paramName = "Fb"
  547. elif i == 7: paramName = "L/R"
  548. if self.fPluginInfo['label'] == "zynChorus":
  549. if i == 0: paramName = "Freq"
  550. elif i == 1: paramName = "Rnd"
  551. elif i == 2: paramName = "L type" # combobox
  552. elif i == 3: paramName = "St.df"
  553. elif i == 6: paramName = "Fb"
  554. elif i == 7: paramName = "L/R"
  555. elif i == 8: paramName = "Flngr" # button
  556. elif i == 9: paramName = "Subst" # button
  557. elif self.fPluginInfo['label'] == "zynDistortion":
  558. if i == 0: paramName = "LRc."
  559. elif i == 4: paramName = "Neg." # button
  560. elif i == 5: paramName = "LPF"
  561. elif i == 6: paramName = "HPF"
  562. elif i == 7: paramName = "St." # button
  563. elif i == 8: paramName = "PF" # button
  564. elif self.fPluginInfo['label'] == "zynDynamicFilter":
  565. if i == 0: paramName = "Freq"
  566. elif i == 1: paramName = "Rnd"
  567. elif i == 2: paramName = "L type" # combobox
  568. elif i == 3: paramName = "St.df"
  569. elif i == 4: paramName = "LfoD"
  570. elif i == 5: paramName = "A.S."
  571. elif i == 6: paramName = "A.Inv." # button
  572. elif i == 7: paramName = "A.M."
  573. elif self.fPluginInfo['label'] == "zynEcho":
  574. if i == 1: paramName = "LRdl."
  575. elif i == 2: paramName = "LRc."
  576. elif i == 3: paramName = "Fb."
  577. elif i == 4: paramName = "Damp"
  578. elif self.fPluginInfo['label'] == "zynPhaser":
  579. if i == 0: paramName = "Freq"
  580. elif i == 1: paramName = "Rnd"
  581. elif i == 2: paramName = "L type" # combobox
  582. elif i == 3: paramName = "St.df"
  583. elif i == 5: paramName = "Fb"
  584. elif i == 7: paramName = "L/R"
  585. elif i == 8: paramName = "Subst" # button
  586. elif i == 9: paramName = "Phase"
  587. elif i == 11: paramName = "Dist"
  588. elif self.fPluginInfo['label'] == "zynReverb":
  589. if i == 2: paramName = "I.delfb"
  590. elif i == 5: paramName = "LPF"
  591. elif i == 6: paramName = "HPF"
  592. elif i == 9: paramName = "R.S."
  593. elif i == 10: paramName = "I.del"
  594. #elif paramLow.find("damp"):
  595. #paramName = "Damp"
  596. #elif paramLow.find("frequency"):
  597. #paramName = "Freq"
  598. # Cut generic names
  599. #elif paramName == "Depth": paramName = "Dpth"
  600. #elif paramName == "Feedback": paramName = "Fb"
  601. #elif paramName == "L/R Cross": #paramName = "L/R"
  602. #elif paramName == "Random": paramName = "Rnd"
  603. widget = PixmapDial(self, i)
  604. widget.setPixmap(5)
  605. widget.setLabel(paramName)
  606. widget.setCustomPaint(PixmapDial.CUSTOM_PAINT_NO_GRADIENT)
  607. widget.setSingleStep(paramRanges['step']*1000)
  608. widget.setMinimum(paramRanges['min']*1000)
  609. widget.setMaximum(paramRanges['max']*1000)
  610. widget.setValue(paramValue*1000)
  611. if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0:
  612. widget.setEnabled(False)
  613. widget.valueChanged.connect(self.slot_parameterValueChanged)
  614. self.ui.container.layout().insertWidget(index, widget)
  615. index += 1
  616. self.fParameterList.append([i, widget])
  617. # -------------------------------------------------------------
  618. # Set-up MIDI programs
  619. midiProgramCount = Carla.host.get_midi_program_count(self.fPluginId) if Carla.host is not None else 0
  620. if midiProgramCount > 0:
  621. self.ui.cb_presets.setEnabled(True)
  622. self.ui.label_presets.setEnabled(True)
  623. for i in range(midiProgramCount):
  624. mpData = Carla.host.get_midi_program_data(self.fPluginId, i)
  625. mpName = charPtrToString(mpData['name'])
  626. self.ui.cb_presets.addItem(mpName)
  627. self.fCurrentMidiProgram = Carla.host.get_current_midi_program_index(self.fPluginId)
  628. self.ui.cb_presets.setCurrentIndex(self.fCurrentMidiProgram)
  629. else:
  630. self.fCurrentMidiProgram = -1
  631. self.ui.cb_presets.setEnabled(False)
  632. self.ui.cb_presets.setVisible(False)
  633. self.ui.label_presets.setEnabled(False)
  634. self.ui.label_presets.setVisible(False)
  635. # -------------------------------------------------------------
  636. # Set-up connections
  637. self.ui.b_enable.clicked.connect(self.slot_enableClicked)
  638. self.ui.b_edit.clicked.connect(self.slot_showEditDialog)
  639. self.ui.cb_presets.currentIndexChanged.connect(self.slot_presetChanged)
  640. self.customContextMenuRequested.connect(self.slot_showCustomMenu)
  641. #------------------------------------------------------------------
  642. def getFixedHeight(self):
  643. return 70
  644. #------------------------------------------------------------------
  645. def setName(self, name):
  646. self.ui.label_name.setText(name)
  647. PluginSlot.setName(self, name)
  648. #------------------------------------------------------------------
  649. def setParameterValue(self, parameterId, value):
  650. self.parameterValueChanged(parameterId, value)
  651. PluginSlot.setParameterValue(self, parameterId, value)
  652. def setMidiProgram(self, index):
  653. self.midiProgramChanged(index)
  654. PluginSlot.setMidiProgram(self, index)
  655. #------------------------------------------------------------------
  656. def activeChanged(self, onOff):
  657. self.ui.b_enable.blockSignals(True)
  658. self.ui.b_enable.setChecked(onOff)
  659. self.ui.b_enable.blockSignals(False)
  660. def editDialogChanged(self, visible):
  661. self.ui.b_edit.blockSignals(True)
  662. self.ui.b_edit.setChecked(visible)
  663. self.ui.b_edit.blockSignals(False)
  664. def parameterValueChanged(self, parameterId, value):
  665. for paramIndex, paramWidget in self.fParameterList:
  666. if paramIndex != parameterId:
  667. continue
  668. paramWidget.blockSignals(True)
  669. paramWidget.setValue(value*1000)
  670. paramWidget.blockSignals(False)
  671. break
  672. def midiProgramChanged(self, index):
  673. self.ui.cb_presets.blockSignals(True)
  674. self.ui.cb_presets.setCurrentIndex(index)
  675. self.ui.cb_presets.blockSignals(False)
  676. #------------------------------------------------------------------
  677. def idleFast(self):
  678. # Input peaks
  679. if self.fPeaksInputCount > 0:
  680. if self.fPeaksInputCount > 1:
  681. peak1 = Carla.host.get_input_peak_value(self.fPluginId, True)
  682. peak2 = Carla.host.get_input_peak_value(self.fPluginId, False)
  683. self.ui.peak_in.displayMeter(1, peak1)
  684. self.ui.peak_in.displayMeter(2, peak2)
  685. else:
  686. peak = Carla.host.get_input_peak_value(self.fPluginId, True)
  687. self.ui.peak_in.displayMeter(1, peak)
  688. # Output peaks
  689. if self.fPeaksOutputCount > 0:
  690. if self.fPeaksOutputCount > 1:
  691. peak1 = Carla.host.get_output_peak_value(self.fPluginId, True)
  692. peak2 = Carla.host.get_output_peak_value(self.fPluginId, False)
  693. self.ui.peak_out.displayMeter(1, peak1)
  694. self.ui.peak_out.displayMeter(2, peak2)
  695. else:
  696. peak = Carla.host.get_output_peak_value(self.fPluginId, True)
  697. self.ui.peak_out.displayMeter(1, peak)
  698. #------------------------------------------------------------------
  699. @pyqtSlot(bool)
  700. def slot_enableClicked(self, yesNo):
  701. self.setActive(yesNo, False, True)
  702. @pyqtSlot(int)
  703. def slot_parameterValueChanged(self, value):
  704. index = self.sender().getIndex()
  705. value = float(value)/1000.0
  706. Carla.host.set_parameter_value(self.fPluginId, index, value)
  707. PluginSlot.setParameterValue(self, index, value)
  708. @pyqtSlot(int)
  709. def slot_presetChanged(self, index):
  710. Carla.host.set_midi_program(self.fPluginId, index)
  711. PluginSlot.setMidiProgram(self, index)
  712. @pyqtSlot()
  713. def slot_showCustomMenu(self):
  714. self.showDefaultMenu(self.ui.b_enable.isChecked(), self.ui.b_edit, None)
  715. # ------------------------------------------------------------------------------------------------------------
  716. def createPluginSlot(parent, pluginId):
  717. pluginInfo = Carla.host.get_plugin_info(pluginId)
  718. pluginName = Carla.host.get_real_plugin_name(pluginId)
  719. pluginLabel = charPtrToString(pluginInfo['label'])
  720. #pluginMaker = charPtrToString(pluginInfo['maker'])
  721. #pluginIcon = charPtrToString(pluginInfo['iconName'])
  722. if pluginInfo['type'] == PLUGIN_INTERNAL:
  723. if pluginLabel.startswith("zyn"):
  724. return PluginSlot_ZynFX(parent, pluginId)
  725. if pluginName.split(" ", 1)[0].lower() == "calf":
  726. return PluginSlot_Calf(parent, pluginId)
  727. return PluginSlot_Default(parent, pluginId)
  728. # ------------------------------------------------------------------------------------------------------------