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

10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin/slot skin code
  4. # Copyright (C) 2013-2018 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 (Config)
  19. from carla_config import *
  20. # ------------------------------------------------------------------------------------------------------------
  21. # Imports (Global)
  22. if config_UseQt5:
  23. from PyQt5.QtCore import Qt, QRectF
  24. from PyQt5.QtGui import QFont, QFontDatabase, QPen, QPixmap
  25. from PyQt5.QtWidgets import QFrame, QPushButton
  26. else:
  27. from PyQt4.QtCore import Qt, QRectF
  28. from PyQt4.QtGui import QFont, QFontDatabase, QFrame, QPen, QPixmap, QPushButton
  29. # ------------------------------------------------------------------------------------------------------------
  30. # Imports (Custom)
  31. import ui_carla_plugin_calf
  32. import ui_carla_plugin_classic
  33. import ui_carla_plugin_compact
  34. import ui_carla_plugin_default
  35. import ui_carla_plugin_presets
  36. from carla_widgets import *
  37. from digitalpeakmeter import DigitalPeakMeter
  38. from pixmapdial import PixmapDial
  39. # ------------------------------------------------------------------------------------------------------------
  40. # Plugin Skin Rules (WORK IN PROGRESS)
  41. # Base is a QFrame (NoFrame, Plain, 0-size lines), with "PluginWidget" as object name.
  42. # Spacing of the top-most layout must be 1px.
  43. # Top and bottom margins must be 3px (can be splitted between different qt layouts).
  44. # Left and right margins must be 6px (can be splitted between different qt layouts).
  45. # If the left or right side has built-in margins, say a transparent png border,
  46. # those margins must be taken into consideration.
  47. #
  48. # There's a top and bottom layout, separated by a horizontal line.
  49. # Compacted skins do not have the bottom layout and separating line.
  50. # T O P A R E A
  51. #
  52. # -----------------------------------------------------------------
  53. # | <> | <> [ WIDGETS ] [ LEDS ] |
  54. # | BUTTONS <> | <> PLUGIN NAME < spacer > [ WIDGETS ] [ LEDS ] |
  55. # | <> | <> [ WIDGETS ] [ LEDS ] |
  56. # -----------------------------------------------------------------
  57. #
  58. # Buttons area has size fixed. (TBA)
  59. # Spacers at the left of the plugin name must be 8x1 in size (fixed).
  60. # The line before the plugin name must be height-10px (fixed).
  61. # WIDGETS area can be extended to the left, if using meters they should have 80px.
  62. # WIDGETS margins are 4px for left+right and 2px for top+bottom, with 4px spacing.
  63. # ------------------------------------------------------------------------------------------------------------
  64. # Try to "shortify" a parameter name
  65. def getParameterShortName(paramName):
  66. paramName = paramName.split("/",1)[0].split(" (",1)[0].split(" [",1)[0].strip()
  67. paramLow = paramName.lower()
  68. # Cut useless prefix
  69. if paramLow.startswith("compressor "):
  70. paramName = paramName.replace("ompressor ", ".", 1)
  71. paramLow = paramName.lower()
  72. elif paramLow.startswith("room "):
  73. paramName = paramName.split(" ",1)[1]
  74. paramLow = paramName.lower()
  75. # Cut useless suffix
  76. if paramLow.endswith(" level"):
  77. paramName = paramName.rsplit(" ",1)[0]
  78. paramLow = paramName.lower()
  79. elif paramLow.endswith(" time"):
  80. paramName = paramName.rsplit(" ",1)[0]
  81. paramLow = paramName.lower()
  82. # Cut generic names
  83. if "attack" in paramLow:
  84. paramName = paramName.replace("ttack", "tk")
  85. elif "bandwidth" in paramLow:
  86. paramName = paramName.replace("andwidth", "w")
  87. elif "damping" in paramLow:
  88. paramName = paramName.replace("amping", "amp")
  89. elif "distortion" in paramLow:
  90. paramName = paramName.replace("istortion", "ist")
  91. elif "feedback" in paramLow:
  92. paramName = paramName.replace("eedback", "b")
  93. elif "frequency" in paramLow:
  94. paramName = paramName.replace("requency", "req")
  95. elif "input" in paramLow:
  96. paramName = paramName.replace("nput", "n")
  97. elif "makeup" in paramLow:
  98. paramName = paramName.replace("akeup", "kUp" if "Make" in paramName else "kup")
  99. elif "output" in paramLow:
  100. paramName = paramName.replace("utput", "ut")
  101. elif "random" in paramLow:
  102. paramName = paramName.replace("andom", "nd")
  103. elif "threshold" in paramLow:
  104. paramName = paramName.replace("hreshold", "hres")
  105. # remove space if last char from 1st word is lowercase and the first char from the 2nd is uppercase,
  106. # or if 2nd is a number
  107. if " " in paramName:
  108. name1, name2 = paramName.split(" ", 1)
  109. if (name1[-1].islower() and name2[0].isupper()) or name2.isdigit():
  110. paramName = paramName.replace(" ", "", 1)
  111. # cut stuff if too big
  112. if len(paramName) > 7:
  113. paramName = paramName.replace("a","").replace("e","").replace("i","").replace("o","").replace("u","")
  114. if len(paramName) > 7:
  115. paramName = paramName[:7]
  116. return paramName.strip()
  117. # ------------------------------------------------------------------------------------------------------------
  118. # Get RGB colors for a plugin category
  119. def getColorFromCategory(category):
  120. r = 40
  121. g = 40
  122. b = 40
  123. if category == PLUGIN_CATEGORY_MODULATOR:
  124. r += 10
  125. elif category == PLUGIN_CATEGORY_EQ:
  126. g += 10
  127. elif category == PLUGIN_CATEGORY_FILTER:
  128. b += 10
  129. elif category == PLUGIN_CATEGORY_DELAY:
  130. r += 15
  131. b -= 15
  132. elif category == PLUGIN_CATEGORY_DISTORTION:
  133. g += 10
  134. b += 10
  135. elif category == PLUGIN_CATEGORY_DYNAMICS:
  136. r += 10
  137. b += 10
  138. elif category == PLUGIN_CATEGORY_UTILITY:
  139. r += 10
  140. g += 10
  141. return (r, g, b)
  142. def getModColorFromCategory(category):
  143. if category == PLUGIN_CATEGORY_NONE:
  144. return (40, 40, 40)
  145. if category == PLUGIN_CATEGORY_SYNTH:
  146. return (30, 150, 49)
  147. if category == PLUGIN_CATEGORY_DELAY:
  148. return (47, 47, 47)
  149. if category in (PLUGIN_CATEGORY_EQ, PLUGIN_CATEGORY_FILTER):
  150. return (255, 220, 25)
  151. if category == PLUGIN_CATEGORY_DISTORTION:
  152. return (255, 127, 25)
  153. if category == PLUGIN_CATEGORY_DYNAMICS:
  154. return (255, 25, 25)
  155. if category == PLUGIN_CATEGORY_MODULATOR:
  156. return (109, 31, 142)
  157. if category == PLUGIN_CATEGORY_UTILITY:
  158. return (95, 95, 95)
  159. if category == PLUGIN_CATEGORY_OTHER:
  160. return (92, 210, 254)
  161. return (40, 40, 40)
  162. # ------------------------------------------------------------------------------------------------------------
  163. #
  164. def setPixmapDialStyle(widget, parameterId, parameterCount, skinStyle):
  165. if skinStyle.startswith("calf"):
  166. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT)
  167. widget.setPixmap(7)
  168. elif skinStyle.startswith("openav"):
  169. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT)
  170. if parameterId == PARAMETER_DRYWET:
  171. widget.setPixmap(13)
  172. elif parameterId == PARAMETER_VOLUME:
  173. widget.setPixmap(12)
  174. else:
  175. widget.setPixmap(11)
  176. else:
  177. if parameterId == PARAMETER_DRYWET:
  178. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_WET)
  179. elif parameterId == PARAMETER_VOLUME:
  180. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_VOL)
  181. else:
  182. _r = 255 - int((float(parameterId)/float(parameterCount))*200.0)
  183. _g = 55 + int((float(parameterId)/float(parameterCount))*200.0)
  184. _b = 0 #(r-40)*4
  185. widget.setCustomPaintColor(QColor(_r, _g, _b))
  186. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR)
  187. widget.setPixmap(3)
  188. widget.forceWhiteLabelGradientText()
  189. # ------------------------------------------------------------------------------------------------------------
  190. # Abstract plugin slot
  191. class AbstractPluginSlot(QFrame, PluginEditParentMeta):
  192. #class AbstractPluginSlot(QFrame, PluginEditParentMeta, metaclass=PyQtMetaClass):
  193. def __init__(self, parent, host, pluginId, skinStyle):
  194. QFrame.__init__(self, parent)
  195. self.host = host
  196. self.fParent = parent
  197. if False:
  198. # kdevelop likes this :)
  199. host = CarlaHostNull()
  200. self.host = host
  201. # -------------------------------------------------------------
  202. # Get plugin info
  203. self.fPluginId = pluginId
  204. self.fPluginInfo = host.get_plugin_info(self.fPluginId)
  205. self.fSkinStyle = skinStyle
  206. # -------------------------------------------------------------
  207. # Internal stuff
  208. self.fIsActive = False
  209. self.fIsSelected = False
  210. self.fLastGreenLedState = False
  211. self.fLastBlueLedState = False
  212. self.fParameterIconTimer = ICON_STATE_NULL
  213. self.fParameterList = [] # index, widget
  214. audioCountInfo = host.get_audio_port_count_info(self.fPluginId)
  215. self.fPeaksInputCount = audioCountInfo['ins']
  216. self.fPeaksOutputCount = audioCountInfo['outs']
  217. if self.fPeaksInputCount > 2:
  218. self.fPeaksInputCount = 2
  219. if self.fPeaksOutputCount > 2:
  220. self.fPeaksOutputCount = 2
  221. # used during testing
  222. self.fIdleTimerId = 0
  223. # -------------------------------------------------------------
  224. # Set-up GUI
  225. self.fEditDialog = PluginEdit(self, host, self.fPluginId)
  226. # -------------------------------------------------------------
  227. # Set-up common widgets (as none)
  228. self.b_enable = None
  229. self.b_gui = None
  230. self.b_edit = None
  231. self.b_remove = None
  232. self.cb_presets = None
  233. self.label_name = None
  234. self.label_presets = None
  235. self.label_type = None
  236. self.led_control = None
  237. self.led_midi = None
  238. self.led_audio_in = None
  239. self.led_audio_out = None
  240. self.peak_in = None
  241. self.peak_out = None
  242. self.w_knobs_left = None
  243. self.w_knobs_right = None
  244. # -------------------------------------------------------------
  245. # Set-up connections
  246. self.customContextMenuRequested.connect(self.slot_showCustomMenu)
  247. host.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback)
  248. host.PluginUnavailableCallback.connect(self.slot_handlePluginUnavailableCallback)
  249. host.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback)
  250. host.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback)
  251. host.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback)
  252. host.ParameterMidiCcChangedCallback.connect(self.slot_handleParameterMidiCcChangedCallback)
  253. host.ProgramChangedCallback.connect(self.slot_handleProgramChangedCallback)
  254. host.MidiProgramChangedCallback.connect(self.slot_handleMidiProgramChangedCallback)
  255. host.OptionChangedCallback.connect(self.slot_handleOptionChangedCallback)
  256. host.UiStateChangedCallback.connect(self.slot_handleUiStateChangedCallback)
  257. # -----------------------------------------------------------------
  258. @pyqtSlot(int, str)
  259. def slot_handlePluginRenamedCallback(self, pluginId, newName):
  260. if self.fPluginId == pluginId:
  261. self.setName(newName)
  262. @pyqtSlot(int, str)
  263. def slot_handlePluginUnavailableCallback(self, pluginId, errorMsg):
  264. if self.fPluginId == pluginId:
  265. pass
  266. @pyqtSlot(int, int, float)
  267. def slot_handleParameterValueChangedCallback(self, pluginId, index, value):
  268. if self.fPluginId == pluginId:
  269. self.setParameterValue(index, value, True)
  270. @pyqtSlot(int, int, float)
  271. def slot_handleParameterDefaultChangedCallback(self, pluginId, index, value):
  272. if self.fPluginId == pluginId:
  273. self.setParameterDefault(index, value)
  274. @pyqtSlot(int, int, int)
  275. def slot_handleParameterMidiCcChangedCallback(self, pluginId, index, cc):
  276. if self.fPluginId == pluginId:
  277. self.setParameterMidiControl(index, cc)
  278. @pyqtSlot(int, int, int)
  279. def slot_handleParameterMidiChannelChangedCallback(self, pluginId, index, channel):
  280. if self.fPluginId == pluginId:
  281. self.setParameterMidiChannel(index, channel)
  282. @pyqtSlot(int, int)
  283. def slot_handleProgramChangedCallback(self, pluginId, index):
  284. if self.fPluginId == pluginId:
  285. self.setProgram(index, True)
  286. @pyqtSlot(int, int)
  287. def slot_handleMidiProgramChangedCallback(self, pluginId, index):
  288. if self.fPluginId == pluginId:
  289. self.setMidiProgram(index, True)
  290. @pyqtSlot(int, int, bool)
  291. def slot_handleOptionChangedCallback(self, pluginId, option, yesNo):
  292. if self.fPluginId == pluginId:
  293. self.setOption(option, yesNo)
  294. @pyqtSlot(int, int)
  295. def slot_handleUiStateChangedCallback(self, pluginId, state):
  296. if self.fPluginId == pluginId:
  297. self.customUiStateChanged(state)
  298. #------------------------------------------------------------------
  299. def ready(self):
  300. self.fIsActive = bool(self.host.get_internal_parameter_value(self.fPluginId, PARAMETER_ACTIVE) >= 0.5)
  301. isCalfSkin = self.fSkinStyle.startswith("calf") and not isinstance(self, PluginSlot_Compact)
  302. if self.b_enable is not None:
  303. self.b_enable.setChecked(self.fIsActive)
  304. self.b_enable.clicked.connect(self.slot_enableClicked)
  305. if isCalfSkin:
  306. self.b_enable.setPixmaps(":/bitmaps/button_calf3.png", ":/bitmaps/button_calf3_down.png", ":/bitmaps/button_calf3.png")
  307. else:
  308. self.b_enable.setPixmaps(":/bitmaps/button_off.png", ":/bitmaps/button_on.png", ":/bitmaps/button_off.png")
  309. if self.b_gui is not None:
  310. self.b_gui.clicked.connect(self.slot_showCustomUi)
  311. self.b_gui.setEnabled(bool(self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI))
  312. if isCalfSkin:
  313. self.b_gui.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png")
  314. elif self.fPluginInfo['iconName'] == "distrho" or self.fSkinStyle in ("3bandeq","3bandsplitter","pingpongpan"):
  315. self.b_gui.setPixmaps(":/bitmaps/button_distrho.png", ":/bitmaps/button_distrho_down.png", ":/bitmaps/button_distrho_hover.png")
  316. elif self.fPluginInfo['iconName'] == "file":
  317. self.b_gui.setPixmaps(":/bitmaps/button_file.png", ":/bitmaps/button_file_down.png", ":/bitmaps/button_file_hover.png")
  318. else:
  319. self.b_gui.setPixmaps(":/bitmaps/button_gui.png", ":/bitmaps/button_gui_down.png", ":/bitmaps/button_gui_hover.png")
  320. if self.b_edit is not None:
  321. self.b_edit.clicked.connect(self.slot_showEditDialog)
  322. if isCalfSkin:
  323. self.b_edit.setPixmaps(":/bitmaps/button_calf2.png", ":/bitmaps/button_calf2_down.png", ":/bitmaps/button_calf2_hover.png")
  324. else:
  325. self.b_edit.setPixmaps(":/bitmaps/button_edit.png", ":/bitmaps/button_edit_down.png", ":/bitmaps/button_edit_hover.png")
  326. else:
  327. # Edit button *must* be available
  328. self.b_edit = QPushButton(self)
  329. self.b_edit.setCheckable(True)
  330. self.b_edit.hide()
  331. if self.b_remove is not None:
  332. self.b_remove.clicked.connect(self.slot_removePlugin)
  333. if self.label_name is not None:
  334. self.label_name.setEnabled(self.fIsActive)
  335. self.label_name.setText(self.fPluginInfo['name'])
  336. nameFont = self.label_name.font()
  337. if self.fSkinStyle.startswith("calf"):
  338. nameFont.setBold(True)
  339. nameFont.setPixelSize(12)
  340. elif self.fSkinStyle.startswith("openav"):
  341. QFontDatabase.addApplicationFont(":/fonts/uranium.ttf")
  342. nameFont.setFamily("Uranium")
  343. nameFont.setPixelSize(15)
  344. nameFont.setCapitalization(QFont.AllUppercase)
  345. else:
  346. nameFont.setBold(True)
  347. nameFont.setPixelSize(11)
  348. self.label_name.setFont(nameFont)
  349. if self.label_presets is not None:
  350. presetFont = self.label_presets.font()
  351. presetFont.setBold(True)
  352. presetFont.setPixelSize(10)
  353. self.label_presets.setFont(presetFont)
  354. if self.label_type is not None:
  355. self.label_type.setText(getPluginTypeAsString(self.fPluginInfo['type']))
  356. if self.led_control is not None:
  357. self.led_control.setColor(self.led_control.YELLOW)
  358. self.led_control.setEnabled(False)
  359. if self.led_midi is not None:
  360. self.led_midi.setColor(self.led_midi.RED)
  361. self.led_midi.setEnabled(False)
  362. if self.led_audio_in is not None:
  363. self.led_audio_in.setColor(self.led_audio_in.GREEN)
  364. self.led_audio_in.setEnabled(False)
  365. if self.led_audio_out is not None:
  366. self.led_audio_out.setColor(self.led_audio_out.BLUE)
  367. self.led_audio_out.setEnabled(False)
  368. if self.peak_in is not None:
  369. self.peak_in.setChannelCount(self.fPeaksInputCount)
  370. self.peak_in.setMeterColor(DigitalPeakMeter.COLOR_GREEN)
  371. self.peak_in.setMeterOrientation(DigitalPeakMeter.HORIZONTAL)
  372. if self.fSkinStyle.startswith("calf"):
  373. self.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_CALF)
  374. elif self.fSkinStyle == "rncbc":
  375. self.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_RNCBC)
  376. elif self.fSkinStyle.startswith("openav") or self.fSkinStyle == "zynfx":
  377. self.peak_in.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV)
  378. if self.fPeaksInputCount == 0 and not isinstance(self, PluginSlot_Classic):
  379. self.peak_in.hide()
  380. if self.peak_out is not None:
  381. self.peak_out.setChannelCount(self.fPeaksOutputCount)
  382. self.peak_out.setMeterColor(DigitalPeakMeter.COLOR_BLUE)
  383. self.peak_out.setMeterOrientation(DigitalPeakMeter.HORIZONTAL)
  384. if self.fSkinStyle.startswith("calf"):
  385. self.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_CALF)
  386. elif self.fSkinStyle == "rncbc":
  387. self.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_RNCBC)
  388. elif self.fSkinStyle.startswith("openav") or self.fSkinStyle == "zynfx":
  389. self.peak_out.setMeterStyle(DigitalPeakMeter.STYLE_OPENAV)
  390. if self.fPeaksOutputCount == 0 and not isinstance(self, PluginSlot_Classic):
  391. self.peak_out.hide()
  392. # -------------------------------------------------------------
  393. if self.fSkinStyle == "openav":
  394. styleSheet = """
  395. QFrame#PluginWidget {
  396. background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
  397. stop: 0 #383838, stop: %f #111111, stop: 1.0 #111111);
  398. }
  399. QLabel#label_name { color: #FFFFFF; }
  400. QLabel#label_name:disabled { color: #505050; }
  401. """ % (0.95 if isinstance(self, PluginSlot_Compact) else 0.35)
  402. elif self.fSkinStyle == "openav-old":
  403. styleSheet = """
  404. QFrame#PluginWidget {
  405. background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
  406. stop: 0 #303030, stop: %f #111111, stop: 1.0 #111111);
  407. }
  408. QLabel#label_name { color: #FF5100; }
  409. QLabel#label_name:disabled { color: #505050; }
  410. """ % (0.95 if isinstance(self, PluginSlot_Compact) else 0.35)
  411. else:
  412. if self.fSkinStyle in ("3bandeq", "calf_black", "calf_blue", "nekobi", "zynfx"):
  413. styleSheet2 = "background-image: url(:/bitmaps/background_%s.png);" % self.fSkinStyle
  414. else:
  415. styleSheet2 = "background-color: rgb(%i, %i, %i);" % getColorFromCategory(self.fPluginInfo['category'])
  416. styleSheet2 += "background-image: url(:/bitmaps/background_noise1.png);"
  417. styleSheet = """
  418. QFrame#PluginWidget {
  419. %s
  420. background-repeat: repeat-xy;
  421. }
  422. QLabel#label_name,
  423. QLabel#label_audio_in,
  424. QLabel#label_audio_out,
  425. QLabel#label_midi,
  426. QLabel#label_presets { color: #BBB; }
  427. QLabel#label_name:disabled { color: #555; }
  428. """ % styleSheet2
  429. styleSheet += """
  430. QComboBox#cb_presets,
  431. QLabel#label_audio_in,
  432. QLabel#label_audio_out,
  433. QLabel#label_midi { font-size: 10px; }
  434. """
  435. self.setStyleSheet(styleSheet)
  436. # -------------------------------------------------------------
  437. # Set-up parameters
  438. if self.w_knobs_left is not None:
  439. parameterCount = self.host.get_parameter_count(self.fPluginId)
  440. if "calf" in self.fSkinStyle:
  441. maxWidgets = 7
  442. else:
  443. maxWidgets = 8
  444. index = 0
  445. for i in range(parameterCount):
  446. if index >= maxWidgets:
  447. break
  448. paramInfo = self.host.get_parameter_info(self.fPluginId, i)
  449. paramData = self.host.get_parameter_data(self.fPluginId, i)
  450. paramRanges = self.host.get_parameter_ranges(self.fPluginId, i)
  451. isInteger = (paramData['hints'] & PARAMETER_IS_INTEGER) != 0
  452. if paramData['type'] != PARAMETER_INPUT:
  453. continue
  454. if paramData['hints'] & PARAMETER_IS_BOOLEAN:
  455. continue
  456. if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0:
  457. continue
  458. if (paramData['hints'] & PARAMETER_USES_SCALEPOINTS) != 0 and not isInteger:
  459. # NOTE: we assume integer scalepoints are continuous
  460. continue
  461. if isInteger and paramRanges['max']-paramRanges['min'] <= 3:
  462. continue
  463. if paramInfo['name'].startswith("unused"):
  464. continue
  465. paramName = getParameterShortName(paramInfo['name'])
  466. widget = PixmapDial(self, i)
  467. widget.setLabel(paramName)
  468. widget.setMinimum(paramRanges['min'])
  469. widget.setMaximum(paramRanges['max'])
  470. if isInteger:
  471. widget.setPrecision(paramRanges['max']-paramRanges['min'], True)
  472. setPixmapDialStyle(widget, i, parameterCount, self.fSkinStyle)
  473. index += 1
  474. self.fParameterList.append([i, widget])
  475. self.w_knobs_left.layout().addWidget(widget)
  476. if self.w_knobs_right is not None and (self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) != 0:
  477. widget = PixmapDial(self, PARAMETER_DRYWET)
  478. widget.setLabel("Dry/Wet")
  479. widget.setMinimum(0.0)
  480. widget.setMaximum(1.0)
  481. setPixmapDialStyle(widget, PARAMETER_DRYWET, 0, self.fSkinStyle)
  482. self.fParameterList.append([PARAMETER_DRYWET, widget])
  483. self.w_knobs_right.layout().addWidget(widget)
  484. if self.w_knobs_right is not None and (self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) != 0:
  485. widget = PixmapDial(self, PARAMETER_VOLUME)
  486. widget.setLabel("Volume")
  487. widget.setMinimum(0.0)
  488. widget.setMaximum(1.27)
  489. setPixmapDialStyle(widget, PARAMETER_VOLUME, 0, self.fSkinStyle)
  490. self.fParameterList.append([PARAMETER_VOLUME, widget])
  491. self.w_knobs_right.layout().addWidget(widget)
  492. for paramIndex, paramWidget in self.fParameterList:
  493. paramWidget.setContextMenuPolicy(Qt.CustomContextMenu)
  494. paramWidget.customContextMenuRequested.connect(self.slot_knobCustomMenu)
  495. paramWidget.realValueChanged.connect(self.slot_parameterValueChanged)
  496. paramWidget.blockSignals(True)
  497. paramWidget.setValue(self.host.get_internal_parameter_value(self.fPluginId, paramIndex))
  498. paramWidget.blockSignals(False)
  499. # -------------------------------------------------------------
  500. self.setWindowTitle(self.fPluginInfo['name'])
  501. #------------------------------------------------------------------
  502. def getFixedHeight(self):
  503. return 32
  504. def getHints(self):
  505. return self.fPluginInfo['hints']
  506. def getPluginId(self):
  507. return self.fPluginId
  508. #------------------------------------------------------------------
  509. def setPluginId(self, idx):
  510. self.fPluginId = idx
  511. self.fEditDialog.setPluginId(idx)
  512. def setName(self, name):
  513. self.fPluginInfo['name'] = name
  514. self.fEditDialog.setName(name)
  515. if self.label_name is not None:
  516. self.label_name.setText(name)
  517. def setSelected(self, yesNo):
  518. if self.fIsSelected == yesNo:
  519. return
  520. self.fIsSelected = yesNo
  521. self.update()
  522. #------------------------------------------------------------------
  523. def setActive(self, active, sendCallback=False, sendHost=True):
  524. self.fIsActive = active
  525. if sendCallback:
  526. self.fParameterIconTimer = ICON_STATE_ON
  527. self.activeChanged(active)
  528. if sendHost:
  529. self.host.set_active(self.fPluginId, active)
  530. if active:
  531. self.fEditDialog.clearNotes()
  532. self.midiActivityChanged(False)
  533. if self.label_name is not None:
  534. self.label_name.setEnabled(self.fIsActive)
  535. # called from rack, checks if param is possible first
  536. def setInternalParameter(self, parameterId, value):
  537. if parameterId <= PARAMETER_MAX or parameterId >= PARAMETER_NULL:
  538. return
  539. elif parameterId == PARAMETER_ACTIVE:
  540. return self.setActive(bool(value), True, True)
  541. elif parameterId == PARAMETER_DRYWET:
  542. if (self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET) == 0: return
  543. self.host.set_drywet(self.fPluginId, value)
  544. elif parameterId == PARAMETER_VOLUME:
  545. if (self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME) == 0: return
  546. self.host.set_volume(self.fPluginId, value)
  547. elif parameterId == PARAMETER_BALANCE_LEFT:
  548. if (self.fPluginInfo['hints'] & PLUGIN_CAN_BALANCE) == 0: return
  549. self.host.set_balance_left(self.fPluginId, value)
  550. elif parameterId == PARAMETER_BALANCE_RIGHT:
  551. if (self.fPluginInfo['hints'] & PLUGIN_CAN_BALANCE) == 0: return
  552. self.host.set_balance_right(self.fPluginId, value)
  553. elif parameterId == PARAMETER_PANNING:
  554. if (self.fPluginInfo['hints'] & PLUGIN_CAN_PANNING) == 0: return
  555. self.host.set_panning(self.fPluginId, value)
  556. elif parameterId == PARAMETER_CTRL_CHANNEL:
  557. self.host.set_ctrl_channel(self.fPluginId, value)
  558. self.fEditDialog.setParameterValue(parameterId, value)
  559. #------------------------------------------------------------------
  560. def setParameterValue(self, parameterId, value, sendCallback):
  561. if parameterId == PARAMETER_ACTIVE:
  562. return self.setActive(bool(value), True, False)
  563. self.fEditDialog.setParameterValue(parameterId, value)
  564. if sendCallback:
  565. self.fParameterIconTimer = ICON_STATE_ON
  566. self.editDialogParameterValueChanged(self.fPluginId, parameterId, value)
  567. def setParameterDefault(self, parameterId, value):
  568. self.fEditDialog.setParameterDefault(parameterId, value)
  569. def setParameterMidiControl(self, parameterId, control):
  570. self.fEditDialog.setParameterMidiControl(parameterId, control)
  571. def setParameterMidiChannel(self, parameterId, channel):
  572. self.fEditDialog.setParameterMidiChannel(parameterId, channel)
  573. #------------------------------------------------------------------
  574. def setProgram(self, index, sendCallback):
  575. self.fEditDialog.setProgram(index)
  576. if sendCallback:
  577. self.fParameterIconTimer = ICON_STATE_ON
  578. self.editDialogProgramChanged(self.fPluginId, index)
  579. self.updateParameterValues()
  580. def setMidiProgram(self, index, sendCallback):
  581. self.fEditDialog.setMidiProgram(index)
  582. if sendCallback:
  583. self.fParameterIconTimer = ICON_STATE_ON
  584. self.editDialogMidiProgramChanged(self.fPluginId, index)
  585. self.updateParameterValues()
  586. #------------------------------------------------------------------
  587. def setOption(self, option, yesNo):
  588. self.fEditDialog.setOption(option, yesNo)
  589. #------------------------------------------------------------------
  590. def showCustomUI(self):
  591. self.host.show_custom_ui(self.fPluginId, True)
  592. if self.b_gui is not None:
  593. self.b_gui.setChecked(True)
  594. def showEditDialog(self):
  595. self.fEditDialog.show()
  596. self.fEditDialog.activateWindow()
  597. if self.b_edit is not None:
  598. self.b_edit.setChecked(True)
  599. def showRenameDialog(self):
  600. oldName = self.fPluginInfo['name']
  601. newNameTry = QInputDialog.getText(self, self.tr("Rename Plugin"), self.tr("New plugin name:"), QLineEdit.Normal, oldName)
  602. if not (newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]):
  603. return
  604. newName = newNameTry[0]
  605. if not self.host.rename_plugin(self.fPluginId, newName):
  606. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  607. self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  608. return
  609. self.setName(newName)
  610. def showReplaceDialog(self):
  611. data = gCarla.gui.showAddPluginDialog()
  612. if data is None:
  613. return
  614. btype, ptype, filename, label, uniqueId, extraPtr = data
  615. if not self.host.replace_plugin(self.fPluginId):
  616. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to replace plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  617. return
  618. ok = self.host.add_plugin(btype, ptype, filename, None, label, uniqueId, extraPtr, 0x0)
  619. self.host.replace_plugin(self.host.get_max_plugin_number())
  620. if not ok:
  621. CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  622. #------------------------------------------------------------------
  623. def activeChanged(self, onOff):
  624. self.fIsActive = onOff
  625. if self.b_enable is None:
  626. return
  627. self.b_enable.blockSignals(True)
  628. self.b_enable.setChecked(onOff)
  629. self.b_enable.blockSignals(False)
  630. def customUiStateChanged(self, state):
  631. if self.b_gui is None:
  632. return
  633. self.b_gui.blockSignals(True)
  634. if state == 0:
  635. self.b_gui.setChecked(False)
  636. self.b_gui.setEnabled(True)
  637. elif state == 1:
  638. self.b_gui.setChecked(True)
  639. self.b_gui.setEnabled(True)
  640. elif state == -1:
  641. self.b_gui.setChecked(False)
  642. self.b_gui.setEnabled(False)
  643. self.b_gui.blockSignals(False)
  644. def parameterActivityChanged(self, onOff):
  645. if self.led_control is None:
  646. return
  647. self.led_control.setChecked(onOff)
  648. def midiActivityChanged(self, onOff):
  649. if self.led_midi is None:
  650. return
  651. self.led_midi.setChecked(onOff)
  652. def optionChanged(self, option, yesNo):
  653. pass
  654. # -----------------------------------------------------------------
  655. # PluginEdit callbacks
  656. def editDialogVisibilityChanged(self, pluginId, visible):
  657. if self.b_edit is None:
  658. return
  659. self.b_edit.blockSignals(True)
  660. self.b_edit.setChecked(visible)
  661. self.b_edit.blockSignals(False)
  662. def editDialogPluginHintsChanged(self, pluginId, hints):
  663. self.fPluginInfo['hints'] = hints
  664. for paramIndex, paramWidget in self.fParameterList:
  665. if paramIndex == PARAMETER_DRYWET:
  666. paramWidget.setVisible(hints & PLUGIN_CAN_DRYWET)
  667. elif paramIndex == PARAMETER_VOLUME:
  668. paramWidget.setVisible(hints & PLUGIN_CAN_VOLUME)
  669. if self.b_gui is not None:
  670. self.b_gui.setEnabled(bool(hints & PLUGIN_HAS_CUSTOM_UI))
  671. def editDialogParameterValueChanged(self, pluginId, parameterId, value):
  672. for paramIndex, paramWidget in self.fParameterList:
  673. if paramIndex != parameterId:
  674. continue
  675. paramWidget.blockSignals(True)
  676. paramWidget.setValue(value)
  677. paramWidget.blockSignals(False)
  678. break
  679. def editDialogProgramChanged(self, pluginId, index):
  680. if self.cb_presets is None:
  681. return
  682. self.cb_presets.blockSignals(True)
  683. self.cb_presets.setCurrentIndex(index)
  684. self.cb_presets.blockSignals(False)
  685. # FIXME
  686. self.updateParameterValues()
  687. def editDialogMidiProgramChanged(self, pluginId, index):
  688. if self.cb_presets is None:
  689. return
  690. self.cb_presets.blockSignals(True)
  691. self.cb_presets.setCurrentIndex(index)
  692. self.cb_presets.blockSignals(False)
  693. # FIXME
  694. self.updateParameterValues()
  695. def editDialogNotePressed(self, pluginId, note):
  696. pass
  697. def editDialogNoteReleased(self, pluginId, note):
  698. pass
  699. def editDialogMidiActivityChanged(self, pluginId, onOff):
  700. self.midiActivityChanged(onOff)
  701. #------------------------------------------------------------------
  702. def idleFast(self):
  703. # Input peaks
  704. if self.fPeaksInputCount > 0:
  705. if self.fPeaksInputCount > 1:
  706. peak1 = self.host.get_input_peak_value(self.fPluginId, True)
  707. peak2 = self.host.get_input_peak_value(self.fPluginId, False)
  708. ledState = bool(peak1 != 0.0 or peak2 != 0.0)
  709. if self.peak_in is not None:
  710. self.peak_in.displayMeter(1, peak1)
  711. self.peak_in.displayMeter(2, peak2)
  712. else:
  713. peak = self.host.get_input_peak_value(self.fPluginId, True)
  714. ledState = bool(peak != 0.0)
  715. if self.peak_in is not None:
  716. self.peak_in.displayMeter(1, peak)
  717. if self.fLastGreenLedState != ledState and self.led_audio_in is not None:
  718. self.fLastGreenLedState = ledState
  719. self.led_audio_in.setChecked(ledState)
  720. # Output peaks
  721. if self.fPeaksOutputCount > 0:
  722. if self.fPeaksOutputCount > 1:
  723. peak1 = self.host.get_output_peak_value(self.fPluginId, True)
  724. peak2 = self.host.get_output_peak_value(self.fPluginId, False)
  725. ledState = bool(peak1 != 0.0 or peak2 != 0.0)
  726. if self.peak_out is not None:
  727. self.peak_out.displayMeter(1, peak1)
  728. self.peak_out.displayMeter(2, peak2)
  729. else:
  730. peak = self.host.get_output_peak_value(self.fPluginId, True)
  731. ledState = bool(peak != 0.0)
  732. if self.peak_out is not None:
  733. self.peak_out.displayMeter(1, peak)
  734. if self.fLastBlueLedState != ledState and self.led_audio_out is not None:
  735. self.fLastBlueLedState = ledState
  736. self.led_audio_out.setChecked(ledState)
  737. def idleSlow(self):
  738. if self.fParameterIconTimer == ICON_STATE_ON:
  739. self.parameterActivityChanged(True)
  740. self.fParameterIconTimer = ICON_STATE_WAIT
  741. elif self.fParameterIconTimer == ICON_STATE_WAIT:
  742. self.fParameterIconTimer = ICON_STATE_OFF
  743. elif self.fParameterIconTimer == ICON_STATE_OFF:
  744. self.parameterActivityChanged(False)
  745. self.fParameterIconTimer = ICON_STATE_NULL
  746. self.fEditDialog.idleSlow()
  747. #------------------------------------------------------------------
  748. def drawOutline(self):
  749. painter = QPainter(self)
  750. if self.fIsSelected:
  751. painter.setPen(QPen(Qt.cyan, 4))
  752. painter.setBrush(Qt.transparent)
  753. painter.drawRect(0, 0, self.width(), self.height())
  754. else:
  755. painter.setPen(QPen(Qt.black, 1))
  756. painter.setBrush(Qt.black)
  757. painter.drawLine(0, self.height()-1, self.width(), self.height()-1)
  758. def updateParameterValues(self):
  759. for paramIndex, paramWidget in self.fParameterList:
  760. if paramIndex < 0:
  761. continue
  762. paramWidget.blockSignals(True)
  763. paramWidget.setValue(self.host.get_current_parameter_value(self.fPluginId, paramIndex))
  764. paramWidget.blockSignals(False)
  765. #------------------------------------------------------------------
  766. @pyqtSlot(bool)
  767. def slot_enableClicked(self, yesNo):
  768. self.setActive(yesNo, False, True)
  769. @pyqtSlot()
  770. def slot_showCustomMenu(self):
  771. menu = QMenu(self)
  772. # -------------------------------------------------------------
  773. # Expand/Minimize
  774. actCompact = menu.addAction(self.tr("Expand") if isinstance(self, PluginSlot_Compact) else self.tr("Minimize"))
  775. menu.addSeparator()
  776. # -------------------------------------------------------------
  777. # Move up and down
  778. actMoveUp = menu.addAction(self.tr("Move Up"))
  779. actMoveDown = menu.addAction(self.tr("Move Down"))
  780. if self.fPluginId == 0:
  781. actMoveUp.setEnabled(False)
  782. if self.fPluginId >= self.fParent.getPluginCount():
  783. actMoveDown.setEnabled(False)
  784. # -------------------------------------------------------------
  785. # Bypass and Enable/Disable
  786. actBypass = menu.addAction(self.tr("Bypass"))
  787. actEnable = menu.addAction(self.tr("Disable") if self.fIsActive else self.tr("Enable"))
  788. menu.addSeparator()
  789. if self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET:
  790. actBypass.setCheckable(True)
  791. actBypass.setChecked(self.host.get_internal_parameter_value(self.fPluginId, PARAMETER_DRYWET) == 0.0)
  792. else:
  793. actBypass.setVisible(False)
  794. # -------------------------------------------------------------
  795. # Reset and Randomize parameters
  796. actReset = menu.addAction(self.tr("Reset parameters"))
  797. actRandom = menu.addAction(self.tr("Randomize parameters"))
  798. menu.addSeparator()
  799. # -------------------------------------------------------------
  800. # Edit and Show Custom UI
  801. actEdit = menu.addAction(self.tr("Edit"))
  802. actGui = menu.addAction(self.tr("Show Custom UI"))
  803. menu.addSeparator()
  804. if self.b_edit is not None:
  805. actEdit.setCheckable(True)
  806. actEdit.setChecked(self.b_edit.isChecked())
  807. else:
  808. actEdit.setVisible(False)
  809. if self.b_gui is not None:
  810. actGui.setCheckable(True)
  811. actGui.setChecked(self.b_gui.isChecked())
  812. actGui.setEnabled(self.b_gui.isEnabled())
  813. else:
  814. actGui.setVisible(False)
  815. # -------------------------------------------------------------
  816. # Other stuff
  817. actClone = menu.addAction(self.tr("Clone"))
  818. actRename = menu.addAction(self.tr("Rename..."))
  819. actReplace = menu.addAction(self.tr("Replace..."))
  820. actRemove = menu.addAction(self.tr("Remove"))
  821. if self.fIdleTimerId != 0:
  822. actRemove.setVisible(False)
  823. if self.host.exportLV2:
  824. menu.addSeparator()
  825. actExportLV2 = menu.addAction(self.tr("Export LV2..."))
  826. else:
  827. actExportLV2 = None
  828. # -------------------------------------------------------------
  829. # exec
  830. actSel = menu.exec_(QCursor.pos())
  831. if not actSel:
  832. return
  833. # -------------------------------------------------------------
  834. # Expand/Minimize
  835. elif actSel == actCompact:
  836. # FIXME
  837. gCarla.gui.compactPlugin(self.fPluginId)
  838. # -------------------------------------------------------------
  839. # Move up and down
  840. elif actSel == actMoveUp:
  841. gCarla.gui.switchPlugins(self.fPluginId, self.fPluginId-1)
  842. elif actSel == actMoveDown:
  843. gCarla.gui.switchPlugins(self.fPluginId, self.fPluginId+1)
  844. # -------------------------------------------------------------
  845. # Bypass and Enable/Disable
  846. elif actSel == actBypass:
  847. value = 0.0 if actBypass.isChecked() else 1.0
  848. self.host.set_drywet(self.fPluginId, value)
  849. self.setParameterValue(PARAMETER_DRYWET, value, True)
  850. elif actSel == actEnable:
  851. self.setActive(not self.fIsActive, True, True)
  852. # -------------------------------------------------------------
  853. # Reset and Randomize parameters
  854. elif actSel == actReset:
  855. self.host.reset_parameters(self.fPluginId)
  856. elif actSel == actRandom:
  857. self.host.randomize_parameters(self.fPluginId)
  858. # -------------------------------------------------------------
  859. # Edit and Show Custom UI
  860. elif actSel == actEdit:
  861. self.b_edit.click()
  862. elif actSel == actGui:
  863. self.b_gui.click()
  864. # -------------------------------------------------------------
  865. # Clone
  866. elif actSel == actClone:
  867. if not self.host.clone_plugin(self.fPluginId):
  868. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  869. self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  870. # -------------------------------------------------------------
  871. # Rename
  872. elif actSel == actRename:
  873. self.showRenameDialog()
  874. # -------------------------------------------------------------
  875. # Replace
  876. elif actSel == actReplace:
  877. self.showReplaceDialog()
  878. # -------------------------------------------------------------
  879. # Remove
  880. elif actSel == actRemove:
  881. if not self.host.remove_plugin(self.fPluginId):
  882. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  883. self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  884. # -------------------------------------------------------------
  885. # Export LV2
  886. elif actSel == actExportLV2:
  887. filepath = QInputDialog.getItem(self, self.tr("Export LV2 Plugin"),
  888. self.tr("Select LV2 Path where plugin will be exported to:"),
  889. CARLA_DEFAULT_LV2_PATH, editable=False)
  890. if not all(filepath):
  891. return
  892. plugname = self.fPluginInfo['name']
  893. filepath = os.path.join(filepath[0], plugname.replace(" ","_"))
  894. if not filepath.endswith(".lv2"):
  895. filepath += ".lv2"
  896. if os.path.exists(filepath):
  897. if QMessageBox.question(self, self.tr("Export to LV2"),
  898. self.tr("Plugin bundle already exists, overwrite?")) == QMessageBox.Ok:
  899. return
  900. if not self.host.export_plugin_lv2(self.fPluginId, filepath):
  901. return CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  902. self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  903. QMessageBox.information(self, self.tr("Plugin exported"),
  904. self.tr("Plugin exported successfully, saved in folder:\n%s" % filepath))
  905. # -------------------------------------------------------------
  906. @pyqtSlot()
  907. def slot_knobCustomMenu(self):
  908. sender = self.sender()
  909. index = sender.fIndex
  910. minimum = sender.fMinimum
  911. maximum = sender.fMaximum
  912. current = sender.fRealValue
  913. label = sender.fLabel
  914. if index in (PARAMETER_NULL, PARAMETER_CTRL_CHANNEL) or index <= PARAMETER_MAX:
  915. return
  916. elif index in (PARAMETER_DRYWET, PARAMETER_VOLUME):
  917. default = 1.0
  918. elif index == PARAMETER_BALANCE_LEFT:
  919. default = -1.0
  920. elif index == PARAMETER_BALANCE_RIGHT:
  921. default = 1.0
  922. elif index == PARAMETER_PANNING:
  923. default = 0.0
  924. else:
  925. default = self.host.get_default_parameter_value(self.fPluginId, index)
  926. if index < PARAMETER_NULL:
  927. # show in integer percentage
  928. textReset = self.tr("Reset (%i%%)" % round(default*100.0))
  929. textMinim = self.tr("Set to Minimum (%i%%)" % round(minimum*100.0))
  930. textMaxim = self.tr("Set to Maximum (%i%%)" % round(maximum*100.0))
  931. else:
  932. # show in full float value
  933. textReset = self.tr("Reset (%f)" % default)
  934. textMinim = self.tr("Set to Minimum (%f)" % minimum)
  935. textMaxim = self.tr("Set to Maximum (%f)" % maximum)
  936. menu = QMenu(self)
  937. actReset = menu.addAction(textReset)
  938. menu.addSeparator()
  939. actMinimum = menu.addAction(textMinim)
  940. actCenter = menu.addAction(self.tr("Set to Center"))
  941. actMaximum = menu.addAction(textMaxim)
  942. menu.addSeparator()
  943. actSet = menu.addAction(self.tr("Set value..."))
  944. if index > PARAMETER_NULL or index not in (PARAMETER_BALANCE_LEFT, PARAMETER_BALANCE_RIGHT, PARAMETER_PANNING):
  945. menu.removeAction(actCenter)
  946. actSelected = menu.exec_(QCursor.pos())
  947. if actSelected == actSet:
  948. if index < PARAMETER_NULL:
  949. value, ok = QInputDialog.getInt(self, self.tr("Set value"), label, round(current*100), round(minimum*100), round(maximum*100), 1)
  950. if not ok:
  951. return
  952. value = float(value)/100.0
  953. else:
  954. paramInfo = self.host.get_parameter_info(self.fPluginId, index)
  955. paramRanges = self.host.get_parameter_ranges(self.fPluginId, index)
  956. scalePoints = []
  957. for i in range(paramInfo['scalePointCount']):
  958. scalePoints.append(self.host.get_parameter_scalepoint_info(self.fPluginId, index, i))
  959. dialog = CustomInputDialog(self, label, current, minimum, maximum,
  960. paramRanges['step'], paramRanges['stepSmall'], scalePoints)
  961. if not dialog.exec_():
  962. return
  963. value = dialog.returnValue()
  964. elif actSelected == actMinimum:
  965. value = minimum
  966. elif actSelected == actMaximum:
  967. value = maximum
  968. elif actSelected == actReset:
  969. value = default
  970. elif actSelected == actCenter:
  971. value = 0.0
  972. else:
  973. return
  974. sender.setValue(value, True)
  975. #------------------------------------------------------------------
  976. @pyqtSlot(bool)
  977. def slot_showCustomUi(self, show):
  978. self.host.show_custom_ui(self.fPluginId, show)
  979. @pyqtSlot(bool)
  980. def slot_showEditDialog(self, show):
  981. self.fEditDialog.setVisible(show)
  982. @pyqtSlot()
  983. def slot_removePlugin(self):
  984. if not self.host.remove_plugin(self.fPluginId):
  985. CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"),
  986. self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok)
  987. #------------------------------------------------------------------
  988. @pyqtSlot(float)
  989. def slot_parameterValueChanged(self, value):
  990. index = self.sender().getIndex()
  991. if index < 0:
  992. self.setInternalParameter(index, value)
  993. else:
  994. self.host.set_parameter_value(self.fPluginId, index, value)
  995. self.setParameterValue(index, value, False)
  996. @pyqtSlot(int)
  997. def slot_programChanged(self, index):
  998. self.host.set_program(self.fPluginId, index)
  999. self.setProgram(index, False)
  1000. @pyqtSlot(int)
  1001. def slot_midiProgramChanged(self, index):
  1002. self.host.set_midi_program(self.fPluginId, index)
  1003. self.setMidiProgram(index, False)
  1004. #------------------------------------------------------------------
  1005. def testTimer(self):
  1006. self.fIdleTimerId = self.startTimer(25)
  1007. #------------------------------------------------------------------
  1008. def mouseDoubleClickEvent(self, event):
  1009. QFrame.mouseDoubleClickEvent(self, event)
  1010. # FIXME
  1011. gCarla.gui.compactPlugin(self.fPluginId)
  1012. def closeEvent(self, event):
  1013. if self.fIdleTimerId != 0:
  1014. self.killTimer(self.fIdleTimerId)
  1015. self.fIdleTimerId = 0
  1016. self.host.engine_close()
  1017. QFrame.closeEvent(self, event)
  1018. def timerEvent(self, event):
  1019. if event.timerId() == self.fIdleTimerId:
  1020. self.host.engine_idle()
  1021. self.idleFast()
  1022. self.idleSlow()
  1023. QFrame.timerEvent(self, event)
  1024. def paintEvent(self, event):
  1025. self.drawOutline()
  1026. QFrame.paintEvent(self, event)
  1027. # ------------------------------------------------------------------------------------------------------------
  1028. class PluginSlot_Calf(AbstractPluginSlot):
  1029. def __init__(self, parent, host, pluginId, skinStyle):
  1030. AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle)
  1031. self.ui = ui_carla_plugin_calf.Ui_PluginWidget()
  1032. self.ui.setupUi(self)
  1033. audioCount = self.host.get_audio_port_count_info(self.fPluginId)
  1034. midiCount = self.host.get_midi_port_count_info(self.fPluginId)
  1035. # -------------------------------------------------------------
  1036. # Internal stuff
  1037. self.fButtonFont = self.ui.b_gui.font()
  1038. self.fButtonFont.setBold(False)
  1039. self.fButtonFont.setPixelSize(10)
  1040. self.fButtonColorOn = QColor( 18, 41, 87)
  1041. self.fButtonColorOff = QColor(150, 150, 150)
  1042. # -------------------------------------------------------------
  1043. # Set-up GUI
  1044. self.ui.label_active.setFont(self.fButtonFont)
  1045. self.ui.b_remove.setPixmaps(":/bitmaps/button_calf1.png", ":/bitmaps/button_calf1_down.png", ":/bitmaps/button_calf1_hover.png")
  1046. self.ui.b_edit.setTopText(self.tr("Edit"), self.fButtonColorOn, self.fButtonFont)
  1047. self.ui.b_remove.setTopText(self.tr("Remove"), self.fButtonColorOn, self.fButtonFont)
  1048. if self.fPluginInfo['hints'] & PLUGIN_HAS_CUSTOM_UI:
  1049. self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOn, self.fButtonFont)
  1050. else:
  1051. self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOff, self.fButtonFont)
  1052. if audioCount['ins'] == 0:
  1053. self.ui.label_audio_in.hide()
  1054. if audioCount['outs'] == 0:
  1055. self.ui.label_audio_out.hide()
  1056. if midiCount['ins'] == 0:
  1057. self.ui.label_midi.hide()
  1058. self.ui.led_midi.hide()
  1059. if self.fIdleTimerId != 0:
  1060. self.ui.b_remove.setEnabled(False)
  1061. self.ui.b_remove.setVisible(False)
  1062. # -------------------------------------------------------------
  1063. self.b_enable = self.ui.b_enable
  1064. self.b_gui = self.ui.b_gui
  1065. self.b_edit = self.ui.b_edit
  1066. self.b_remove = self.ui.b_remove
  1067. self.label_name = self.ui.label_name
  1068. self.led_midi = self.ui.led_midi
  1069. self.peak_in = self.ui.peak_in
  1070. self.peak_out = self.ui.peak_out
  1071. self.w_knobs_left = self.ui.w_knobs
  1072. self.ready()
  1073. self.ui.led_midi.setColor(self.ui.led_midi.CALF)
  1074. #------------------------------------------------------------------
  1075. def getFixedHeight(self):
  1076. return 94 if max(self.peak_in.channelCount(), self.peak_out.channelCount()) < 2 else 106
  1077. #------------------------------------------------------------------
  1078. def editDialogPluginHintsChanged(self, pluginId, hints):
  1079. if hints & PLUGIN_HAS_CUSTOM_UI:
  1080. self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOn, self.fButtonFont)
  1081. else:
  1082. self.ui.b_gui.setTopText(self.tr("GUI"), self.fButtonColorOff, self.fButtonFont)
  1083. AbstractPluginSlot.editDialogPluginHintsChanged(self, pluginId, hints)
  1084. #------------------------------------------------------------------
  1085. def paintEvent(self, event):
  1086. isBlack = bool(self.fSkinStyle == "calf_black")
  1087. painter = QPainter(self)
  1088. painter.setBrush(Qt.transparent)
  1089. painter.setPen(QPen(QColor(20, 20, 20) if isBlack else QColor(75, 86, 99), 1))
  1090. painter.drawRect(0, 1, self.width()-1, self.height()-3)
  1091. painter.setPen(QPen(QColor(45, 45, 45) if isBlack else QColor(86, 99, 114), 1))
  1092. painter.drawLine(0, 0, self.width(), 0)
  1093. AbstractPluginSlot.paintEvent(self, event)
  1094. # ------------------------------------------------------------------------------------------------------------
  1095. class PluginSlot_Classic(AbstractPluginSlot):
  1096. def __init__(self, parent, host, pluginId):
  1097. AbstractPluginSlot.__init__(self, parent, host, pluginId, "classic")
  1098. self.ui = ui_carla_plugin_classic.Ui_PluginWidget()
  1099. self.ui.setupUi(self)
  1100. # -------------------------------------------------------------
  1101. # Internal stuff
  1102. self.fColorTop = QColor(60, 60, 60)
  1103. self.fColorBottom = QColor(47, 47, 47)
  1104. self.fColorSeprtr = QColor(70, 70, 70)
  1105. # -------------------------------------------------------------
  1106. self.b_enable = self.ui.b_enable
  1107. self.b_gui = self.ui.b_gui
  1108. self.b_edit = self.ui.b_edit
  1109. self.label_name = self.ui.label_name
  1110. self.led_control = self.ui.led_control
  1111. self.led_midi = self.ui.led_midi
  1112. self.led_audio_in = self.ui.led_audio_in
  1113. self.led_audio_out = self.ui.led_audio_out
  1114. self.peak_in = self.ui.peak_in
  1115. self.peak_out = self.ui.peak_out
  1116. self.ready()
  1117. #------------------------------------------------------------------
  1118. def getFixedHeight(self):
  1119. return 36
  1120. #------------------------------------------------------------------
  1121. def paintEvent(self, event):
  1122. painter = QPainter(self)
  1123. painter.save()
  1124. areaX = self.ui.area_right.x()+7
  1125. width = self.width()
  1126. height = self.height()
  1127. painter.setPen(QPen(QColor(17, 17, 17), 1))
  1128. painter.setBrush(QColor(17, 17, 17))
  1129. painter.drawRect(0, 0, width, height)
  1130. painter.setPen(self.fColorSeprtr.lighter(110))
  1131. painter.setBrush(self.fColorBottom)
  1132. painter.setRenderHint(QPainter.Antialiasing, True)
  1133. # name -> leds arc
  1134. path = QPainterPath()
  1135. path.moveTo(areaX-20, height-4)
  1136. path.cubicTo(areaX, height-5, areaX-20, 4.75, areaX, 4.75)
  1137. path.lineTo(areaX, height-5)
  1138. painter.drawPath(path)
  1139. painter.setPen(self.fColorSeprtr)
  1140. painter.setRenderHint(QPainter.Antialiasing, False)
  1141. # separator lines
  1142. painter.drawLine(0, height-5, areaX-20, height-5)
  1143. painter.drawLine(areaX, 4, width, 4)
  1144. painter.setPen(self.fColorBottom)
  1145. painter.setBrush(self.fColorBottom)
  1146. # top, bottom and left lines
  1147. painter.drawLine(0, 0, width, 0)
  1148. painter.drawRect(0, height-4, areaX, 4)
  1149. painter.drawRoundedRect(areaX-20, height-5, areaX, 5, 22, 22)
  1150. painter.drawLine(0, 0, 0, height)
  1151. # fill the rest
  1152. painter.drawRect(areaX-1, 5, width, height)
  1153. # bottom 1px line
  1154. painter.setPen(self.fColorSeprtr)
  1155. painter.drawLine(0, height-1, width, height-1)
  1156. painter.restore()
  1157. AbstractPluginSlot.paintEvent(self, event)
  1158. # ------------------------------------------------------------------------------------------------------------
  1159. class PluginSlot_Compact(AbstractPluginSlot):
  1160. def __init__(self, parent, host, pluginId, skinStyle):
  1161. AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle)
  1162. self.ui = ui_carla_plugin_compact.Ui_PluginWidget()
  1163. self.ui.setupUi(self)
  1164. self.b_enable = self.ui.b_enable
  1165. self.b_gui = self.ui.b_gui
  1166. self.b_edit = self.ui.b_edit
  1167. self.label_name = self.ui.label_name
  1168. self.led_control = self.ui.led_control
  1169. self.led_midi = self.ui.led_midi
  1170. self.led_audio_in = self.ui.led_audio_in
  1171. self.led_audio_out = self.ui.led_audio_out
  1172. self.peak_in = self.ui.peak_in
  1173. self.peak_out = self.ui.peak_out
  1174. self.ready()
  1175. #------------------------------------------------------------------
  1176. def getFixedHeight(self):
  1177. if self.fSkinStyle == "calf_blue":
  1178. return 36
  1179. return 30
  1180. # ------------------------------------------------------------------------------------------------------------
  1181. class PluginSlot_Default(AbstractPluginSlot):
  1182. def __init__(self, parent, host, pluginId, skinStyle):
  1183. AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle)
  1184. self.ui = ui_carla_plugin_default.Ui_PluginWidget()
  1185. self.ui.setupUi(self)
  1186. # -------------------------------------------------------------
  1187. self.b_enable = self.ui.b_enable
  1188. self.b_gui = self.ui.b_gui
  1189. self.b_edit = self.ui.b_edit
  1190. self.label_name = self.ui.label_name
  1191. self.led_control = self.ui.led_control
  1192. self.led_midi = self.ui.led_midi
  1193. self.led_audio_in = self.ui.led_audio_in
  1194. self.led_audio_out = self.ui.led_audio_out
  1195. self.peak_in = self.ui.peak_in
  1196. self.peak_out = self.ui.peak_out
  1197. self.w_knobs_left = self.ui.w_knobs_left
  1198. self.w_knobs_right = self.ui.w_knobs_right
  1199. self.ready()
  1200. #------------------------------------------------------------------
  1201. def getFixedHeight(self):
  1202. return 80
  1203. #------------------------------------------------------------------
  1204. def paintEvent(self, event):
  1205. painter = QPainter(self)
  1206. painter.setBrush(Qt.transparent)
  1207. painter.setPen(QPen(QColor(42, 42, 42), 1))
  1208. painter.drawRect(0, 1, self.width()-1, self.getFixedHeight()-3)
  1209. painter.setPen(QPen(QColor(60, 60, 60), 1))
  1210. painter.drawLine(0, 0, self.width(), 0)
  1211. AbstractPluginSlot.paintEvent(self, event)
  1212. # ------------------------------------------------------------------------------------------------------------
  1213. class PluginSlot_Presets(AbstractPluginSlot):
  1214. def __init__(self, parent, host, pluginId, skinStyle):
  1215. AbstractPluginSlot.__init__(self, parent, host, pluginId, skinStyle)
  1216. self.ui = ui_carla_plugin_presets.Ui_PluginWidget()
  1217. self.ui.setupUi(self)
  1218. usingMidiPrograms = bool(skinStyle != "presets")
  1219. # -------------------------------------------------------------
  1220. # Set-up programs
  1221. if usingMidiPrograms:
  1222. programCount = self.host.get_midi_program_count(self.fPluginId)
  1223. else:
  1224. programCount = self.host.get_program_count(self.fPluginId)
  1225. if programCount > 0:
  1226. self.ui.cb_presets.setEnabled(True)
  1227. self.ui.label_presets.setEnabled(True)
  1228. for i in range(programCount):
  1229. if usingMidiPrograms:
  1230. progName = self.host.get_midi_program_data(self.fPluginId, i)['name']
  1231. else:
  1232. progName = self.host.get_program_name(self.fPluginId, i)
  1233. self.ui.cb_presets.addItem(progName)
  1234. if usingMidiPrograms:
  1235. curProg = self.host.get_current_midi_program_index(self.fPluginId)
  1236. else:
  1237. curProg = self.host.get_current_program_index(self.fPluginId)
  1238. self.ui.cb_presets.setCurrentIndex(curProg)
  1239. else:
  1240. self.ui.cb_presets.setEnabled(False)
  1241. self.ui.cb_presets.setVisible(False)
  1242. self.ui.label_presets.setEnabled(False)
  1243. self.ui.label_presets.setVisible(False)
  1244. # -------------------------------------------------------------
  1245. self.b_enable = self.ui.b_enable
  1246. self.b_gui = self.ui.b_gui
  1247. self.b_edit = self.ui.b_edit
  1248. self.cb_presets = self.ui.cb_presets
  1249. self.label_name = self.ui.label_name
  1250. self.label_presets = self.ui.label_presets
  1251. self.led_control = self.ui.led_control
  1252. self.led_midi = self.ui.led_midi
  1253. self.led_audio_in = self.ui.led_audio_in
  1254. self.led_audio_out = self.ui.led_audio_out
  1255. self.peak_in = self.ui.peak_in
  1256. self.peak_out = self.ui.peak_out
  1257. if skinStyle == "zynfx":
  1258. self.setupZynFxParams()
  1259. else:
  1260. self.w_knobs_left = self.ui.w_knobs_left
  1261. self.w_knobs_right = self.ui.w_knobs_right
  1262. self.ready()
  1263. if usingMidiPrograms:
  1264. self.ui.cb_presets.currentIndexChanged.connect(self.slot_midiProgramChanged)
  1265. else:
  1266. self.ui.cb_presets.currentIndexChanged.connect(self.slot_programChanged)
  1267. # -------------------------------------------------------------
  1268. def setupZynFxParams(self):
  1269. parameterCount = self.host.get_parameter_count(self.fPluginId)
  1270. index = 0
  1271. for i in range(parameterCount):
  1272. if index >= 8:
  1273. break
  1274. paramInfo = self.host.get_parameter_info(self.fPluginId, i)
  1275. paramData = self.host.get_parameter_data(self.fPluginId, i)
  1276. paramRanges = self.host.get_parameter_ranges(self.fPluginId, i)
  1277. if paramData['type'] != PARAMETER_INPUT:
  1278. continue
  1279. if paramData['hints'] & PARAMETER_IS_BOOLEAN:
  1280. continue
  1281. if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0:
  1282. continue
  1283. paramName = paramInfo['name']
  1284. if paramName.startswith("unused"):
  1285. continue
  1286. # real zyn fx plugins
  1287. if self.fPluginInfo['label'] == "zynalienwah":
  1288. if i == 0: paramName = "Freq"
  1289. elif i == 1: paramName = "Rnd"
  1290. elif i == 2: paramName = "L type" # combobox
  1291. elif i == 3: paramName = "St.df"
  1292. elif i == 5: paramName = "Fb"
  1293. elif i == 7: paramName = "L/R"
  1294. elif self.fPluginInfo['label'] == "zynchorus":
  1295. if i == 0: paramName = "Freq"
  1296. elif i == 1: paramName = "Rnd"
  1297. elif i == 2: paramName = "L type" # combobox
  1298. elif i == 3: paramName = "St.df"
  1299. elif i == 6: paramName = "Fb"
  1300. elif i == 7: paramName = "L/R"
  1301. elif i == 8: paramName = "Flngr" # button
  1302. elif i == 9: paramName = "Subst" # button
  1303. elif self.fPluginInfo['label'] == "zyndistortion":
  1304. if i == 0: paramName = "LRc."
  1305. elif i == 4: paramName = "Neg." # button
  1306. elif i == 5: paramName = "LPF"
  1307. elif i == 6: paramName = "HPF"
  1308. elif i == 7: paramName = "St." # button
  1309. elif i == 8: paramName = "PF" # button
  1310. elif self.fPluginInfo['label'] == "zyndynamicfilter":
  1311. if i == 0: paramName = "Freq"
  1312. elif i == 1: paramName = "Rnd"
  1313. elif i == 2: paramName = "L type" # combobox
  1314. elif i == 3: paramName = "St.df"
  1315. elif i == 4: paramName = "LfoD"
  1316. elif i == 5: paramName = "A.S."
  1317. elif i == 6: paramName = "A.Inv." # button
  1318. elif i == 7: paramName = "A.M."
  1319. elif self.fPluginInfo['label'] == "zynecho":
  1320. if i == 1: paramName = "LRdl."
  1321. elif i == 2: paramName = "LRc."
  1322. elif i == 3: paramName = "Fb."
  1323. elif i == 4: paramName = "Damp"
  1324. elif self.fPluginInfo['label'] == "zynphaser":
  1325. if i == 0: paramName = "Freq"
  1326. elif i == 1: paramName = "Rnd"
  1327. elif i == 2: paramName = "L type" # combobox
  1328. elif i == 3: paramName = "St.df"
  1329. elif i == 5: paramName = "Fb"
  1330. elif i == 7: paramName = "L/R"
  1331. elif i == 8: paramName = "Subst" # button
  1332. elif i == 9: paramName = "Phase"
  1333. elif i == 11: paramName = "Dist"
  1334. elif self.fPluginInfo['label'] == "zynreverb":
  1335. if i == 2: paramName = "I.delfb"
  1336. elif i == 5: paramName = "LPF"
  1337. elif i == 6: paramName = "HPF"
  1338. elif i == 9: paramName = "R.S."
  1339. elif i == 10: paramName = "I.del"
  1340. else:
  1341. paramName = getParameterShortName(paramName)
  1342. widget = PixmapDial(self, i)
  1343. widget.setLabel(paramName)
  1344. widget.setMinimum(paramRanges['min'])
  1345. widget.setMaximum(paramRanges['max'])
  1346. widget.setPixmap(3)
  1347. widget.setCustomPaintColor(QColor(83, 173, 10))
  1348. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR)
  1349. widget.forceWhiteLabelGradientText()
  1350. if (paramData['hints'] & PARAMETER_IS_ENABLED) == 0:
  1351. widget.setEnabled(False)
  1352. self.fParameterList.append([i, widget])
  1353. self.ui.w_knobs_left.layout().addWidget(widget)
  1354. if self.fPluginInfo['hints'] & PLUGIN_CAN_DRYWET:
  1355. widget = PixmapDial(self, PARAMETER_DRYWET)
  1356. widget.setLabel("Wet")
  1357. widget.setMinimum(0.0)
  1358. widget.setMaximum(1.0)
  1359. widget.setPixmap(3)
  1360. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_WET)
  1361. widget.forceWhiteLabelGradientText()
  1362. self.fParameterList.append([PARAMETER_DRYWET, widget])
  1363. self.ui.w_knobs_right.layout().addWidget(widget)
  1364. if self.fPluginInfo['hints'] & PLUGIN_CAN_VOLUME:
  1365. widget = PixmapDial(self, PARAMETER_VOLUME)
  1366. widget.setLabel("Volume")
  1367. widget.setMinimum(0.0)
  1368. widget.setMaximum(1.27)
  1369. widget.setPixmap(3)
  1370. widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_CARLA_VOL)
  1371. widget.forceWhiteLabelGradientText()
  1372. self.fParameterList.append([PARAMETER_VOLUME, widget])
  1373. self.ui.w_knobs_right.layout().addWidget(widget)
  1374. #------------------------------------------------------------------
  1375. def getFixedHeight(self):
  1376. return 80
  1377. #------------------------------------------------------------------
  1378. def paintEvent(self, event):
  1379. painter = QPainter(self)
  1380. painter.setBrush(Qt.transparent)
  1381. painter.setPen(QPen(QColor(50, 50, 50), 1))
  1382. painter.drawRect(0, 1, self.width()-1, self.height()-3)
  1383. painter.setPen(QPen(QColor(64, 64, 64), 1))
  1384. painter.drawLine(0, 0, self.width(), 0)
  1385. AbstractPluginSlot.paintEvent(self, event)
  1386. # ------------------------------------------------------------------------------------------------------------
  1387. def getSkinStyle(host, pluginId):
  1388. if False:
  1389. # kdevelop likes this :)
  1390. host = CarlaHostNull()
  1391. progCount = 0
  1392. pluginInfo = PyCarlaPluginInfo
  1393. pluginName = ""
  1394. pluginInfo = host.get_plugin_info(pluginId)
  1395. pluginName = host.get_real_plugin_name(pluginId)
  1396. pluginLabel = pluginInfo['label'].lower()
  1397. pluginMaker = pluginInfo['maker']
  1398. uniqueId = pluginInfo['uniqueId']
  1399. if pluginInfo['type'] == PLUGIN_VST2:
  1400. progCount = host.get_program_count(pluginId)
  1401. else:
  1402. progCount = host.get_midi_program_count(pluginId)
  1403. # Samplers
  1404. if pluginInfo['type'] == PLUGIN_SF2:
  1405. return "sf2"
  1406. if pluginInfo['type'] == PLUGIN_SFZ:
  1407. return "sfz"
  1408. # Calf
  1409. if pluginName.split(" ", 1)[0].lower() == "calf":
  1410. return "calf_black" if "mono" in pluginLabel else "calf_blue"
  1411. # OpenAV
  1412. if pluginMaker == "OpenAV Productions":
  1413. return "openav-old"
  1414. if pluginMaker == "OpenAV":
  1415. return "openav"
  1416. # ZynFX
  1417. if pluginInfo['type'] == PLUGIN_INTERNAL:
  1418. if pluginLabel.startswith("zyn") and pluginInfo['category'] != PLUGIN_CATEGORY_SYNTH:
  1419. return "zynfx"
  1420. if pluginInfo['type'] == PLUGIN_LADSPA:
  1421. if pluginLabel.startswith("zyn") and pluginMaker.startswith("Josep Andreu"):
  1422. return "zynfx"
  1423. if pluginInfo['type'] == PLUGIN_LV2:
  1424. if pluginLabel.startswith("http://kxstudio.sf.net/carla/plugins/zyn") and pluginName != "ZynAddSubFX":
  1425. return "zynfx"
  1426. # Presets
  1427. if progCount > 1 and (pluginInfo['hints'] & PLUGIN_USES_MULTI_PROGS) == 0:
  1428. if pluginInfo['type'] == PLUGIN_VST2:
  1429. return "presets"
  1430. return "mpresets"
  1431. # DISTRHO Plugins (needs to be last)
  1432. if pluginMaker.startswith("falkTX, ") or pluginMaker == "DISTRHO" or pluginLabel.startswith("http://distrho.sf.net/plugins/"):
  1433. return pluginLabel.replace("http://distrho.sf.net/plugins/","")
  1434. return "default"
  1435. def createPluginSlot(parent, host, pluginId, options):
  1436. if not options['useSkins']:
  1437. return PluginSlot_Classic(parent, host, pluginId)
  1438. skinStyle = getSkinStyle(host, pluginId)
  1439. if "compact" in skinStyle or options['compact']:
  1440. return PluginSlot_Compact(parent, host, pluginId, skinStyle)
  1441. if skinStyle.startswith("calf"):
  1442. return PluginSlot_Calf(parent, host, pluginId, skinStyle)
  1443. if skinStyle in ("mpresets", "presets", "zynfx"):
  1444. return PluginSlot_Presets(parent, host, pluginId, skinStyle)
  1445. return PluginSlot_Default(parent, host, pluginId, skinStyle)
  1446. # ------------------------------------------------------------------------------------------------------------
  1447. # Main Testing
  1448. if __name__ == '__main__':
  1449. from carla_app import CarlaApplication
  1450. from carla_host import initHost, loadHostSettings
  1451. import resources_rc
  1452. app = CarlaApplication("Carla-Skins")
  1453. host = initHost("Skins", None, False, False, False)
  1454. loadHostSettings(host)
  1455. host.engine_init("JACK", "Carla-Widgets")
  1456. host.add_plugin(BINARY_NATIVE, PLUGIN_INTERNAL, "", "", "zynreverb", 0, None, 0x0)
  1457. #host.add_plugin(BINARY_NATIVE, PLUGIN_DSSI, "/usr/lib/dssi/karplong.so", "karplong", "karplong", 0, None, 0x0)
  1458. #host.add_plugin(BINARY_NATIVE, PLUGIN_LV2, "", "", "http://www.openavproductions.com/sorcer", 0, None, 0x0)
  1459. #host.add_plugin(BINARY_NATIVE, PLUGIN_LV2, "", "", "http://calf.sourceforge.net/plugins/Compressor", 0, None, 0x0)
  1460. host.set_active(0, True)
  1461. #gui = createPluginSlot(None, host, 0, True)
  1462. gui = PluginSlot_Compact(None, host, 0, "default")
  1463. gui.testTimer()
  1464. gui.show()
  1465. app.exec_()