From 22bb590d54107446f09d0cb60f32e610cc9ed7ad Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 18 Aug 2016 23:35:42 +0200 Subject: [PATCH] Make a non-linear fader for dB use. Not perfect yet, but will do. --- Makefile | 4 +- mainwindow.cpp | 14 ++-- mainwindow.h | 2 +- nonlinear_fader.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++ nonlinear_fader.h | 28 ++++++++ ui_audio_miniview.ui | 9 ++- 6 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 nonlinear_fader.cpp create mode 100644 nonlinear_fader.h diff --git a/Makefile b/Makefile index 1aae6cd..5cf71d7 100644 --- a/Makefile +++ b/Makefile @@ -13,8 +13,8 @@ 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 -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 +OBJS=glwidget.o main.o mainwindow.o vumeter.o lrameter.o vu_common.o correlation_meter.o aboutdialog.o input_mapping_dialog.o nonlinear_fader.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 nonlinear_fader.moc.o # Mixer objects OBJS += mixer.o audio_mixer.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o resampling_queue.o httpd.o ebu_r128_proc.o flags.o image_input.o stereocompressor.o filter.o alsa_input.o alsa_output.o correlation_measurer.o disk_space_estimator.o diff --git a/mainwindow.cpp b/mainwindow.cpp index c1a3836..3f9873f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -255,7 +255,7 @@ void MainWindow::setup_audio_miniview() // TODO: Set the fader position. ui->faders->addWidget(channel); - connect(ui_audio_miniview->fader, &QAbstractSlider::valueChanged, + connect(ui_audio_miniview->fader, &NonLinearFader::dbValueChanged, bind(&MainWindow::mini_fader_changed, this, ui_audio_miniview, bus_index, _1)); } } @@ -381,13 +381,15 @@ void MainWindow::compressor_threshold_knob_changed(int value) QString::fromStdString(format_db(threshold_dbfs, DB_WITH_SIGN))); } -void MainWindow::mini_fader_changed(Ui::AudioMiniView *ui, int channel, int value) +void MainWindow::mini_fader_changed(Ui::AudioMiniView *ui, int channel, double volume_db) { - float volume_db = value * 0.1f; - char buf[256]; - snprintf(buf, sizeof(buf), "%+.1f dB", volume_db); - ui->fader_label->setText(buf); + if (isfinite(volume_db)) { + snprintf(buf, sizeof(buf), "%+.1f dB", volume_db); + ui->fader_label->setText(buf); + } else { + ui->fader_label->setText("-∞ dB"); + } global_mixer->get_audio_mixer()->set_fader_volume(channel, volume_db); } diff --git a/mainwindow.h b/mainwindow.h index b93470a..cfde53e 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -51,7 +51,7 @@ public slots: void cutoff_knob_changed(int value); void limiter_threshold_knob_changed(int value); void compressor_threshold_knob_changed(int value); - void mini_fader_changed(Ui::AudioMiniView *ui, int channel, int value); + void mini_fader_changed(Ui::AudioMiniView *ui, int channel, double db_volume); void reset_meters_button_clicked(); void relayout(); diff --git a/nonlinear_fader.cpp b/nonlinear_fader.cpp new file mode 100644 index 0000000..7c26434 --- /dev/null +++ b/nonlinear_fader.cpp @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nonlinear_fader.h" + +using namespace std; + +namespace { + +vector> fader_control_points = { + // The main area is from +6 to -12 dB (18 dB), and we use half the slider range for it. + { 6.0, 0.0 }, + { -12.0, 0.5 }, + + // -12 to -21 is half the range (9 dB). Halve. + { -21.0, 0.625 }, + + // -21 to -30 (9 dB) gets the same range as the previous one. + { -30.0, 0.75 }, + + // -30 to -48 (18 dB) gets half of half. + { -48.0, 0.875 }, + + // -48 to -84 (36 dB) gets half of half of half. + { -84.0, 1.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 - 1].second; + const double x1 = fader_control_points[i].second; + const double y0 = fader_control_points[i - 1].first; + const double y1 = fader_control_points[i].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 + +NonLinearFader::NonLinearFader(QWidget *parent) + : QSlider(parent) +{ + update_slider_position(); +} + +void NonLinearFader::setDbValue(double db) +{ + db_value = db; + update_slider_position(); + emit dbValueChanged(db); +} + +void NonLinearFader::paintEvent(QPaintEvent *event) +{ + QStyleOptionSlider opt; + this->initStyleOption(&opt); + QRect gr = this->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); + QRect sr = this->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + + // FIXME: Where does the slider_length / 2 come from? I can't really find it + // in the Qt code, but it seems to match up with reality. + int slider_length = sr.height(); + int slider_min = gr.top() + (slider_length / 2); + int slider_max = gr.bottom() + (slider_length / 2) - slider_length + 1; + + QPainter p(this); + + // Draw some ticks every 6 dB. + // FIXME: Find a way to make the slider wider, so that we have more space for tickmarks + // and some dB numbering. + 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)); + p.drawLine(QPoint(0, y), QPoint(gr.left() - x_margin, y)); + p.drawLine(QPoint(gr.right() + x_margin, y), QPoint(width() - 1, y)); + } + + QSlider::paintEvent(event); +} + +void NonLinearFader::resizeEvent(QResizeEvent *event) +{ + QSlider::resizeEvent(event); + inhibit_updates = true; + setRange(0, event->size().height() - 1); + inhibit_updates = false; + update_slider_position(); +} + +void NonLinearFader::sliderChange(SliderChange change) +{ + QSlider::sliderChange(change); + if (change == QAbstractSlider::SliderValueChange && !inhibit_updates) { + if (value() == 0) { + db_value = -HUGE_VAL; + } else { + double frac = 1.0 - value() / (height() - 1.0); + db_value = slider_fraction_to_db(frac); + } + emit dbValueChanged(db_value); + } +} + +void NonLinearFader::update_slider_position() +{ + inhibit_updates = true; + setValue(lrint((1.0 - db_to_slider_fraction(db_value)) * (height() - 1.0))); + inhibit_updates = false; +} diff --git a/nonlinear_fader.h b/nonlinear_fader.h new file mode 100644 index 0000000..4126fbd --- /dev/null +++ b/nonlinear_fader.h @@ -0,0 +1,28 @@ +#ifndef _NONLINEAR_FADER_H +#define _NONLINEAR_FADER_H 1 + +#include + +class NonLinearFader : public QSlider { + Q_OBJECT + +public: + NonLinearFader(QWidget *parent); + void setDbValue(double db); + +signals: + void dbValueChanged(double db); + +protected: + void paintEvent(QPaintEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void sliderChange(SliderChange change) override; + +private: + void update_slider_position(); + + bool inhibit_updates = false; + double db_value = 0.0; +}; + +#endif // !defined(_NONLINEAR_FADER_H) diff --git a/ui_audio_miniview.ui b/ui_audio_miniview.ui index d7149c9..a261e88 100644 --- a/ui_audio_miniview.ui +++ b/ui_audio_miniview.ui @@ -259,7 +259,7 @@ 0 - + -390 @@ -273,7 +273,7 @@ Qt::Vertical - QSlider::TicksBothSides + QSlider::NoTicks 30 @@ -339,6 +339,11 @@ QLabel
ellipsis_label.h
+ + NonLinearFader + QSlider +
nonlinear_fader.h
+
-- 2.39.2