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.

374 lines
10KB

  1. /*
  2. * Digital Peak Meter, a custom Qt widget
  3. * Copyright (C) 2011-2015 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef DIGITALPEAKMETER_HPP_INCLUDED
  18. #define DIGITALPEAKMETER_HPP_INCLUDED
  19. #include "CarlaJuceUtils.hpp"
  20. #include <QtGui/QPainter>
  21. #include <QtGui/QPaintEvent>
  22. #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  23. # include <QtWidgets/QWidget>
  24. #else
  25. # include <QtGui/QWidget>
  26. #endif
  27. // ------------------------------------------------------------------------------------------------------------
  28. class DigitalPeakMeter : public QWidget
  29. {
  30. public:
  31. enum Color {
  32. COLOR_GREEN = 1,
  33. COLOR_BLUE = 2
  34. };
  35. enum Orientation {
  36. HORIZONTAL = 1,
  37. VERTICAL = 2
  38. };
  39. enum Style {
  40. STYLE_DEFAULT = 1,
  41. STYLE_OPENAV = 2,
  42. STYLE_RNCBC = 3
  43. };
  44. // --------------------------------------------------------------------------------------------------------
  45. DigitalPeakMeter(QWidget* const p)
  46. : QWidget(p),
  47. fChannelCount(0),
  48. fChannelData(nullptr),
  49. fLastChannelData(nullptr),
  50. fMeterColor(COLOR_GREEN),
  51. fMeterColorBase(93, 231, 61),
  52. fMeterColorBaseAlt(15, 110, 15, 100),
  53. fMeterLinesEnabled(true),
  54. fMeterOrientation(VERTICAL),
  55. fMeterStyle(STYLE_DEFAULT),
  56. fMeterBackground("#111111"),
  57. fMeterGradient(0, 0, 0, 0),
  58. fSmoothMultiplier(1),
  59. leakDetector_DigitalPeakMeter()
  60. {
  61. updateGrandient();
  62. }
  63. ~DigitalPeakMeter() override
  64. {
  65. if (fChannelData != nullptr)
  66. {
  67. delete[] fChannelData;
  68. fChannelData = nullptr;
  69. }
  70. if (fLastChannelData != nullptr)
  71. {
  72. delete[] fLastChannelData;
  73. fLastChannelData = nullptr;
  74. }
  75. }
  76. // --------------------------------------------------------------------------------------------------------
  77. int channelCount() const noexcept
  78. {
  79. return fChannelCount;
  80. }
  81. void setChannelCount(const int count)
  82. {
  83. if (fChannelCount == count)
  84. return;
  85. if (count < 0)
  86. return qCritical("DigitalPeakMeter::setChannelCount(%i) - channel count must be a positive integer or zero", count);
  87. fChannelCount = count;
  88. fChannelData = new float[count];
  89. fLastChannelData = new float[count];
  90. for (int i=count; --i >= 0;)
  91. {
  92. /**/fChannelData[i] = 0.0f;
  93. fLastChannelData[i] = 0.0f;
  94. }
  95. }
  96. // --------------------------------------------------------------------------------------------------------
  97. Color meterColor() const noexcept
  98. {
  99. return fMeterColor;
  100. }
  101. void setMeterColor(const Color color)
  102. {
  103. if (fMeterColor == color)
  104. return;
  105. if (! QList<Color>({COLOR_GREEN, COLOR_BLUE}).contains(color))
  106. return qCritical("DigitalPeakMeter::setMeterColor(%i) - invalid color", color);
  107. switch (color)
  108. {
  109. case COLOR_GREEN:
  110. fMeterColorBase = QColor(93, 231, 61);
  111. fMeterColorBaseAlt = QColor(15, 110, 15, 100);
  112. break;
  113. case COLOR_BLUE:
  114. fMeterColorBase = QColor(82, 238, 248);
  115. fMeterColorBaseAlt = QColor(15, 15, 110, 100);
  116. break;
  117. }
  118. fMeterColor = color;
  119. updateGrandient();
  120. }
  121. // --------------------------------------------------------------------------------------------------------
  122. bool meterLinesEnabled() const noexcept
  123. {
  124. return fMeterLinesEnabled;
  125. }
  126. void setMeterLinesEnabled(const bool yesNo)
  127. {
  128. if (fMeterLinesEnabled == yesNo)
  129. return;
  130. fMeterLinesEnabled = yesNo;
  131. }
  132. // --------------------------------------------------------------------------------------------------------
  133. Orientation meterOrientation() const noexcept
  134. {
  135. return fMeterOrientation;
  136. }
  137. void setMeterOrientation(const Orientation orientation)
  138. {
  139. if (fMeterOrientation == orientation)
  140. return;
  141. if (! QList<Orientation>({HORIZONTAL, VERTICAL}).contains(orientation))
  142. return qCritical("DigitalPeakMeter::setMeterOrientation(%i) - invalid orientation", orientation);
  143. fMeterOrientation = orientation;
  144. updateGrandient();
  145. }
  146. // --------------------------------------------------------------------------------------------------------
  147. Style meterStyle() const noexcept
  148. {
  149. return fMeterStyle;
  150. }
  151. void setMeterStyle(const Style style)
  152. {
  153. if (fMeterStyle == style)
  154. return;
  155. if (! QList<Style>({STYLE_DEFAULT, STYLE_OPENAV, STYLE_RNCBC}).contains(style))
  156. return qCritical("DigitalPeakMeter::setMeterStyle(%i) - invalid style", style);
  157. switch (style)
  158. {
  159. case STYLE_DEFAULT:
  160. fMeterBackground = QColor("#111111");
  161. break;
  162. case STYLE_OPENAV:
  163. fMeterBackground = QColor("#1A1A1A");
  164. break;
  165. case STYLE_RNCBC:
  166. fMeterBackground = QColor("#111111");
  167. break;
  168. }
  169. fMeterStyle = style;
  170. updateGrandient();
  171. }
  172. // --------------------------------------------------------------------------------------------------------
  173. int smoothMultiplier() const noexcept
  174. {
  175. return fSmoothMultiplier;
  176. }
  177. void setSmoothMultiplier(const int value)
  178. {
  179. if (fSmoothMultiplier == value)
  180. return;
  181. if (value < 0)
  182. return qCritical("DigitalPeakMeter::setSmoothMultiplier(%i) - value must be >= 0", value);
  183. if (value > 5)
  184. return qCritical("DigitalPeakMeter::setSmoothMultiplier(%i) - value must be < 5", value);
  185. fSmoothMultiplier = value;
  186. }
  187. // --------------------------------------------------------------------------------------------------------
  188. void displayMeter(const int meter, float level, bool forced = false)
  189. {
  190. if (meter <= 0 or meter > fChannelCount)
  191. return qCritical("DigitalPeakMeter::displayMeter(%i, %f) - invalid meter number", meter, level);
  192. const int i = meter - 1;
  193. if (fSmoothMultiplier > 0 && ! forced)
  194. level = (fLastChannelData[i] * float(fSmoothMultiplier) + level) / float(fSmoothMultiplier + 1);
  195. if (level < 0.001f)
  196. level = 0.0f;
  197. else if (level > 0.999f)
  198. level = 1.0f;
  199. if (fChannelData[i] != level)
  200. {
  201. fChannelData[i] = level;
  202. update();
  203. }
  204. fLastChannelData[i] = level;
  205. }
  206. // --------------------------------------------------------------------------------------------------------
  207. protected:
  208. void updateGrandient()
  209. {
  210. fMeterGradient = QLinearGradient(0, 0, 1, 1);
  211. if (fMeterStyle == STYLE_OPENAV)
  212. {
  213. fMeterGradient.setColorAt(0.0, fMeterColorBase);
  214. fMeterGradient.setColorAt(1.0, fMeterColorBase);
  215. }
  216. else
  217. {
  218. switch (fMeterOrientation)
  219. {
  220. case HORIZONTAL:
  221. fMeterGradient.setColorAt(0.0, fMeterColorBase);
  222. fMeterGradient.setColorAt(0.2, fMeterColorBase);
  223. fMeterGradient.setColorAt(0.4, fMeterColorBase);
  224. fMeterGradient.setColorAt(0.6, fMeterColorBase);
  225. fMeterGradient.setColorAt(0.8, Qt::yellow);
  226. fMeterGradient.setColorAt(1.0, Qt::red);
  227. break;
  228. case VERTICAL:
  229. fMeterGradient.setColorAt(0.0, Qt::red);
  230. fMeterGradient.setColorAt(0.2, Qt::yellow);
  231. fMeterGradient.setColorAt(0.4, fMeterColorBase);
  232. fMeterGradient.setColorAt(0.6, fMeterColorBase);
  233. fMeterGradient.setColorAt(0.8, fMeterColorBase);
  234. fMeterGradient.setColorAt(1.0, fMeterColorBase);
  235. break;
  236. }
  237. }
  238. updateGrandientFinalStop();
  239. }
  240. void updateGrandientFinalStop()
  241. {
  242. switch (fMeterOrientation)
  243. {
  244. case HORIZONTAL:
  245. fMeterGradient.setFinalStop(width(), 0);
  246. break;
  247. case VERTICAL:
  248. fMeterGradient.setFinalStop(0, height());
  249. break;
  250. }
  251. }
  252. // --------------------------------------------------------------------------------------------------------
  253. QSize minimumSizeHint() const override
  254. {
  255. return QSize(10, 10);
  256. }
  257. QSize sizeHint() const override
  258. {
  259. return QSize(width(), height());
  260. }
  261. // --------------------------------------------------------------------------------------------------------
  262. void paintEvent(QPaintEvent* const ev) override
  263. {
  264. QPainter painter(this);
  265. ev->accept();
  266. const int width_ = width();
  267. const int height_ = height();
  268. // draw background
  269. painter.setPen(QPen(fMeterBackground, 2));
  270. painter.setBrush(fMeterBackground);
  271. painter.drawRect(0, 0, width_, height_);
  272. }
  273. // --------------------------------------------------------------------------------------------------------
  274. void resizeEvent(QResizeEvent* const ev) override
  275. {
  276. QWidget::resizeEvent(ev);
  277. updateGrandientFinalStop();
  278. }
  279. // --------------------------------------------------------------------------------------------------------
  280. private:
  281. int fChannelCount;
  282. float* fChannelData;
  283. float* fLastChannelData;
  284. Color fMeterColor;
  285. QColor fMeterColorBase;
  286. QColor fMeterColorBaseAlt;
  287. bool fMeterLinesEnabled;
  288. Orientation fMeterOrientation;
  289. Style fMeterStyle;
  290. QColor fMeterBackground;
  291. QLinearGradient fMeterGradient;
  292. int fSmoothMultiplier;
  293. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DigitalPeakMeter)
  294. };
  295. // ------------------------------------------------------------------------------------------------------------
  296. #endif // DIGITALPEAKMETER_HPP_INCLUDED