]> git.sesse.net Git - nageru/commitdiff
Split out the piecewise linear interpolation code into its own class.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 22 Oct 2016 18:51:14 +0000 (20:51 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Tue, 25 Oct 2016 16:48:36 +0000 (18:48 +0200)
Makefile
nonlinear_fader.cpp
piecewise_interpolator.cpp [new file with mode: 0644]
piecewise_interpolator.h [new file with mode: 0644]

index 735729461afc9e61387051cf82d07cafad498f1b..6054259cfcbc855caf18cbdde3d5524fb8cbbea0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ endif
 LDLIBS=$(shell pkg-config --libs $(PKG_MODULES)) -pthread -lva -lva-drm -lva-x11 -lX11 -lavformat -lavcodec -lavutil -lswscale -lavresample -lzita-resampler -lasound -ldl
 
 # Qt objects
-OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o correlation_meter.o aboutdialog.o input_mapping_dialog.o midi_mapping_dialog.o nonlinear_fader.o
+OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o correlation_meter.o aboutdialog.o input_mapping_dialog.o midi_mapping_dialog.o nonlinear_fader.o piecewise_interpolator.o
 OBJS += glwidget.moc.o mainwindow.moc.o vumeter.moc.o lrameter.moc.o correlation_meter.moc.o aboutdialog.moc.o ellipsis_label.moc.o input_mapping_dialog.moc.o midi_mapping_dialog.moc.o nonlinear_fader.moc.o clickable_label.moc.o
 OBJS += midi_mapper.o midi_mapping.pb.o
 
index 4892c6770517b5a8d465fcf9949a808e8332da47..06a929c39259c037a0d6bf27c9a0a36c0ea8efcd 100644 (file)
@@ -11,6 +11,8 @@
 #include <utility>
 #include <vector>
 
+#include "piecewise_interpolator.h"
+
 class QPaintEvent;
 class QWidget;
 
@@ -18,7 +20,7 @@ using namespace std;
 
 namespace {
 
-vector<pair<double, double>> fader_control_points = {
+PiecewiseInterpolator interpolator({
        // The main area is from +6 to -12 dB (18 dB), and we use half the slider range for it.
        // Adjust slightly so that the MIDI controller value of 106 becomes exactly 0.0 dB
        // (cf. map_controller_to_float()); otherwise, we'd miss ever so slightly, which is
@@ -37,49 +39,7 @@ vector<pair<double, double>> fader_control_points = {
 
        // -48 to -84 (36 dB) gets half of half of half.
        { -84.0, 0.0 },
-};
-
-double slider_fraction_to_db(double db)
-{
-       if (db >= fader_control_points[0].second) {
-               return fader_control_points[0].first;
-       }
-       if (db <= fader_control_points.back().second) {
-               return fader_control_points.back().first;
-       }
-       for (unsigned i = 1; i < fader_control_points.size(); ++i) {
-               const double x0 = fader_control_points[i].second;
-               const double x1 = fader_control_points[i - 1].second;
-               const double y0 = fader_control_points[i].first;
-               const double y1 = fader_control_points[i - 1].first;
-               if (db >= x0 && db <= x1) {
-                       const double t = (db - x0) / (x1 - x0);
-                       return y0 + t * (y1 - y0);
-               }
-       }
-       assert(false);
-}
-
-double db_to_slider_fraction(double x)
-{
-       if (x >= fader_control_points[0].first) {
-               return fader_control_points[0].second;
-       }
-       if (x <= fader_control_points.back().first) {
-               return fader_control_points.back().second;
-       }
-       for (unsigned i = 1; i < fader_control_points.size(); ++i) {
-               const double x0 = fader_control_points[i].first;
-               const double x1 = fader_control_points[i - 1].first;
-               const double y0 = fader_control_points[i].second;
-               const double y1 = fader_control_points[i - 1].second;
-               if (x >= x0 && x <= x1) {
-                       const double t = (x - x0) / (x1 - x0);
-                       return y0 + t * (y1 - y0);
-               }
-       }
-       assert(false);
-}
+});
 
 }  // namespace
 
@@ -117,7 +77,7 @@ void NonLinearFader::paintEvent(QPaintEvent *event)
        int x_margin = 5;
        p.setPen(Qt::darkGray);
        for (int db = -84; db <= 6; db += 6) {
-               int y = slider_min + lrint(db_to_slider_fraction(db) * (slider_max - slider_min));
+               int y = slider_min + lrint(interpolator.db_to_fraction(db) * (slider_max - slider_min));
                p.drawLine(QPoint(0, y), QPoint(gr.left() - x_margin, y));
                p.drawLine(QPoint(gr.right() + x_margin, y), QPoint(width() - 1, y));
        }
@@ -133,7 +93,7 @@ void NonLinearFader::sliderChange(SliderChange change)
                        db_value = -HUGE_VAL;
                } else {
                        double frac = double(value() - minimum()) / (maximum() - minimum());
-                       db_value = slider_fraction_to_db(frac);
+                       db_value = interpolator.fraction_to_db(frac);
                }
                emit dbValueChanged(db_value);
        }
