diff --git a/data/themes/classic/fader_background.png b/data/themes/classic/fader_background.png deleted file mode 100644 index 682ff4c9281..00000000000 Binary files a/data/themes/classic/fader_background.png and /dev/null differ diff --git a/data/themes/classic/fader_leds.png b/data/themes/classic/fader_leds.png deleted file mode 100644 index 6c673cf36d1..00000000000 Binary files a/data/themes/classic/fader_leds.png and /dev/null differ diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index 08a04f01df7..dfaee134dbc 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -653,9 +653,9 @@ lmms--gui--MixerChannelView QGraphicsView { /* persistent peak markers for fx peak meters */ lmms--gui--Fader { - qproperty-peakGreen: rgb( 74, 253, 133); - qproperty-peakYellow: rgb(224, 222, 18); - qproperty-peakRed: rgb( 255, 100, 100); + qproperty-peakOk: rgb( 74, 253, 133); + qproperty-peakWarn: rgb(224, 222, 18); + qproperty-peakClip: rgb( 255, 100, 100); } lmms--gui--TimeLineWidget { diff --git a/data/themes/default/fader_background.png b/data/themes/default/fader_background.png deleted file mode 100644 index 7d6b59e35fe..00000000000 Binary files a/data/themes/default/fader_background.png and /dev/null differ diff --git a/data/themes/default/fader_leds.png b/data/themes/default/fader_leds.png deleted file mode 100644 index 707902e04c6..00000000000 Binary files a/data/themes/default/fader_leds.png and /dev/null differ diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 89c14f20a2a..f13ec09d816 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -694,9 +694,9 @@ lmms--gui--MixerChannelView QGraphicsView { /* persistent peak markers for fx peak meters */ lmms--gui--Fader { - qproperty-peakGreen: #0ad45c; - qproperty-peakYellow: #d6ec52; - qproperty-peakRed: #c12038; + qproperty-peakOk: #0ad45c; + qproperty-peakWarn: #d6ec52; + qproperty-peakClip: #c12038; } lmms--gui--TimeLineWidget { diff --git a/include/Fader.h b/include/Fader.h index 20132f71db2..a3158a8b436 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -54,6 +54,7 @@ #include "AutomatableModelView.h" #include "embed.h" +#include "lmms_math.h" namespace lmms::gui @@ -66,21 +67,21 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView { Q_OBJECT public: - Q_PROPERTY( QColor peakGreen READ peakGreen WRITE setPeakGreen ) - Q_PROPERTY( QColor peakRed READ peakRed WRITE setPeakRed ) - Q_PROPERTY( QColor peakYellow READ peakYellow WRITE setPeakYellow ) - Q_PROPERTY( bool levelsDisplayedInDBFS READ getLevelsDisplayedInDBFS WRITE setLevelsDisplayedInDBFS ) - - Fader( FloatModel * _model, const QString & _name, QWidget * _parent ); - Fader( FloatModel * _model, const QString & _name, QWidget * _parent, QPixmap * back, QPixmap * leds, QPixmap * knob ); + Q_PROPERTY(QColor peakOk MEMBER m_peakOk) + Q_PROPERTY(QColor peakClip MEMBER m_peakClip) + Q_PROPERTY(QColor peakWarn MEMBER m_peakWarn) + Q_PROPERTY(bool levelsDisplayedInDBFS MEMBER m_levelsDisplayedInDBFS) + Q_PROPERTY(bool renderUnityLine READ getRenderUnityLine WRITE setRenderUnityLine) + Q_PROPERTY(QColor unityMarker MEMBER m_unityMarker) + + Fader(FloatModel* model, const QString& name, QWidget* parent); + Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob); ~Fader() override = default; - void init(FloatModel * model, QString const & name); - - void setPeak_L( float fPeak ); + void setPeak_L(float fPeak); float getPeak_L() { return m_fPeakValue_L; } - void setPeak_R( float fPeak ); + void setPeak_R(float fPeak); float getPeak_R() { return m_fPeakValue_R; } inline float getMinPeak() const { return m_fMinPeak; } @@ -89,43 +90,31 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView inline float getMaxPeak() const { return m_fMaxPeak; } inline void setMaxPeak(float maxPeak) { m_fMaxPeak = maxPeak; } - QColor const & peakGreen() const; - void setPeakGreen( const QColor & c ); - - QColor const & peakRed() const; - void setPeakRed( const QColor & c ); - - QColor const & peakYellow() const; - void setPeakYellow( const QColor & c ); + inline bool getRenderUnityLine() const { return m_renderUnityLine; } + inline void setRenderUnityLine(bool value = true) { m_renderUnityLine = value; } - inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; } - inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; } - - void setDisplayConversion( bool b ) + void setDisplayConversion(bool b) { m_conversionFactor = b ? 100.0 : 1.0; } - inline void setHintText( const QString & _txt_before, - const QString & _txt_after ) + inline void setHintText(const QString& txt_before, + const QString& txt_after) { - setDescription( _txt_before ); - setUnit( _txt_after ); + setDescription(txt_before); + setUnit(txt_after); } private: - void contextMenuEvent( QContextMenuEvent * _me ) override; - void mousePressEvent( QMouseEvent *ev ) override; - void mouseDoubleClickEvent( QMouseEvent* mouseEvent ) override; - void mouseMoveEvent( QMouseEvent *ev ) override; - void mouseReleaseEvent( QMouseEvent * _me ) override; - void wheelEvent( QWheelEvent *ev ) override; - void paintEvent( QPaintEvent *ev ) override; - - inline bool clips(float const & value) const { return value >= 1.0f; } + void contextMenuEvent(QContextMenuEvent* me) override; + void mousePressEvent(QMouseEvent* ev) override; + void mouseDoubleClickEvent(QMouseEvent* mouseEvent) override; + void mouseMoveEvent(QMouseEvent* ev) override; + void mouseReleaseEvent(QMouseEvent* me) override; + void wheelEvent(QWheelEvent* ev) override; + void paintEvent(QPaintEvent* ev) override; - void paintDBFSLevels(QPaintEvent *ev, QPainter & painter); - void paintLinearLevels(QPaintEvent *ev, QPainter & painter); + void paintLevels(QPaintEvent* ev, QPainter& painter, bool linear = false); int knobPosY() const { @@ -135,37 +124,37 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView return height() - ((height() - m_knob.height()) * (realVal / fRange)); } - void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer ); - int calculateDisplayPeak( float fPeak ); + void setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElapsedTimer& lastPeakTimer); void updateTextFloat(); // Private members private: - float m_fPeakValue_L; - float m_fPeakValue_R; - float m_persistentPeak_L; - float m_persistentPeak_R; - float m_fMinPeak; - float m_fMaxPeak; + float m_fPeakValue_L {0.}; + float m_fPeakValue_R {0.}; + float m_persistentPeak_L {0.}; + float m_persistentPeak_R {0.}; + float m_fMinPeak {dbfsToAmp(-42)}; + float m_fMaxPeak {dbfsToAmp(9)}; QElapsedTimer m_lastPeakTimer_L; QElapsedTimer m_lastPeakTimer_R; - QPixmap m_back; - QPixmap m_leds; - QPixmap m_knob; + QPixmap m_knob {embed::getIconPixmap("fader_knob")}; + + bool m_levelsDisplayedInDBFS {true}; - bool m_levelsDisplayedInDBFS; + int m_moveStartPoint {-1}; + float m_startValue {0.}; - int m_moveStartPoint; - float m_startValue; + static SimpleTextFloat* s_textFloat; - static SimpleTextFloat * s_textFloat; + QColor m_peakOk {10, 212, 92}; + QColor m_peakClip {193, 32, 56}; + QColor m_peakWarn {214, 236, 82}; + QColor m_unityMarker {63, 63, 63, 255}; - QColor m_peakGreen; - QColor m_peakRed; - QColor m_peakYellow; + bool m_renderUnityLine {true}; } ; diff --git a/include/lmms_math.h b/include/lmms_math.h index f6455d6931f..3f58e3b75d4 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -32,6 +32,7 @@ #include "lmms_constants.h" #include "lmmsconfig.h" +#include namespace lmms { @@ -269,18 +270,18 @@ static inline float safeDbfsToAmp( float dbfs ) //! @brief Converts linear amplitude (>0-1.0) to dBFS scale. //! @param amp Linear amplitude, where 1.0 = 0dBFS. ** Must be larger than zero! ** //! @return Amplitude in dBFS. -static inline float ampToDbfs( float amp ) +static inline float ampToDbfs(float amp) { - return log10f( amp ) * 20.0f; + return log10f(amp) * 20.0f; } //! @brief Converts dBFS-scale to linear amplitude with 0dBFS = 1.0 //! @param dbfs The dBFS value to convert. ** Must be a real number - not inf/nan! ** //! @return Linear amplitude -static inline float dbfsToAmp( float dbfs ) +static inline float dbfsToAmp(float dbfs) { - return std::pow(10.f, dbfs * 0.05f ); + return std::pow(10.f, dbfs * 0.05f); } @@ -352,6 +353,28 @@ static inline int numDigitsAsInt(float f) return digits; } +template +class LinearMap +{ +public: + LinearMap(T x1, T y1, T x2, T y2) + { + T const dx = x2 - x1; + assert (dx != T(0)); + + m_a = (y2 - y1) / dx; + m_b = y1 - m_a * x1; + } + + T map(T x) const + { + return m_a * x + m_b; + } + +private: + T m_a; + T m_b; +}; } // namespace lmms diff --git a/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp index 12b560b2370..a4f44f5d305 100644 --- a/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp +++ b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp @@ -32,6 +32,9 @@ #include "Knob.h" #include "Fader.h" +#include + + namespace lmms::gui { @@ -64,30 +67,32 @@ CrossoverEQControlDialog::CrossoverEQControlDialog( CrossoverEQControls * contro xover34->setLabel( "3/4" ); xover34->setHintText( tr( "Band 3/4 crossover:" ), " Hz" ); - m_fader_bg = QPixmap( PLUGIN_NAME::getIconPixmap( "fader_bg" ) ); - m_fader_empty = QPixmap( PLUGIN_NAME::getIconPixmap( "fader_empty" ) ); - m_fader_knob = QPixmap( PLUGIN_NAME::getIconPixmap( "fader_knob2" ) ); + QPixmap const fader_knob(PLUGIN_NAME::getIconPixmap("fader_knob2")); // faders - auto gain1 = new Fader(&controls->m_gain1, tr("Band 1 gain"), this, &m_fader_bg, &m_fader_empty, &m_fader_knob); + auto gain1 = new Fader(&controls->m_gain1, tr("Band 1 gain"), this, fader_knob); gain1->move( 7, 56 ); gain1->setDisplayConversion( false ); gain1->setHintText( tr( "Band 1 gain:" ), " dBFS" ); + gain1->setRenderUnityLine(false); - auto gain2 = new Fader(&controls->m_gain2, tr("Band 2 gain"), this, &m_fader_bg, &m_fader_empty, &m_fader_knob); + auto gain2 = new Fader(&controls->m_gain2, tr("Band 2 gain"), this, fader_knob); gain2->move( 47, 56 ); gain2->setDisplayConversion( false ); gain2->setHintText( tr( "Band 2 gain:" ), " dBFS" ); + gain2->setRenderUnityLine(false); - auto gain3 = new Fader(&controls->m_gain3, tr("Band 3 gain"), this, &m_fader_bg, &m_fader_empty, &m_fader_knob); + auto gain3 = new Fader(&controls->m_gain3, tr("Band 3 gain"), this, fader_knob); gain3->move( 87, 56 ); gain3->setDisplayConversion( false ); gain3->setHintText( tr( "Band 3 gain:" ), " dBFS" ); + gain3->setRenderUnityLine(false); - auto gain4 = new Fader(&controls->m_gain4, tr("Band 4 gain"), this, &m_fader_bg, &m_fader_empty, &m_fader_knob); + auto gain4 = new Fader(&controls->m_gain4, tr("Band 4 gain"), this, fader_knob); gain4->move( 127, 56 ); gain4->setDisplayConversion( false ); gain4->setHintText( tr( "Band 4 gain:" ), " dBFS" ); + gain4->setRenderUnityLine(false); // leds auto mute1 = new LedCheckBox("", this, tr("Band 1 mute"), LedCheckBox::LedColor::Green); diff --git a/plugins/CrossoverEQ/CrossoverEQControlDialog.h b/plugins/CrossoverEQ/CrossoverEQControlDialog.h index 9ddb5d9bfb2..0f25600f9f0 100644 --- a/plugins/CrossoverEQ/CrossoverEQControlDialog.h +++ b/plugins/CrossoverEQ/CrossoverEQControlDialog.h @@ -27,7 +27,6 @@ #ifndef CROSSOVEREQ_CONTROL_DIALOG_H #define CROSSOVEREQ_CONTROL_DIALOG_H -#include #include "EffectControlDialog.h" namespace lmms @@ -46,11 +45,6 @@ class CrossoverEQControlDialog : public EffectControlDialog public: CrossoverEQControlDialog( CrossoverEQControls * controls ); ~CrossoverEQControlDialog() override = default; - -private: - QPixmap m_fader_bg; - QPixmap m_fader_empty; - QPixmap m_fader_knob; }; diff --git a/plugins/CrossoverEQ/fader_bg.png b/plugins/CrossoverEQ/fader_bg.png deleted file mode 100644 index ca4eedafdc9..00000000000 Binary files a/plugins/CrossoverEQ/fader_bg.png and /dev/null differ diff --git a/plugins/CrossoverEQ/fader_empty.png b/plugins/CrossoverEQ/fader_empty.png deleted file mode 100644 index 797a0d3bc2d..00000000000 Binary files a/plugins/CrossoverEQ/fader_empty.png and /dev/null differ diff --git a/plugins/Eq/EqControls.h b/plugins/Eq/EqControls.h index 6db82f3e33f..80680c7fb5a 100644 --- a/plugins/Eq/EqControls.h +++ b/plugins/Eq/EqControls.h @@ -66,6 +66,8 @@ class EqControls : public EffectControls float m_inPeakR; float m_outPeakL; float m_outPeakR; + + // The following are linear peaks float m_lowShelfPeakL, m_lowShelfPeakR; float m_para1PeakL, m_para1PeakR; float m_para2PeakL, m_para2PeakR; diff --git a/plugins/Eq/EqControlsDialog.cpp b/plugins/Eq/EqControlsDialog.cpp index 634bde846bc..17de9ce98a9 100644 --- a/plugins/Eq/EqControlsDialog.cpp +++ b/plugins/Eq/EqControlsDialog.cpp @@ -72,18 +72,16 @@ EqControlsDialog::EqControlsDialog( EqControls *controls ) : setBand( 6, &controls->m_highShelfActiveModel, &controls->m_highShelfFreqModel, &controls->m_highShelfResModel, &controls->m_highShelfGainModel, QColor(255 ,255, 255), tr( "High-shelf" ), &controls->m_highShelfPeakL, &controls->m_highShelfPeakR,0,0,0,0,0,0 ); setBand( 7, &controls->m_lpActiveModel, &controls->m_lpFreqModel, &controls->m_lpResModel, 0, QColor(255 ,255, 255), tr( "LP" ) ,0,0,0,0,0, &controls->m_lp12Model, &controls->m_lp24Model, &controls->m_lp48Model); - static auto s_faderBg = PLUGIN_NAME::getIconPixmap("faderback"); - static auto s_faderLeds = PLUGIN_NAME::getIconPixmap("faderleds"); - static auto s_faderKnob = PLUGIN_NAME::getIconPixmap("faderknob"); + QSize const faderSize(23, 80); - auto GainFaderIn = new EqFader(&controls->m_inGainModel, tr("Input gain"), this, &s_faderBg, &s_faderLeds, &s_faderKnob, - &controls->m_inPeakL, &controls->m_inPeakR); + auto GainFaderIn = new EqFader(&controls->m_inGainModel, tr("Input gain"), this, &controls->m_inPeakL, &controls->m_inPeakR); + GainFaderIn->setFixedSize(faderSize); GainFaderIn->move( 23, 295 ); GainFaderIn->setDisplayConversion( false ); GainFaderIn->setHintText( tr( "Gain" ), "dBv"); - auto GainFaderOut = new EqFader(&controls->m_outGainModel, tr("Output gain"), this, &s_faderBg, &s_faderLeds, &s_faderKnob, - &controls->m_outPeakL, &controls->m_outPeakR); + auto GainFaderOut = new EqFader(&controls->m_outGainModel, tr("Output gain"), this, &controls->m_outPeakL, &controls->m_outPeakR); + GainFaderOut->setFixedSize(faderSize); GainFaderOut->move( 453, 295); GainFaderOut->setDisplayConversion( false ); GainFaderOut->setHintText( tr( "Gain" ), "dBv" ); @@ -92,8 +90,9 @@ EqControlsDialog::EqControlsDialog( EqControls *controls ) : int distance = 126; for( int i = 1; i < m_parameterWidget->bandCount() - 1; i++ ) { - auto gainFader = new EqFader(m_parameterWidget->getBandModels(i)->gain, tr(""), this, &s_faderBg, &s_faderLeds, - &s_faderKnob, m_parameterWidget->getBandModels(i)->peakL, m_parameterWidget->getBandModels(i)->peakR); + auto gainFader = new EqFader(m_parameterWidget->getBandModels(i)->gain, tr(""), this, + m_parameterWidget->getBandModels(i)->peakL, m_parameterWidget->getBandModels(i)->peakR); + gainFader->setFixedSize(faderSize); gainFader->move( distance, 295 ); distance += 44; gainFader->setMinimumHeight(80); diff --git a/plugins/Eq/EqEffect.cpp b/plugins/Eq/EqEffect.cpp index 31be4d0f5b6..d8d2b2b29e2 100644 --- a/plugins/Eq/EqEffect.cpp +++ b/plugins/Eq/EqEffect.cpp @@ -287,24 +287,23 @@ bool EqEffect::processAudioBuffer( sampleFrame *buf, const fpp_t frames ) -float EqEffect::peakBand( float minF, float maxF, EqAnalyser *fft, int sr ) +float EqEffect::linearPeakBand(float minF, float maxF, EqAnalyser* fft, int sr) { auto const fftEnergy = fft->getEnergy(); if (fftEnergy == 0.) { return 0.; } - float peak = -60; - float *b = fft->m_bands; - float h = 0; - for( int x = 0; x < MAX_BANDS; x++, b++ ) + + float peakLinear = 0.; + + for (int i = 0; i < MAX_BANDS; ++i) { - if( bandToFreq( x ,sr) >= minF && bandToFreq( x,sr ) <= maxF ) + if (bandToFreq(i, sr) >= minF && bandToFreq(i, sr) <= maxF) { - h = 20. * log10(*b / fftEnergy); - peak = h > peak ? h : peak; + peakLinear = std::max(peakLinear, fft->m_bands[i] / fftEnergy); } } - return ( peak + 60 ) / 100; + return peakLinear; } @@ -312,45 +311,34 @@ float EqEffect::peakBand( float minF, float maxF, EqAnalyser *fft, int sr ) void EqEffect::setBandPeaks( EqAnalyser *fft, int samplerate ) { + auto computePeakBand = [&](const FloatModel& freqModel, const FloatModel& bwModel) + { + float const freq = freqModel.value(); + float const bw = bwModel.value(); + + return linearPeakBand(freq * (1 - bw * 0.5), freq * (1 + bw * 0.5), fft, samplerate); + }; + m_eqControls.m_lowShelfPeakR = m_eqControls.m_lowShelfPeakL = - peakBand( m_eqControls.m_lowShelfFreqModel.value() - * ( 1 - m_eqControls.m_lowShelfResModel.value() * 0.5 ), - m_eqControls.m_lowShelfFreqModel.value(), - fft , samplerate ); + linearPeakBand(m_eqControls.m_lowShelfFreqModel.value() * (1 - m_eqControls.m_lowShelfResModel.value() * 0.5), + m_eqControls.m_lowShelfFreqModel.value(), fft , samplerate); m_eqControls.m_para1PeakL = m_eqControls.m_para1PeakR = - peakBand( m_eqControls.m_para1FreqModel.value() - * ( 1 - m_eqControls.m_para1BwModel.value() * 0.5 ), - m_eqControls.m_para1FreqModel.value() - * ( 1 + m_eqControls.m_para1BwModel.value() * 0.5 ), - fft , samplerate ); + computePeakBand(m_eqControls.m_para1FreqModel, m_eqControls.m_para1BwModel); m_eqControls.m_para2PeakL = m_eqControls.m_para2PeakR = - peakBand( m_eqControls.m_para2FreqModel.value() - * ( 1 - m_eqControls.m_para2BwModel.value() * 0.5 ), - m_eqControls.m_para2FreqModel.value() - * ( 1 + m_eqControls.m_para2BwModel.value() * 0.5 ), - fft , samplerate ); + computePeakBand(m_eqControls.m_para2FreqModel, m_eqControls.m_para2BwModel); m_eqControls.m_para3PeakL = m_eqControls.m_para3PeakR = - peakBand( m_eqControls.m_para3FreqModel.value() - * ( 1 - m_eqControls.m_para3BwModel.value() * 0.5 ), - m_eqControls.m_para3FreqModel.value() - * ( 1 + m_eqControls.m_para3BwModel.value() * 0.5 ), - fft , samplerate ); + computePeakBand(m_eqControls.m_para3FreqModel, m_eqControls.m_para3BwModel); m_eqControls.m_para4PeakL = m_eqControls.m_para4PeakR = - peakBand( m_eqControls.m_para4FreqModel.value() - * ( 1 - m_eqControls.m_para4BwModel.value() * 0.5 ), - m_eqControls.m_para4FreqModel.value() - * ( 1 + m_eqControls.m_para4BwModel.value() * 0.5 ), - fft , samplerate ); + computePeakBand(m_eqControls.m_para4FreqModel, m_eqControls.m_para4BwModel); m_eqControls.m_highShelfPeakL = m_eqControls.m_highShelfPeakR = - peakBand( m_eqControls.m_highShelfFreqModel.value(), - m_eqControls.m_highShelfFreqModel.value() - * ( 1 + m_eqControls.m_highShelfResModel.value() * 0.5 ), - fft, samplerate ); + linearPeakBand(m_eqControls.m_highShelfFreqModel.value(), + m_eqControls.m_highShelfFreqModel.value() * (1 + m_eqControls.m_highShelfResModel.value() * 0.5), + fft, samplerate); } extern "C" diff --git a/plugins/Eq/EqEffect.h b/plugins/Eq/EqEffect.h index 9b23b51b57e..7e91ee40142 100644 --- a/plugins/Eq/EqEffect.h +++ b/plugins/Eq/EqEffect.h @@ -87,7 +87,7 @@ class EqEffect : public Effect float m_inGain; float m_outGain; - float peakBand( float minF, float maxF, EqAnalyser *, int ); + float linearPeakBand(float minF, float maxF, EqAnalyser*, int); inline float bandToFreq ( int index , int sampleRate ) { diff --git a/plugins/Eq/EqFader.h b/plugins/Eq/EqFader.h index 9db0fbe2d82..d8897af5c90 100644 --- a/plugins/Eq/EqFader.h +++ b/plugins/Eq/EqFader.h @@ -42,20 +42,6 @@ class EqFader : public Fader public: Q_OBJECT public: - EqFader( FloatModel * model, const QString & name, QWidget * parent, QPixmap * backg, QPixmap * leds, QPixmap * knobpi, float* lPeak, float* rPeak ) : - Fader( model, name, parent, backg, leds, knobpi ) - { - setMinimumSize( 23, 80 ); - setMaximumSize( 23, 80 ); - resize( 23, 80 ); - m_lPeak = lPeak; - m_rPeak = rPeak; - connect( getGUI()->mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( updateVuMeters() ) ); - m_model = model; - setPeak_L( 0 ); - setPeak_R( 0 ); - } - EqFader( FloatModel * model, const QString & name, QWidget * parent, float* lPeak, float* rPeak ) : Fader( model, name, parent ) { diff --git a/plugins/Eq/faderback.png b/plugins/Eq/faderback.png deleted file mode 100644 index 2a03c3a5c1e..00000000000 Binary files a/plugins/Eq/faderback.png and /dev/null differ diff --git a/plugins/Eq/faderknob.png b/plugins/Eq/faderknob.png deleted file mode 100755 index 866cd863492..00000000000 Binary files a/plugins/Eq/faderknob.png and /dev/null differ diff --git a/plugins/Eq/faderleds.png b/plugins/Eq/faderleds.png deleted file mode 100644 index b99fac9fd5a..00000000000 Binary files a/plugins/Eq/faderleds.png and /dev/null differ diff --git a/src/gui/MixerChannelView.cpp b/src/gui/MixerChannelView.cpp index 9b43991d3b6..6577ace51cc 100644 --- a/src/gui/MixerChannelView.cpp +++ b/src/gui/MixerChannelView.cpp @@ -122,9 +122,6 @@ namespace lmms::gui soloMuteLayout->addWidget(m_muteButton, 0, Qt::AlignHCenter); m_fader = new Fader{&mixerChannel->m_volumeModel, tr("Fader %1").arg(channelIndex), this}; - m_fader->setLevelsDisplayedInDBFS(); - m_fader->setMinPeak(dbfsToAmp(-42)); - m_fader->setMaxPeak(dbfsToAmp(9)); m_effectRackView = new EffectRackView{&mixerChannel->m_fxChain, mixerView->m_racksWidget}; m_effectRackView->setFixedWidth(EffectRackView::DEFAULT_WIDTH); diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 840fe299133..370cc750291 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include "lmms_math.h" #include "embed.h" @@ -59,100 +60,60 @@ namespace lmms::gui { -SimpleTextFloat * Fader::s_textFloat = nullptr; - -Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : - QWidget( _parent ), - FloatModelView( _model, this ), - m_fPeakValue_L( 0.0 ), - m_fPeakValue_R( 0.0 ), - m_persistentPeak_L( 0.0 ), - m_persistentPeak_R( 0.0 ), - m_fMinPeak( 0.01f ), - m_fMaxPeak( 1.1 ), - m_back(embed::getIconPixmap("fader_background")), - m_leds(embed::getIconPixmap("fader_leds")), - m_knob(embed::getIconPixmap("fader_knob")), - m_levelsDisplayedInDBFS(false), - m_moveStartPoint( -1 ), - m_startValue( 0 ), - m_peakGreen( 0, 0, 0 ), - m_peakRed( 0, 0, 0 ), - m_peakYellow( 0, 0, 0 ) +SimpleTextFloat* Fader::s_textFloat = nullptr; + +Fader::Fader(FloatModel* model, const QString& name, QWidget* parent) : + QWidget(parent), + FloatModelView(model, this) { - if( s_textFloat == nullptr ) + if (s_textFloat == nullptr) { s_textFloat = new SimpleTextFloat; } - init(_model, _name); + setWindowTitle(name); + setAttribute(Qt::WA_OpaquePaintEvent, false); + // For now resize the widget to the size of the previous background image "fader_background.png" as it was found in the classic and default theme + constexpr QSize minimumSize(23, 116); + setMinimumSize(minimumSize); + resize(minimumSize); + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + setModel(model); + setHintText("Volume:", "%"); m_conversionFactor = 100.0; } -Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixmap * back, QPixmap * leds, QPixmap * knob ) : - QWidget( parent ), - FloatModelView( model, this ), - m_fPeakValue_L( 0.0 ), - m_fPeakValue_R( 0.0 ), - m_persistentPeak_L( 0.0 ), - m_persistentPeak_R( 0.0 ), - m_fMinPeak( 0.01f ), - m_fMaxPeak( 1.1 ), - m_back(*back), - m_leds(*leds), - m_knob(*knob), - m_levelsDisplayedInDBFS(false), - m_moveStartPoint( -1 ), - m_startValue( 0 ), - m_peakGreen( 0, 0, 0 ), - m_peakRed( 0, 0, 0 ) +Fader::Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob) : + Fader(model, name, parent) { - if( s_textFloat == nullptr ) - { - s_textFloat = new SimpleTextFloat; - } - - init(model, name); + m_knob = knob; } -void Fader::init(FloatModel * model, QString const & name) -{ - setWindowTitle( name ); - setAttribute( Qt::WA_OpaquePaintEvent, false ); - QSize backgroundSize = m_back.size(); - setMinimumSize( backgroundSize ); - setMaximumSize( backgroundSize ); - resize( backgroundSize ); - setModel( model ); - setHintText( "Volume:","%"); -} - - -void Fader::contextMenuEvent( QContextMenuEvent * _ev ) +void Fader::contextMenuEvent(QContextMenuEvent* ev) { - CaptionMenu contextMenu( windowTitle() ); - addDefaultActions( &contextMenu ); - contextMenu.exec( QCursor::pos() ); - _ev->accept(); + CaptionMenu contextMenu(windowTitle()); + addDefaultActions(&contextMenu); + contextMenu.exec(QCursor::pos()); + ev->accept(); } -void Fader::mouseMoveEvent( QMouseEvent *mouseEvent ) +void Fader::mouseMoveEvent(QMouseEvent* mouseEvent) { - if( m_moveStartPoint >= 0 ) + if (m_moveStartPoint >= 0) { int dy = m_moveStartPoint - mouseEvent->globalY(); float delta = dy * (model()->maxValue() - model()->minValue()) / (float)(height() - (m_knob).height()); const auto step = model()->step(); - float newValue = static_cast( static_cast( ( m_startValue + delta ) / step + 0.5 ) ) * step; - model()->setValue( newValue ); + float newValue = static_cast(static_cast((m_startValue + delta) / step + 0.5)) * step; + model()->setValue(newValue); updateTextFloat(); } @@ -161,16 +122,16 @@ void Fader::mouseMoveEvent( QMouseEvent *mouseEvent ) -void Fader::mousePressEvent( QMouseEvent* mouseEvent ) +void Fader::mousePressEvent(QMouseEvent* mouseEvent) { - if( mouseEvent->button() == Qt::LeftButton && - ! ( mouseEvent->modifiers() & Qt::ControlModifier ) ) + if (mouseEvent->button() == Qt::LeftButton && + !(mouseEvent->modifiers() & Qt::ControlModifier)) { - AutomatableModel *thisModel = model(); - if( thisModel ) + AutomatableModel* thisModel = model(); + if (thisModel) { thisModel->addJournalCheckPoint(); - thisModel->saveJournallingState( false ); + thisModel->saveJournallingState(false); } if (mouseEvent->y() >= knobPosY() - (m_knob).height() && mouseEvent->y() < knobPosY()) @@ -190,37 +151,36 @@ void Fader::mousePressEvent( QMouseEvent* mouseEvent ) } else { - AutomatableModelView::mousePressEvent( mouseEvent ); + AutomatableModelView::mousePressEvent(mouseEvent); } } -void Fader::mouseDoubleClickEvent( QMouseEvent* mouseEvent ) +void Fader::mouseDoubleClickEvent(QMouseEvent* mouseEvent) { bool ok; - // TODO: dbV handling + // TODO: dbFS handling auto minv = model()->minValue() * m_conversionFactor; auto maxv = model()->maxValue() * m_conversionFactor; - float newValue = QInputDialog::getDouble(this, tr("Set value"), + float enteredValue = QInputDialog::getDouble(this, tr("Set value"), tr("Please enter a new value between %1 and %2:").arg(minv).arg(maxv), - model()->getRoundedValue() * m_conversionFactor, minv, maxv, model()->getDigitCount(), &ok) - / m_conversionFactor; + model()->getRoundedValue() * m_conversionFactor, minv, maxv, model()->getDigitCount(), &ok); - if( ok ) + if (ok) { - model()->setValue( newValue ); + model()->setValue(enteredValue / m_conversionFactor); } } -void Fader::mouseReleaseEvent( QMouseEvent * mouseEvent ) +void Fader::mouseReleaseEvent(QMouseEvent* mouseEvent) { - if( mouseEvent && mouseEvent->button() == Qt::LeftButton ) + if (mouseEvent && mouseEvent->button() == Qt::LeftButton) { - AutomatableModel *thisModel = model(); - if( thisModel ) + AutomatableModel* thisModel = model(); + if (thisModel) { thisModel->restoreJournallingState(); } @@ -230,20 +190,20 @@ void Fader::mouseReleaseEvent( QMouseEvent * mouseEvent ) } -void Fader::wheelEvent ( QWheelEvent *ev ) +void Fader::wheelEvent (QWheelEvent* ev) { ev->accept(); if (ev->angleDelta().y() > 0) { - model()->incValue( 1 ); + model()->incValue(1); } else { - model()->incValue( -1 ); + model()->incValue(-1); } updateTextFloat(); - s_textFloat->setVisibilityTimeOut( 1000 ); + s_textFloat->setVisibilityTimeOut(1000); } @@ -251,21 +211,14 @@ void Fader::wheelEvent ( QWheelEvent *ev ) /// /// Set peak value (0.0 .. 1.0) /// -void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer ) +void Fader::setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElapsedTimer& lastPeakTimer) { - if( fPeak < m_fMinPeak ) - { - fPeak = m_fMinPeak; - } - else if( fPeak > m_fMaxPeak ) - { - fPeak = m_fMaxPeak; - } + fPeak = std::clamp(fPeak, m_fMinPeak, m_fMaxPeak); - if( targetPeak != fPeak) + if (targetPeak != fPeak) { targetPeak = fPeak; - if( targetPeak >= persistentPeak ) + if (targetPeak >= persistentPeak) { persistentPeak = targetPeak; lastPeakTimer.restart(); @@ -273,25 +226,25 @@ void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QEla update(); } - if( persistentPeak > 0 && lastPeakTimer.elapsed() > 1500 ) + if (persistentPeak > 0 && lastPeakTimer.elapsed() > 1500) { - persistentPeak = qMax( 0, persistentPeak-0.05 ); + persistentPeak = qMax(0, persistentPeak-0.05); update(); } } -void Fader::setPeak_L( float fPeak ) +void Fader::setPeak_L(float fPeak) { - setPeak( fPeak, m_fPeakValue_L, m_persistentPeak_L, m_lastPeakTimer_L ); + setPeak(fPeak, m_fPeakValue_L, m_persistentPeak_L, m_lastPeakTimer_L); } -void Fader::setPeak_R( float fPeak ) +void Fader::setPeak_R(float fPeak) { - setPeak( fPeak, m_fPeakValue_R, m_persistentPeak_R, m_lastPeakTimer_R ); + setPeak(fPeak, m_fPeakValue_R, m_persistentPeak_R, m_lastPeakTimer_R); } @@ -299,169 +252,185 @@ void Fader::setPeak_R( float fPeak ) // update tooltip showing value and adjust position while changing fader value void Fader::updateTextFloat() { - if( ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() && m_conversionFactor == 100.0 ) + if (ConfigManager::inst()->value("app", "displaydbfs").toInt() && m_conversionFactor == 100.0) { - s_textFloat->setText( QString("Volume: %1 dBFS"). - arg( ampToDbfs( model()->value() ), 3, 'f', 2 ) ); + s_textFloat->setText(QString("Volume: %1 dBFS"). + arg(ampToDbfs(model()->value()), 3, 'f', 2)); } else { - s_textFloat->setText( m_description + " " + QString("%1 ").arg( model()->value() * m_conversionFactor ) + " " + m_unit ); + s_textFloat->setText(m_description + " " + QString("%1 ").arg(model()->value() * m_conversionFactor) + " " + m_unit); } s_textFloat->moveGlobal(this, QPoint(width() + 2, knobPosY() - s_textFloat->height() / 2)); } -inline int Fader::calculateDisplayPeak( float fPeak ) +void Fader::paintEvent(QPaintEvent* ev) { - int peak = static_cast(m_back.height() - (fPeak / (m_fMaxPeak - m_fMinPeak)) * m_back.height()); + QPainter painter(this); - return qMin(peak, m_back.height()); -} + // Draw the levels with peaks + paintLevels(ev, painter, !m_levelsDisplayedInDBFS); + // Draw the knob + painter.drawPixmap((width() - m_knob.width()) / 2, knobPosY() - m_knob.height(), m_knob); +} -void Fader::paintEvent( QPaintEvent * ev) +void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) { - QPainter painter(this); - - // Draw the background - painter.drawPixmap(ev->rect(), m_back, ev->rect()); + std::function mapper = [this](float value) { return ampToDbfs(qMax(0.0001, value)); }; - // Draw the levels with peaks - if (getLevelsDisplayedInDBFS()) + if (linear) { - paintDBFSLevels(ev, painter); - } - else - { - paintLinearLevels(ev, painter); + mapper = [this](float value) { return value; }; } - // Draw the knob - painter.drawPixmap(0, knobPosY() - m_knob.height(), m_knob); -} + const float mappedMinPeak(mapper(m_fMinPeak)); + const float mappedMaxPeak(mapper(m_fMaxPeak)); + const float mappedPeakL(mapper(m_fPeakValue_L)); + const float mappedPeakR(mapper(m_fPeakValue_R)); + const float mappedPersistentPeakL(mapper(m_persistentPeak_L)); + const float mappedPersistentPeakR(mapper(m_persistentPeak_R)); + const float mappedUnity(mapper(1.f)); -void Fader::paintDBFSLevels(QPaintEvent * ev, QPainter & painter) -{ - int height = m_back.height(); - int width = m_back.width() / 2; - int center = m_back.width() - width; + painter.save(); - float const maxDB(ampToDbfs(m_fMaxPeak)); - float const minDB(ampToDbfs(m_fMinPeak)); + const QRect baseRect = rect(); - // We will need to divide by the span between min and max several times. It's more - // efficient to calculate the reciprocal once and then to multiply. - float const fullSpanReciprocal = 1 / (maxDB - minDB); + const int height = baseRect.height(); + const int margin = 1; + const int distanceBetweenMeters = 2; - // Draw left levels - float const leftSpan = ampToDbfs(qMax(0.0001, m_fPeakValue_L)) - minDB; - int peak_L = height * leftSpan * fullSpanReciprocal; - QRect drawRectL( 0, height - peak_L, width, peak_L ); // Source and target are identical - painter.drawPixmap(drawRectL, m_leds, drawRectL); - - float const persistentLeftPeakDBFS = ampToDbfs(qMax(0.0001, m_persistentPeak_L)); - int persistentPeak_L = height * (1 - (persistentLeftPeakDBFS - minDB) * fullSpanReciprocal); - // the LED's have a 4px padding and we don't want the peaks - // to draw on the fader background - if( persistentPeak_L <= 4 ) - { - persistentPeak_L = 4; - } - if( persistentLeftPeakDBFS > minDB ) - { - QColor const & peakColor = clips(m_persistentPeak_L) ? peakRed() : - persistentLeftPeakDBFS >= -6 ? peakYellow() : peakGreen(); - painter.fillRect( QRect( 2, persistentPeak_L, 7, 1 ), peakColor ); - } + const int numberOfMeters = 2; + // Compute the width of a single meter by removing the margins and the space between meters + const int leftAndRightMargin = 2 * margin; + const int pixelsBetweenAllMeters = distanceBetweenMeters * (numberOfMeters - 1); + const int remainingPixelsForMeters = baseRect.width() - leftAndRightMargin - pixelsBetweenAllMeters; + const int meterWidth = remainingPixelsForMeters / numberOfMeters; - // Draw right levels - float const rightSpan = ampToDbfs(qMax(0.0001, m_fPeakValue_R)) - minDB; - int peak_R = height * rightSpan * fullSpanReciprocal; - QRect const drawRectR( center, height - peak_R, width, peak_R ); // Source and target are identical - painter.drawPixmap(drawRectR, m_leds, drawRectR); - - float const persistentRightPeakDBFS = ampToDbfs(qMax(0.0001, m_persistentPeak_R)); - int persistentPeak_R = height * (1 - (persistentRightPeakDBFS - minDB) * fullSpanReciprocal); - // the LED's have a 4px padding and we don't want the peaks - // to draw on the fader background - if( persistentPeak_R <= 4 ) - { - persistentPeak_R = 4; - } - if( persistentRightPeakDBFS > minDB ) - { - QColor const & peakColor = clips(m_persistentPeak_R) ? peakRed() : - persistentRightPeakDBFS >= -6 ? peakYellow() : peakGreen(); - painter.fillRect( QRect( 14, persistentPeak_R, 7, 1 ), peakColor ); - } -} + QRect leftMeterOutlineRect(margin, margin, meterWidth, height - 2 * margin); + QRect rightMeterOutlineRect(baseRect.width() - margin - meterWidth, margin, meterWidth, height - 2 * margin); -void Fader::paintLinearLevels(QPaintEvent * ev, QPainter & painter) -{ - // peak leds - //float fRange = abs( m_fMaxPeak ) + abs( m_fMinPeak ); + QMargins removedMargins(1, 1, 1, 1); + QRect leftMeterRect = leftMeterOutlineRect.marginsRemoved(removedMargins); + QRect rightMeterRect = rightMeterOutlineRect.marginsRemoved(removedMargins); + + QPainterPath path; + qreal radius = 2; + path.addRoundedRect(leftMeterOutlineRect, radius, radius); + path.addRoundedRect(rightMeterOutlineRect, radius, radius); + painter.fillPath(path, Qt::black); - int height = m_back.height(); - int width = m_back.width() / 2; - int center = m_back.width() - width; + // Now clip everything to the paths of the meters + painter.setClipPath(path); - int peak_L = calculateDisplayPeak( m_fPeakValue_L - m_fMinPeak ); - int persistentPeak_L = qMax( 3, calculateDisplayPeak( m_persistentPeak_L - m_fMinPeak ) ); - painter.drawPixmap(QRect(0, peak_L, width, height - peak_L), m_leds, QRect(0, peak_L, width, height - peak_L)); + // This linear map performs the following mapping: + // Value (dbFS or linear) -> window coordinates of the widget + // It is for example used to determine the height of peaks, markers and to define the gradient for the levels + const LinearMap valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); - if( m_persistentPeak_L > 0.05 ) + // This lambda takes a value (in dbFS or linear) and a rectangle and computes a rectangle + // that represent the value within the rectangle. It is for example used to compute the unity indicators. + const auto computeLevelMarkerRect = [&valuesToWindowCoordinates](const QRect& rect, float peak) -> QRect { - painter.fillRect( QRect( 2, persistentPeak_L, 7, 1 ), ( m_persistentPeak_L < 1.0 ) - ? peakGreen() - : peakRed() ); - } + return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); + }; - int peak_R = calculateDisplayPeak( m_fPeakValue_R - m_fMinPeak ); - int persistentPeak_R = qMax( 3, calculateDisplayPeak( m_persistentPeak_R - m_fMinPeak ) ); - painter.drawPixmap(QRect(center, peak_R, width, height - peak_R), m_leds, QRect(center, peak_R, width, height - peak_R)); + // This lambda takes a peak value (in dbFS or linear) and a rectangle and computes a rectangle + // that represent the peak value within the rectangle. It's used to compute the peak indicators + // which "dance" on top of the level meters. + const auto computePeakRect = [&valuesToWindowCoordinates](const QRect& rect, float peak) -> QRect + { + return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); + }; - if( m_persistentPeak_R > 0.05 ) + // This lambda takes a peak value (in dbFS or linear) and a rectangle and returns an adjusted copy of the + // rectangle that represents the peak value. It is used to compute the level meters themselves. + const auto computeLevelRect = [&valuesToWindowCoordinates](const QRect& rect, float peak) -> QRect { - painter.fillRect( QRect( 14, persistentPeak_R, 7, 1 ), ( m_persistentPeak_R < 1.0 ) - ? peakGreen() - : peakRed() ); - } -} + QRect result(rect); + result.setTop(valuesToWindowCoordinates.map(peak)); + return result; + }; -QColor const & Fader::peakGreen() const -{ - return m_peakGreen; -} + // Draw left and right level markers for the unity lines (0 dbFS, 1.0 amplitude) + if (getRenderUnityLine()) + { + const auto unityRectL = computeLevelMarkerRect(leftMeterRect, mappedUnity); + painter.fillRect(unityRectL, m_unityMarker); -QColor const & Fader::peakRed() const -{ - return m_peakRed; -} + const auto unityRectR = computeLevelMarkerRect(rightMeterRect, mappedUnity); + painter.fillRect(unityRectR, m_unityMarker); + } -QColor const & Fader::peakYellow() const -{ - return m_peakYellow; -} + // These values define where the gradient changes values, i.e. the ranges + // for clipping, warning and ok. + // Please ensure that "clip starts" is the maximum value and that "ok ends" + // is the minimum value and that all other values lie inbetween. Otherwise + // there will be warnings when the gradient is defined. + const float mappedClipStarts(mapper(dbfsToAmp(0.f))); + const float mappedWarnEnd(mapper(dbfsToAmp(-0.01))); + const float mappedWarnStart(mapper(dbfsToAmp(-6.f))); + const float mappedOkEnd(mapper(dbfsToAmp(-12.f))); + + // Prepare the gradient for the meters + // + // The idea is the following. We want to be able to render arbitrary ranges of min and max values. + // Therefore we first compute the start and end point of the gradient in window coordinates. + // The gradient is assumed to start with the clip color and to end with the ok color with warning values in between. + // We know the min and max peaks that map to a rectangle where we draw the levels. We can use the values of the min and max peaks + // as well as the Y-coordinates of the rectangle to compute a map which will give us the coordinates of the value where the clipping + // starts and where the ok area end. These coordinates are used to initialize the gradient. Please note that the gradient might thus + // extend the rectangle into which we paint. + float clipStartYCoord = valuesToWindowCoordinates.map(mappedClipStarts); + float okEndYCoord = valuesToWindowCoordinates.map(mappedOkEnd); + + QLinearGradient linearGrad(0, clipStartYCoord, 0, okEndYCoord); + + // We already know for the gradient that the clip color will be at 0 and that the ok color is at 1. + // What's left to do is to map the inbetween values into the interval [0,1]. + const LinearMap mapBetweenClipAndOk(mappedClipStarts, 0.f, mappedOkEnd, 1.f); + + linearGrad.setColorAt(0, m_peakClip); + linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnEnd), m_peakWarn); + linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnStart), m_peakWarn); + linearGrad.setColorAt(1, m_peakOk); -void Fader::setPeakGreen( const QColor & c ) -{ - m_peakGreen = c; -} + // Draw left levels + if (mappedPeakL > mappedMinPeak) + { + QPainterPath leftMeterPath; + leftMeterPath.addRoundedRect(computeLevelRect(leftMeterRect, mappedPeakL), radius, radius); + painter.fillPath(leftMeterPath, linearGrad); + } -void Fader::setPeakRed( const QColor & c ) -{ - m_peakRed = c; -} + // Draw left peaks + if (mappedPersistentPeakL > mappedMinPeak) + { + const auto peakRectL = computePeakRect(leftMeterRect, mappedPersistentPeakL); + painter.fillRect(peakRectL, linearGrad); + } -void Fader::setPeakYellow( const QColor & c ) -{ - m_peakYellow = c; -} + // Draw right levels + if (mappedPeakR > mappedMinPeak) + { + QPainterPath rightMeterPath; + rightMeterPath.addRoundedRect(computeLevelRect(rightMeterRect, mappedPeakR), radius, radius); + painter.fillPath(rightMeterPath, linearGrad); + } + // Draw right peaks + if (mappedPersistentPeakR > mappedMinPeak) + { + const auto peakRectR = computePeakRect(rightMeterRect, mappedPersistentPeakR); + painter.fillRect(peakRectR, linearGrad); + } + + painter.restore(); +} } // namespace lmms::gui