]> git.sesse.net Git - nageru/commitdiff
Make the VU meters less ugly at lower sizes, by antialiasing the edges.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 13 Aug 2016 23:17:30 +0000 (01:17 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 13 Aug 2016 23:17:30 +0000 (01:17 +0200)
lrameter.cpp
vu_common.cpp
vu_common.h
vumeter.cpp

index 9ca7b016000d4170ef887d11f8e79ff74f366895..f4395bec39ceb1094e4a472d67a110e4a05c4515 100644 (file)
@@ -46,8 +46,8 @@ void LRAMeter::paintEvent(QPaintEvent *event)
        float level_lu = level_lufs + 23.0f;
        float range_low_lu = range_low_lufs + 23.0f;
        float range_high_lu = range_high_lufs + 23.0f;
-       int range_low_pos = lufs_to_pos(range_low_lu, height());
-       int range_high_pos = lufs_to_pos(range_high_lu, height());
+       int range_low_pos = lrint(lufs_to_pos(range_low_lu, height()));
+       int range_high_pos = lrint(lufs_to_pos(range_high_lu, height()));
 
        QRect top_off_rect(0, 0, width(), range_high_pos);
        QRect on_rect(0, range_high_pos, width(), range_low_pos - range_high_pos);
@@ -59,8 +59,8 @@ void LRAMeter::paintEvent(QPaintEvent *event)
 
        // Draw the target area (+/-1 LU is allowed EBU range).
        // It turns green when we're within.
-       int min_y = lufs_to_pos(1.0f, height());
-       int max_y = lufs_to_pos(-1.0f, height());
+       int min_y = lrint(lufs_to_pos(1.0f, height()));
+       int max_y = lrint(lufs_to_pos(-1.0f, height()));
 
        // FIXME: This outlining isn't so pretty.
        {
@@ -82,7 +82,7 @@ void LRAMeter::paintEvent(QPaintEvent *event)
        }
 
        // Draw the integrated loudness meter, in the same color as the target area.
-       int y = lufs_to_pos(level_lu, height());
+       int y = lrint(lufs_to_pos(level_lu, height()));
        {
                QPen pen(Qt::black);
                pen.setWidth(5);
index 50249699e62b77e0ac60c51faf019806058f93e4..f1a0619b642045d63d20f5eeac610b69f6f1fb16 100644 (file)
@@ -9,7 +9,7 @@
 
 using namespace std;
 
-int lufs_to_pos(float level_lu, int height)
+double lufs_to_pos(float level_lu, int height)
 {       
        const float min_level = 9.0f;    // y=0 is top of screen, so “min” is the loudest level.
        const float max_level = -18.0f;
@@ -19,9 +19,17 @@ int lufs_to_pos(float level_lu, int height)
                return height - 1;
        }
 
-       int y = lrintf(height * (level_lu - min_level) / (max_level - min_level));
-       y = max(y, 0);
-       y = min(y, height - 1);
+       double y = height * (level_lu - min_level) / (max_level - min_level);
+       y = max<double>(y, 0);
+       y = min<double>(y, height - 1);
+
+       // If we are big enough, snap to pixel grid instead of antialiasing
+       // the edges; the unevenness will be less noticeable than the blurriness.
+       double height_per_level = height / (min_level - max_level) - 2.0;
+       if (height_per_level >= 10.0) {
+               y = round(y);
+       }
+
        return y;
 }
 
@@ -29,22 +37,39 @@ void draw_vu_meter(QPainter &painter, int width, int height, int margin, bool is
 {
        painter.fillRect(margin, 0, width - 2 * margin, height, Qt::black);
 
-       // TODO: QLinearGradient is not gamma-correct; we might want to correct for that.
-       QLinearGradient on(0, 0, 0, height);
-       on.setColorAt(0.0f, QColor(255, 0, 0));
-       on.setColorAt(0.5f, QColor(255, 255, 0));
-       on.setColorAt(1.0f, QColor(0, 255, 0));
-       QColor off(80, 80, 80);
-
-       // Draw bars colored up until the level, then gray from there.
-       for (int level = -18; level < 9; ++level) {
-               int min_y = lufs_to_pos(level + 1.0f, height) + 1;
-               int max_y = lufs_to_pos(level, height) - 1;
+       for (int y = 0; y < height; ++y) {
+               // Find coverage of “on” rectangles in this pixel row.
+               double coverage = 0.0;
+               for (int level = -18; level < 9; ++level) {
+                       double min_y = lufs_to_pos(level + 1.0, height) + 1.0;
+                       double max_y = lufs_to_pos(level, height) - 1.0;
+                       min_y = std::max<double>(min_y, y);
+                       min_y = std::min<double>(min_y, y + 1);
+                       max_y = std::max<double>(max_y, y);
+                       max_y = std::min<double>(max_y, y + 1);
+                       coverage += max_y - min_y;
+               }
 
+               double on_r, on_g, on_b;
                if (is_on) {
-                       painter.fillRect(margin, min_y, width - 2 * margin, max_y - min_y, on);
+                       double t = double(y) / height;
+                       if (t <= 0.5) {
+                               on_r = 1.0;
+                               on_g = 2.0 * t;
+                               on_b = 0.0;
+                       } else {
+                               on_r = 1.0 - 2.0 * (t - 0.5);
+                               on_g = 1.0;
+                               on_b = 0.0;
+                       }
                } else {
-                       painter.fillRect(margin, min_y, width - 2 * margin, max_y - min_y, off);
+                       on_r = on_g = on_b = 0.05;
                }
+
+               // Correct for coverage and do a simple gamma correction.
+               int r = lrintf(255 * pow(on_r * coverage, 1.0 / 2.2));
+               int g = lrintf(255 * pow(on_g * coverage, 1.0 / 2.2));
+               int b = lrintf(255 * pow(on_b * coverage, 1.0 / 2.2));
+               painter.fillRect(margin, y, width - 2 * margin, 1, QColor(r, g, b));
        }
 }
index 5df149ef94ea4cc3dfcdcfcf9f218fa72a0f4157..118eed89468ab3ae6b0fa77db6b404a7ebbb29ba 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <QPainter>
 
-int lufs_to_pos(float level_lu, int height);
+double lufs_to_pos(float level_lu, int height);
 
 void draw_vu_meter(QPainter &painter, int width, int height, int margin, bool is_on);
 
index 2e2d1c468c7e1fa434bb19e588d128ad999d3542..15240b4e5b9ac4ff552006d69b236e25b26ebcc6 100644 (file)
@@ -32,7 +32,7 @@ void VUMeter::paintEvent(QPaintEvent *event)
        }
 
        float level_lu = level_lufs + 23.0f;
-       int on_pos = lufs_to_pos(level_lu, height());
+       int on_pos = lrint(lufs_to_pos(level_lu, height()));
        QRect off_rect(0, 0, width(), on_pos);
        QRect on_rect(0, on_pos, width(), height() - on_pos);