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 39KB

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