]> git.sesse.net Git - nageru/blob - nageru/compression_reduction_meter.cpp
Fix a dangling reference (found by GCC 14).
[nageru] / nageru / compression_reduction_meter.cpp
1 #include "compression_reduction_meter.h"
2
3 #include <QFont>
4 #include <QPaintDevice>
5 #include <QPainter>
6 #include <QPixmap>
7 #include <QRect>
8 #include <QWidget>
9 #include <math.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <mutex>
13 #include <vector>
14 #include "piecewise_interpolator.h"
15 #include "vu_common.h"
16
17 class QPaintEvent;
18 class QResizeEvent;
19
20 using namespace std;
21
22 namespace {
23
24 vector<PiecewiseInterpolator::ControlPoint> control_points = {
25         { 60.0f, 6.0f },
26         { 30.0f, 5.0f },
27         { 18.0f, 4.0f },
28         { 12.0f, 3.0f },
29         { 6.0f, 2.0f },
30         { 3.0f, 1.0f },
31         { 0.0f, 0.0f }
32 };
33 PiecewiseInterpolator interpolator(control_points);
34
35 }  // namespace
36
37 CompressionReductionMeter::CompressionReductionMeter(QWidget *parent)
38         : QWidget(parent)
39 {
40 }
41
42 void CompressionReductionMeter::resizeEvent(QResizeEvent *event)
43 {
44         recalculate_pixmaps();
45 }
46
47 void CompressionReductionMeter::paintEvent(QPaintEvent *event)
48 {
49         QPainter painter(this);
50
51         float level_db;
52         {
53                 lock_guard<mutex> lock(level_mutex);
54                 level_db = this->level_db;
55         }
56
57         int on_pos = lrint(db_to_pos(level_db));
58
59         QRect on_rect(0, 0, width(), on_pos);
60         QRect off_rect(0, on_pos, width(), height());
61
62         painter.drawPixmap(on_rect, on_pixmap, on_rect);
63         painter.drawPixmap(off_rect, off_pixmap, off_rect);
64 }
65
66 void CompressionReductionMeter::recalculate_pixmaps()
67 {
68         constexpr int y_offset = text_box_height / 2;
69         constexpr int text_margin = 5;
70         float margin = 0.5 * (width() - meter_width);
71
72         on_pixmap = QPixmap(width(), height());
73         QPainter on_painter(&on_pixmap);
74         on_painter.fillRect(0, 0, width(), height(), parentWidget()->palette().window());
75         draw_vu_meter(on_painter, width(), meter_height(), margin, 2.0, true, min_level, max_level, /*flip=*/true, y_offset);
76         draw_scale(&on_painter, 0.5 * width() + 0.5 * meter_width + text_margin);
77
78         off_pixmap = QPixmap(width(), height());
79         QPainter off_painter(&off_pixmap);
80         off_painter.fillRect(0, 0, width(), height(), parentWidget()->palette().window());
81         draw_vu_meter(off_painter, width(), meter_height(), margin, 2.0, false, min_level, max_level, /*flip=*/true, y_offset);
82         draw_scale(&off_painter, 0.5 * width() + 0.5 * meter_width + text_margin);
83 }
84
85 void CompressionReductionMeter::draw_scale(QPainter *painter, int x_pos)
86 {
87         QFont font;
88         font.setPointSize(8);
89         painter->setPen(Qt::black);
90         painter->setFont(font);
91         for (size_t i = 0; i < control_points.size(); ++i) {
92                 char buf[256];
93                 snprintf(buf, 256, "%.0f", control_points[i].db_value);
94                 double y = db_to_pos(control_points[i].db_value);
95                 painter->drawText(QRect(x_pos, y - text_box_height / 2, text_box_width, text_box_height),
96                         Qt::AlignCenter | Qt::AlignVCenter, buf);
97         }
98 }
99
100 double CompressionReductionMeter::db_to_pos(double level_db) const
101 {
102         float value = interpolator.db_to_fraction(level_db);
103         return height() - lufs_to_pos(value, meter_height(), min_level, max_level) - text_box_height / 2;
104 }
105
106 int CompressionReductionMeter::meter_height() const
107 {
108         return height() - text_box_height;
109 }