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_skin.py 37KB

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