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.

971 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. QLabel {
  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_gui.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png")
  422. self.ui.b_edit.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png")
  423. self.ui.b_remove.setPixmaps(":/bitmaps/button_calf1.png", ":/bitmaps/button_calf1_down.png", ":/bitmaps/button_calf1_hover.png")
  424. self.ui.b_gui.setEnabled((self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI) != 0)
  425. self.ui.led_midi.setColor(self.ui.led_midi.RED)
  426. self.ui.led_midi.setEnabled(False)
  427. self.ui.peak_in.setColor(self.ui.peak_in.GREEN)
  428. self.ui.peak_in.setChannels(self.fPeaksInputCount)
  429. self.ui.peak_in.setOrientation(self.ui.peak_in.HORIZONTAL)
  430. self.ui.peak_out.setColor(self.ui.peak_in.BLUE)
  431. self.ui.peak_out.setChannels(self.fPeaksOutputCount)
  432. self.ui.peak_out.setOrientation(self.ui.peak_out.HORIZONTAL)
  433. self.ui.label_name.setText(self.fPluginInfo['name'])
  434. # -------------------------------------------------------------
  435. # Set-up connections
  436. self.ui.b_gui.clicked.connect(self.slot_showCustomUi)
  437. self.ui.b_edit.clicked.connect(self.slot_showEditDialog)
  438. self.ui.b_remove.clicked.connect(self.slot_removePlugin)
  439. self.customContextMenuRequested.connect(self.slot_showCustomMenu)
  440. #------------------------------------------------------------------
  441. def getFixedHeight(self):
  442. return 80
  443. #------------------------------------------------------------------
  444. def recheckPluginHints(self, hints):
  445. self.ui.b_gui.setEnabled(hints & PLUGIN_HAS_CUSTOM_UI)
  446. PluginSlot.recheckPluginHints(self, hints)
  447. def setName(self, name):
  448. self.ui.label_name.setText(name)
  449. PluginSlot.setName(self, name)
  450. #------------------------------------------------------------------
  451. def activeChanged(self, onOff):
  452. self.fIsActive = onOff
  453. def editDialogChanged(self, visible):
  454. self.ui.b_edit.blockSignals(True)
  455. self.ui.b_edit.setChecked(visible)
  456. self.ui.b_edit.blockSignals(False)
  457. def customUiStateChanged(self, state):
  458. self.ui.b_gui.blockSignals(True)
  459. if state == 0:
  460. self.ui.b_gui.setChecked(False)
  461. self.ui.b_gui.setEnabled(True)
  462. elif state == 1:
  463. self.ui.b_gui.setChecked(True)
  464. self.ui.b_gui.setEnabled(True)
  465. elif state == -1:
  466. self.ui.b_gui.setChecked(False)
  467. self.ui.b_gui.setEnabled(False)
  468. self.ui.b_gui.blockSignals(False)
  469. def midiActivityChanged(self, onOff):
  470. self.ui.led_midi.setChecked(onOff)
  471. #------------------------------------------------------------------
  472. def idleFast(self):
  473. # Input peaks
  474. if self.fPeaksInputCount > 0:
  475. if self.fPeaksInputCount > 1:
  476. peak1 = Carla.host.get_input_peak_value(self.fPluginId, True)
  477. peak2 = Carla.host.get_input_peak_value(self.fPluginId, False)
  478. self.ui.peak_in.displayMeter(1, peak1)
  479. self.ui.peak_in.displayMeter(2, peak2)
  480. else:
  481. peak = Carla.host.get_input_peak_value(self.fPluginId, True)
  482. self.ui.peak_in.displayMeter(1, peak)
  483. # Output peaks
  484. if self.fPeaksOutputCount > 0:
  485. if self.fPeaksOutputCount > 1:
  486. peak1 = Carla.host.get_output_peak_value(self.fPluginId, True)
  487. peak2 = Carla.host.get_output_peak_value(self.fPluginId, False)
  488. self.ui.peak_out.displayMeter(1, peak1)
  489. self.ui.peak_out.displayMeter(2, peak2)
  490. else:
  491. peak = Carla.host.get_output_peak_value(self.fPluginId, True)
  492. self.ui.peak_out.displayMeter(1, peak)
  493. #------------------------------------------------------------------
  494. @pyqtSlot(bool)
  495. def slot_enableClicked(self, yesNo):
  496. self.fIsActive = yesNo
  497. @pyqtSlot()
  498. def slot_showCustomMenu(self):
  499. self.showDefaultMenu(self.fIsActive, self.ui.b_edit, self.ui.b_gui)
  500. # ------------------------------------------------------------------------------------------------------------
  501. class PluginSlot_ZynFX(PluginSlot):
  502. def __init__(self, parent, pluginId):
  503. PluginSlot.__init__(self, parent, pluginId)
  504. self.ui = ui_carla_plugin_zynfx.Ui_PluginWidget()
  505. self.ui.setupUi(self)
  506. # -------------------------------------------------------------
  507. # Set-up GUI
  508. self.setStyleSheet("""
  509. QFrame#PluginWidget {
  510. background-image: url(:/bitmaps/background_zynfx.png);
  511. background-repeat: repeat-xy;
  512. }""")
  513. self.ui.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png")
  514. self.ui.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png")
  515. self.ui.peak_in.setColor(self.ui.peak_in.GREEN)
  516. self.ui.peak_in.setChannels(self.fPeaksInputCount)
  517. self.ui.peak_in.setLinesEnabled(False)
  518. self.ui.peak_in.setOrientation(self.ui.peak_in.VERTICAL)
  519. self.ui.peak_out.setColor(self.ui.peak_in.BLUE)
  520. self.ui.peak_out.setChannels(self.fPeaksOutputCount)
  521. self.ui.peak_out.setLinesEnabled(False)
  522. self.ui.peak_out.setOrientation(self.ui.peak_out.VERTICAL)
  523. self.ui.label_name.setText(self.fPluginInfo['name'])
  524. # -------------------------------------------------------------
  525. # Set-up parameters
  526. self.fParameterList = [] # index, widget
  527. parameterCount = Carla.host.get_parameter_count(self.fPluginId)
  528. index = 0
  529. for i in range(parameterCount):
  530. paramInfo = Carla.host.get_parameter_info(self.fPluginId, i)
  531. paramData = Carla.host.get_parameter_data(self.fPluginId, i)
  532. paramRanges = Carla.host.get_parameter_ranges(self.fPluginId, i)
  533. paramValue = Carla.host.get_current_parameter_value(self.fPluginId, i)
  534. if paramData['type'] != PARAMETER_INPUT:
  535. continue
  536. paramName = charPtrToString(paramInfo['name'])
  537. paramLow = paramName.lower()
  538. # real zyn fx plugins
  539. if self.fPluginInfo['label'] == "zynAlienWah":
  540. if i == 0: paramName = "Freq"
  541. elif i == 1: paramName = "Rnd"
  542. elif i == 2: paramName = "L type" # combobox
  543. elif i == 3: paramName = "St.df"
  544. elif i == 5: paramName = "Fb"
  545. elif i == 7: paramName = "L/R"
  546. if self.fPluginInfo['label'] == "zynChorus":
  547. if i == 0: paramName = "Freq"
  548. elif i == 1: paramName = "Rnd"
  549. elif i == 2: paramName = "L type" # combobox
  550. elif i == 3: paramName = "St.df"
  551. elif i == 6: paramName = "Fb"
  552. elif i == 7: paramName = "L/R"
  553. elif i == 8: paramName = "Flngr" # button
  554. elif i == 9: paramName = "Subst" # button
  555. elif self.fPluginInfo['label'] == "zynDistortion":
  556. if i == 0: paramName = "LRc."
  557. elif i == 4: paramName = "Neg." # button
  558. elif i == 5: paramName = "LPF"
  559. elif i == 6: paramName = "HPF"
  560. elif i == 7: paramName = "St." # button
  561. elif i == 8: paramName = "PF" # button
  562. elif self.fPluginInfo['label'] == "zynDynamicFilter":
  563. if i == 0: paramName = "Freq"
  564. elif i == 1: paramName = "Rnd"
  565. elif i == 2: paramName = "L type" # combobox
  566. elif i == 3: paramName = "St.df"
  567. elif i == 4: paramName = "LfoD"
  568. elif i == 5: paramName = "A.S."
  569. elif i == 6: paramName = "A.Inv." # button
  570. elif i == 7: paramName = "A.M."
  571. elif self.fPluginInfo['label'] == "zynEcho":
  572. if i == 1: paramName = "LRdl."
  573. elif i == 2: paramName = "LRc."
  574. elif i == 3: paramName = "Fb."
  575. elif i == 4: paramName = "Damp"
  576. elif self.fPluginInfo['label'] == "zynPhaser":
  577. if i == 0: paramName = "Freq"
  578. elif i == 1: paramName = "Rnd"
  579. elif i == 2: paramName = "L type" # combobox
  580. elif i == 3: paramName = "St.df"
  581. elif i == 5: paramName = "Fb"
  582. elif i == 7: paramName = "L/R"
  583. elif i == 8: paramName = "Subst" # button
  584. elif i == 9: paramName = "Phase"
  585. elif i == 11: paramName = "Dist"
  586. elif self.fPluginInfo['label'] == "zynReverb":
  587. if i == 2: paramName = "I.delfb"
  588. elif i == 5: paramName = "LPF"
  589. elif i == 6: paramName = "HPF"
  590. elif i == 9: paramName = "R.S."
  591. elif i == 10: paramName = "I.del"
  592. #elif paramLow.find("damp"):
  593. #paramName = "Damp"
  594. #elif paramLow.find("frequency"):
  595. #paramName = "Freq"
  596. # Cut generic names
  597. #elif paramName == "Depth": paramName = "Dpth"
  598. #elif paramName == "Feedback": paramName = "Fb"
  599. #elif paramName == "L/R Cross": #paramName = "L/R"
  600. #elif paramName == "Random": paramName = "Rnd"
  601. widget = PixmapDial(self, i)
  602. widget.setPixmap(5)
  603. widget.setLabel(paramName)
  604. widget.setCustomPaint(PixmapDial.CUSTOM_PAINT_NO_GRADIENT)
  605. widget.setSingleStep(paramRanges['step']*1000)
  606. widget.setMinimum(paramRanges['min']*1000)
  607. widget.setMaximum(paramRanges['max']*1000)
  608. widget.setValue(paramValue*1000)
  609. if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0:
  610. widget.setEnabled(False)
  611. widget.valueChanged.connect(self.slot_parameterValueChanged)
  612. self.ui.container.layout().insertWidget(index, widget)
  613. index += 1
  614. self.fParameterList.append([i, widget])
  615. # -------------------------------------------------------------
  616. # Set-up MIDI programs
  617. midiProgramCount = Carla.host.get_midi_program_count(self.fPluginId) if Carla.host is not None else 0
  618. if midiProgramCount > 0:
  619. self.ui.cb_presets.setEnabled(True)
  620. self.ui.label_presets.setEnabled(True)
  621. for i in range(midiProgramCount):
  622. mpData = Carla.host.get_midi_program_data(self.fPluginId, i)
  623. mpName = charPtrToString(mpData['name'])
  624. self.ui.cb_presets.addItem(mpName)
  625. self.fCurrentMidiProgram = Carla.host.get_current_midi_program_index(self.fPluginId)
  626. self.ui.cb_presets.setCurrentIndex(self.fCurrentMidiProgram)
  627. else:
  628. self.fCurrentMidiProgram = -1
  629. self.ui.cb_presets.setEnabled(False)
  630. self.ui.cb_presets.setVisible(False)
  631. self.ui.label_presets.setEnabled(False)
  632. self.ui.label_presets.setVisible(False)
  633. # -------------------------------------------------------------
  634. # Set-up connections
  635. self.ui.b_enable.clicked.connect(self.slot_enableClicked)
  636. self.ui.b_edit.clicked.connect(self.slot_showEditDialog)
  637. self.ui.cb_presets.currentIndexChanged.connect(self.slot_presetChanged)
  638. self.customContextMenuRequested.connect(self.slot_showCustomMenu)
  639. #------------------------------------------------------------------
  640. def getFixedHeight(self):
  641. return 70
  642. #------------------------------------------------------------------
  643. def setName(self, name):
  644. self.ui.label_name.setText(name)
  645. PluginSlot.setName(self, name)
  646. #------------------------------------------------------------------
  647. def setParameterValue(self, parameterId, value):
  648. self.parameterValueChanged(parameterId, value)
  649. PluginSlot.setParameterValue(self, parameterId, value)
  650. def setMidiProgram(self, index):
  651. self.midiProgramChanged(index)
  652. PluginSlot.setMidiProgram(self, index)
  653. #------------------------------------------------------------------
  654. def activeChanged(self, onOff):
  655. self.ui.b_enable.blockSignals(True)
  656. self.ui.b_enable.setChecked(onOff)
  657. self.ui.b_enable.blockSignals(False)
  658. def editDialogChanged(self, visible):
  659. self.ui.b_edit.blockSignals(True)
  660. self.ui.b_edit.setChecked(visible)
  661. self.ui.b_edit.blockSignals(False)
  662. def parameterValueChanged(self, parameterId, value):
  663. for paramIndex, paramWidget in self.fParameterList:
  664. if paramIndex != parameterId:
  665. continue
  666. paramWidget.blockSignals(True)
  667. paramWidget.setValue(value*1000)
  668. paramWidget.blockSignals(False)
  669. break
  670. def midiProgramChanged(self, index):
  671. self.ui.cb_presets.blockSignals(True)
  672. self.ui.cb_presets.setCurrentIndex(index)
  673. self.ui.cb_presets.blockSignals(False)
  674. #------------------------------------------------------------------
  675. def idleFast(self):
  676. # Input peaks
  677. if self.fPeaksInputCount > 0:
  678. if self.fPeaksInputCount > 1:
  679. peak1 = Carla.host.get_input_peak_value(self.fPluginId, True)
  680. peak2 = Carla.host.get_input_peak_value(self.fPluginId, False)
  681. self.ui.peak_in.displayMeter(1, peak1)
  682. self.ui.peak_in.displayMeter(2, peak2)
  683. else:
  684. peak = Carla.host.get_input_peak_value(self.fPluginId, True)
  685. self.ui.peak_in.displayMeter(1, peak)
  686. # Output peaks
  687. if self.fPeaksOutputCount > 0:
  688. if self.fPeaksOutputCount > 1:
  689. peak1 = Carla.host.get_output_peak_value(self.fPluginId, True)
  690. peak2 = Carla.host.get_output_peak_value(self.fPluginId, False)
  691. self.ui.peak_out.displayMeter(1, peak1)
  692. self.ui.peak_out.displayMeter(2, peak2)
  693. else:
  694. peak = Carla.host.get_output_peak_value(self.fPluginId, True)
  695. self.ui.peak_out.displayMeter(1, peak)
  696. #------------------------------------------------------------------
  697. @pyqtSlot(bool)
  698. def slot_enableClicked(self, yesNo):
  699. self.setActive(yesNo, False, True)
  700. @pyqtSlot(int)
  701. def slot_parameterValueChanged(self, value):
  702. index = self.sender().getIndex()
  703. value = float(value)/1000.0
  704. Carla.host.set_parameter_value(self.fPluginId, index, value)
  705. PluginSlot.setParameterValue(self, index, value)
  706. @pyqtSlot(int)
  707. def slot_presetChanged(self, index):
  708. Carla.host.set_midi_program(self.fPluginId, index)
  709. PluginSlot.setMidiProgram(self, index)
  710. @pyqtSlot()
  711. def slot_showCustomMenu(self):
  712. self.showDefaultMenu(self.ui.b_enable.isChecked(), self.ui.b_edit, None)
  713. # ------------------------------------------------------------------------------------------------------------
  714. def createPluginSlot(parent, pluginId):
  715. pluginInfo = Carla.host.get_plugin_info(pluginId)
  716. pluginName = Carla.host.get_real_plugin_name(pluginId)
  717. pluginLabel = charPtrToString(pluginInfo['label'])
  718. #pluginMaker = charPtrToString(pluginInfo['maker'])
  719. #pluginIcon = charPtrToString(pluginInfo['iconName'])
  720. if pluginInfo['type'] == PLUGIN_INTERNAL:
  721. if pluginLabel.startswith("zyn"):
  722. return PluginSlot_ZynFX(parent, pluginId)
  723. if pluginName.split(" ", 1)[0].lower() == "calf":
  724. return PluginSlot_Calf(parent, pluginId)
  725. return PluginSlot_Default(parent, pluginId)
  726. # ------------------------------------------------------------------------------------------------------------