@@ -142,7 +102,7 @@ void NonLinearFader::sliderChange(SliderChange change)
 void NonLinearFader::update_slider_position()
 {
        inhibit_updates = true;
-       double val = db_to_slider_fraction(db_value) * (maximum() - minimum()) + minimum();
+       double val = interpolator.db_to_fraction(db_value) * (maximum() - minimum()) + minimum();
        setValue(lrint(val));
        inhibit_updates = false;
 }
diff --git a/piecewise_interpolator.cpp b/piecewise_interpolator.cpp
new file mode 100644 (file)
index 0000000..3f07247
--- /dev/null
@@ -0,0 +1,46 @@
+#include "piecewise_interpolator.h"
+
+#include <assert.h>
+
+double PiecewiseInterpolator::fraction_to_db(double db) const
+{
+       if (db >= control_points[0].fraction) {
+               return control_points[0].db_value;
+       }
+       if (db <= control_points.back().fraction) {
+               return control_points.back().db_value;
+       }
+       for (unsigned i = 1; i < control_points.size(); ++i) {
+               const double x0 = control_points[i].fraction;
+               const double x1 = control_points[i - 1].fraction;
+               const double y0 = control_points[i].db_value;
+               const double y1 = control_points[i - 1].db_value;
+               if (db >= x0 && db <= x1) {
+                       const double t = (db - x0) / (x1 - x0);
+                       return y0 + t * (y1 - y0);
+               }
+       }
+       assert(false);
+}
+
+double PiecewiseInterpolator::db_to_fraction(double x) const
+{
+       if (x >= control_points[0].db_value) {
+               return control_points[0].fraction;
+       }
+       if (x <= control_points.back().db_value) {
+               return control_points.back().fraction;
+       }
+       for (unsigned i = 1; i < control_points.size(); ++i) {
+               const double x0 = control_points[i].db_value;
+               const double x1 = control_points[i - 1].db_value;
+               const double y0 = control_points[i].fraction;
+               const double y1 = control_points[i - 1].fraction;
+               if (x >= x0 && x <= x1) {
+                       const double t = (x - x0) / (x1 - x0);
+                       return y0 + t * (y1 - y0);
+               }
+       }
+       assert(false);
+}
+
diff --git a/piecewise_interpolator.h b/piecewise_interpolator.h
new file mode 100644 (file)
index 0000000..17a9d8b
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _PIECEWISE_INTERPOLATOR_H
+#define _PIECEWISE_INTERPOLATOR_H
+
+// A class to do piecewise linear interpolation of one scale to another
+// (and back). Typically used to implement nonlinear dB mappings for sliders
+// or meters, thus the nomenclature.
+
+#include <vector>
+
+class PiecewiseInterpolator {
+public:
+       // Both dB and fraction values must go from high to low.
+       struct ControlPoint {
+               double db_value;
+               double fraction;
+       };
+       PiecewiseInterpolator(const std::vector<ControlPoint> &control_points)
+               : control_points(control_points) {}
+
+       double fraction_to_db(double db) const;
+       double db_to_fraction(double x) const;
+
+private:
+       const std::vector<ControlPoint> control_points;
+};
+
+#endif  // !defined(_PIECEWISE_INTERPOLATOR_H)