]> git.sesse.net Git - nageru/blob - vu_common.cpp
Move the R128 and correlation measurements into AudioMixer.
[nageru] / vu_common.cpp
1 #include "vu_common.h"
2
3 #include <math.h>
4 #include <algorithm>
5
6 #include <QBrush>
7 #include <QColor>
8 #include <QPainter>
9
10 using namespace std;
11
12 double lufs_to_pos(float level_lu, int height)
13 {       
14         const float min_level = 9.0f;    // y=0 is top of screen, so “min” is the loudest level.
15         const float max_level = -18.0f;
16
17         // Handle -inf.
18         if (level_lu < max_level) {
19                 return height - 1;
20         }
21
22         double y = height * (level_lu - min_level) / (max_level - min_level);
23         y = max<double>(y, 0);
24         y = min<double>(y, height - 1);
25
26         // If we are big enough, snap to pixel grid instead of antialiasing
27         // the edges; the unevenness will be less noticeable than the blurriness.
28         double height_per_level = height / (min_level - max_level) - 2.0;
29         if (height_per_level >= 10.0) {
30                 y = round(y);
31         }
32
33         return y;
34 }
35
36 void draw_vu_meter(QPainter &painter, int width, int height, int margin, bool is_on)
37 {
38         painter.fillRect(margin, 0, width - 2 * margin, height, Qt::black);
39
40         for (int y = 0; y < height; ++y) {
41                 // Find coverage of “on” rectangles in this pixel row.
42                 double coverage = 0.0;
43                 for (int level = -18; level < 9; ++level) {
44                         double min_y = lufs_to_pos(level + 1.0, height) + 1.0;
45                         double max_y = lufs_to_pos(level, height) - 1.0;
46                         min_y = std::max<double>(min_y, y);
47                         min_y = std::min<double>(min_y, y + 1);
48                         max_y = std::max<double>(max_y, y);
49                         max_y = std::min<double>(max_y, y + 1);
50                         coverage += max_y - min_y;
51                 }
52
53                 double on_r, on_g, on_b;
54                 if (is_on) {
55                         double t = double(y) / height;
56                         if (t <= 0.5) {
57                                 on_r = 1.0;
58                                 on_g = 2.0 * t;
59                                 on_b = 0.0;
60                         } else {
61                                 on_r = 1.0 - 2.0 * (t - 0.5);
62                                 on_g = 1.0;
63                                 on_b = 0.0;
64                         }
65                 } else {
66                         on_r = on_g = on_b = 0.05;
67                 }
68
69                 // Correct for coverage and do a simple gamma correction.
70                 int r = lrintf(255 * pow(on_r * coverage, 1.0 / 2.2));
71                 int g = lrintf(255 * pow(on_g * coverage, 1.0 / 2.2));
72                 int b = lrintf(255 * pow(on_b * coverage, 1.0 / 2.2));
73                 painter.fillRect(margin, y, width - 2 * margin, 1, QColor(r, g, b));
74         }
75 }