From 9e93fbea58c068d14dd9dad5d0f5226edeef3395 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 22 Oct 2016 20:51:14 +0200 Subject: [PATCH] Split out the piecewise linear interpolation code into its own class. --- Makefile | 2 +- nonlinear_fader.cpp | 54 +++++--------------------------------- piecewise_interpolator.cpp | 46 ++++++++++++++++++++++++++++++++ piecewise_interpolator.h | 27 +++++++++++++++++++ 4 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 piecewise_interpolator.cpp create mode 100644 piecewise_interpolator.h diff --git a/Makefile b/Makefile index 7357294..6054259 100644 --- 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 diff --git a/nonlinear_fader.cpp b/nonlinear_fader.cpp index 4892c67..06a929c 100644 --- a/nonlinear_fader.cpp +++ b/nonlinear_fader.cpp @@ -11,6 +11,8 @@ #include #include +#include "piecewise_interpolator.h" + class QPaintEvent; class QWidget; @@ -18,7 +20,7 @@ using namespace std; namespace { -vector> 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> 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 index 0000000..3f07247 --- /dev/null +++ b/piecewise_interpolator.cpp @@ -0,0 +1,46 @@ +#include "piecewise_interpolator.h" + +#include + +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 index 0000000..17a9d8b --- /dev/null +++ b/piecewise_interpolator.h @@ -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 + +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 &control_points) + : control_points(control_points) {} + + double fraction_to_db(double db) const; + double db_to_fraction(double x) const; + +private: + const std::vector control_points; +}; + +#endif // !defined(_PIECEWISE_INTERPOLATOR_H) -- 2.39.2