1 #include "nonlinear_fader.h"
9 #include <QStyleOption>
21 vector<pair<double, double>> fader_control_points = {
22 // The main area is from +6 to -12 dB (18 dB), and we use half the slider range for it.
23 // Adjust slightly so that the MIDI controller value of 106 becomes exactly 0.0 dB
24 // (cf. map_controller_to_float()); otherwise, we'd miss ever so slightly, which is
25 // really frustrating.
27 { -12.0, 1.0 - (1.0 - 106.5/127.0) * 3.0 }, // About 0.492.
29 // -12 to -21 is half the range (9 dB). Halve.
32 // -21 to -30 (9 dB) gets the same range as the previous one.
35 // -30 to -48 (18 dB) gets half of half.
38 // -48 to -84 (36 dB) gets half of half of half.
42 double slider_fraction_to_db(double db)
44 if (db >= fader_control_points[0].second) {
45 return fader_control_points[0].first;
47 if (db <= fader_control_points.back().second) {
48 return fader_control_points.back().first;
50 for (unsigned i = 1; i < fader_control_points.size(); ++i) {
51 const double x0 = fader_control_points[i].second;
52 const double x1 = fader_control_points[i - 1].second;
53 const double y0 = fader_control_points[i].first;
54 const double y1 = fader_control_points[i - 1].first;
55 if (db >= x0 && db <= x1) {
56 const double t = (db - x0) / (x1 - x0);
57 return y0 + t * (y1 - y0);
63 double db_to_slider_fraction(double x)
65 if (x >= fader_control_points[0].first) {
66 return fader_control_points[0].second;
68 if (x <= fader_control_points.back().first) {
69 return fader_control_points.back().second;
71 for (unsigned i = 1; i < fader_control_points.size(); ++i) {
72 const double x0 = fader_control_points[i].first;
73 const double x1 = fader_control_points[i - 1].first;
74 const double y0 = fader_control_points[i].second;
75 const double y1 = fader_control_points[i - 1].second;
76 if (x >= x0 && x <= x1) {
77 const double t = (x - x0) / (x1 - x0);
78 return y0 + t * (y1 - y0);
86 NonLinearFader::NonLinearFader(QWidget *parent)
89 update_slider_position();
92 void NonLinearFader::setDbValue(double db)
95 update_slider_position();
96 emit dbValueChanged(db);
99 void NonLinearFader::paintEvent(QPaintEvent *event)
101 QStyleOptionSlider opt;
102 this->initStyleOption(&opt);
103 QRect gr = this->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this);
104 QRect sr = this->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
106 // FIXME: Where does the slider_length / 2 come from? I can't really find it
107 // in the Qt code, but it seems to match up with reality.
108 int slider_length = sr.height();
109 int slider_max = gr.top() + (slider_length / 2);
110 int slider_min = gr.bottom() + (slider_length / 2) - slider_length + 1;
114 // Draw some ticks every 6 dB.
115 // FIXME: Find a way to make the slider wider, so that we have more space for tickmarks
116 // and some dB numbering.
118 p.setPen(Qt::darkGray);
119 for (int db = -84; db <= 6; db += 6) {
120 int y = slider_min + lrint(db_to_slider_fraction(db) * (slider_max - slider_min));
121 p.drawLine(QPoint(0, y), QPoint(gr.left() - x_margin, y));
122 p.drawLine(QPoint(gr.right() + x_margin, y), QPoint(width() - 1, y));
125 QSlider::paintEvent(event);
128 void NonLinearFader::sliderChange(SliderChange change)
130 QSlider::sliderChange(change);
131 if (change == QAbstractSlider::SliderValueChange && !inhibit_updates) {
133 db_value = -HUGE_VAL;
135 double frac = double(value() - minimum()) / (maximum() - minimum());
136 db_value = slider_fraction_to_db(frac);
138 emit dbValueChanged(db_value);
142 void NonLinearFader::update_slider_position()
144 inhibit_updates = true;
145 double val = db_to_slider_fraction(db_value) * (maximum() - minimum()) + minimum();
146 setValue(lrint(val));
147 inhibit_updates = false;