]> git.sesse.net Git - nageru/blob - lrameter.cpp
Fix meter display before we have any audio.
[nageru] / lrameter.cpp
1 #include <QPainter>
2
3 #include "lrameter.h"
4
5 using namespace std;
6
7 namespace {
8
9 int lufs_to_pos(float level_lu, int height)
10 {
11         const float min_level = 9.0f;    // y=0 is top of screen, so “min” is the loudest level.
12         const float max_level = -18.0f;
13
14         // Handle -inf.
15         if (level_lu < max_level) {
16                 return height - 1;
17         }
18
19         int y = lrintf(height * (level_lu - min_level) / (max_level - min_level));
20         y = std::max(y, 0);
21         y = std::min(y, height - 1);
22         return y;
23 }
24
25 }  // namespace
26
27 LRAMeter::LRAMeter(QWidget *parent)
28         : QWidget(parent)
29 {
30 }
31
32 void LRAMeter::paintEvent(QPaintEvent *event)
33 {
34         QPainter painter(this);
35         const int margin = 5;
36
37         painter.fillRect(0, 0, width(), height(), parentWidget()->palette().window());
38         painter.fillRect(margin, 0, width() - 2 * margin, height(), Qt::black);
39
40         // TODO: QLinearGradient is not gamma-correct; we might want to correct for that.
41         QLinearGradient on(0, 0, 0, height());
42         on.setColorAt(0.0f, QColor(255, 0, 0));
43         on.setColorAt(0.5f, QColor(255, 255, 0));
44         on.setColorAt(1.0f, QColor(0, 255, 0));
45         QColor off(80, 80, 80);
46
47         float level_lufs;
48         {
49                 unique_lock<mutex> lock(level_mutex);
50                 level_lufs = this->level_lufs;
51         }
52
53         float level_lu = level_lufs + 23.0f;
54         int y = lufs_to_pos(level_lu, height());
55
56         // Draw bars colored up until the level, then gray from there.
57         for (int level = -18; level < 9; ++level) {
58                 int min_y = lufs_to_pos(level + 1.0f, height()) + 1;
59                 int max_y = lufs_to_pos(level, height()) - 1;
60
61                 if (y > max_y) {
62                         painter.fillRect(margin, min_y, width() - 2 * margin, max_y - min_y, off);
63                 } else if (y < min_y) {
64                         painter.fillRect(margin, min_y, width() - 2 * margin, max_y - min_y, on);
65                 } else {
66                         painter.fillRect(margin, min_y, width() - 2 * margin, y - min_y, off);
67                         painter.fillRect(margin, y, width() - 2 * margin, max_y - y, on);
68                 }
69         }
70
71         // Draw the target area (+/-1 LU is allowed EBU range).
72         int min_y = lufs_to_pos(1.0f, height());
73         int max_y = lufs_to_pos(-1.0f, height());
74
75         // FIXME: This outlining isn't so pretty.
76         {
77                 QPen pen(Qt::black);
78                 pen.setWidth(5);
79                 painter.setPen(pen);
80                 painter.drawRect(2, min_y, width() - 5, max_y - min_y);
81         }
82         {
83                 QPen pen;
84                 if (level_lu >= -1.0f && level_lu <= 1.0f) {
85                         pen.setColor(Qt::green);
86                 } else {
87                         pen.setColor(Qt::red);
88                 }
89                 pen.setWidth(3);
90                 painter.setPen(pen);
91                 painter.drawRect(2, min_y, width() - 5, max_y - min_y);
92         }
93 }