From 5aa542d9d79884e6df8c706dd94571fb01bc6584 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 30 Dec 2023 17:43:20 +0100 Subject: [PATCH 01/36] Render fader levels in code with a gradient Render the fader level in code using a gradient instead of using pixmaps. The problem with the pixmaps is that they don't "know" how a fader instance is configured with regards to the minimum and maximum value. This means that the display can give quite a wrong impression. The rendering of levels has been unified in the method `paintLevels`. It can render using dbFS and linear scale. The method `paintLinearLevels` has been removed completely, i.e. there's no more code that renders using pixmaps. Much of the previous code relied on the size of the background image `fader_background.png`, e.g. the initialization of the size. For now the `Fader` widget is initially resized to the size of that background image as it is present in the default and classic theme (see `Fader::init`). All rendering uses the size of the widget itself to determine where to draw what. This means that the widget is prepared to be resizable. The method `paintLevels` first renders the background of the level indicators and uses these as clipping paths for all other rendering operations, e.g. for the rendering of the levels themselves. Levels are rendered using a gradient which is defined with the following stops: * Two stops for the ok levels. * One stop for warning levels. * One stop for clipping levels. Peak indicators do not use the three distinct colors anymore but instead use the color of the gradient at that position of the peak. This makes everything look "smooth". The code now also renders a marker at unity position, i.e. at position 1.0 in linear levels and 0 dbFS in dbFS scale. The painting code makes lots of use of the class `PaintHelper`. This class is configured with a minimum and maximum value and can then return linear factors for given values. There are two supported modes: * Map min to 0 and max to 1 * Map min to 1 and max to 0 It can also compute rectangles that correspond to a given value. These methods can be given rectangles that are supposed to represent the span from min to max. The returned result is then a rectangle that fills the lower part of the source rectangle according to the given value with regards to min and max (`getMeterRect`). Another method returns a rectangle of height 1 which lies inside the given source rectangle at the corresponding level (`getPersistentPeakRect`). The method `paintLevels` uses a mapping function to map the amplitude values (current peak value, persistent peak, etc.) to the display values. There's one mapper that keeps the original value and it is used to display everything in a linear scale. Another mapper maps everything to dbFS and uses these values as display everything in a dbFS scale. The following values must be mapped for the left and right channel to make this work: * Min and max display values (min and max peak values) * The current peak value * The persistent peak value * The value for unity, i.e. 1.0 in linear levels and 0 dbFS in dbFS scale. Remove the method `calculateDisplayPeak` which was used in the old method to render linear levels. `Fader::setPeak` now uses `std::clamp` instead of doing "manual" comparisons. The LMMS plugins Compressor, EQ and Delay are still configured to use linear displays. It should be considered to switch them to dbFS/logarithmic displays as well and to remove the code that renders linearly. --- include/Fader.h | 4 +- src/gui/widgets/Fader.cpp | 234 +++++++++++++++++++++----------------- 2 files changed, 132 insertions(+), 106 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index c44d976a712..cf0164b7b0f 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -124,8 +124,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView inline bool clips(float const & value) const { return value >= 1.0f; } - void paintDBFSLevels(QPaintEvent *ev, QPainter & painter); - void paintLinearLevels(QPaintEvent *ev, QPainter & painter); + void paintLevels(QPaintEvent *ev, QPainter & painter, bool linear = false); int knobPosY() const { @@ -136,7 +135,6 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView } void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QElapsedTimer &lastPeakTimer ); - int calculateDisplayPeak( float fPeak ); void updateTextFloat(); diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 9ddbc74e187..a2c6f5cf887 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" @@ -115,10 +116,8 @@ 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 ); + // TODO For now set to the size of fader_background.png of the classic and default theme. + setMinimumSize(23, 116); setModel( model ); setHintText( "Volume:","%"); } @@ -249,19 +248,12 @@ void Fader::wheelEvent ( QWheelEvent *ev ) /// 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(); @@ -269,7 +261,7 @@ 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 ); update(); @@ -309,125 +301,161 @@ void Fader::updateTextFloat() } -inline int Fader::calculateDisplayPeak( float fPeak ) -{ - int peak = static_cast(m_back.height() - (fPeak / (m_fMaxPeak - m_fMinPeak)) * m_back.height()); - - return qMin(peak, m_back.height()); -} - - void Fader::paintEvent( QPaintEvent * ev) { QPainter painter(this); - // Draw the background - painter.drawPixmap(ev->rect(), m_back, ev->rect()); - // Draw the levels with peaks - if (getLevelsDisplayedInDBFS()) - { - paintDBFSLevels(ev, painter); - } - else - { - paintLinearLevels(ev, painter); - } + // TODO LMMS Compressor, EQ and Delay still use linear displays... + paintLevels(ev, painter, !getLevelsDisplayedInDBFS()); // Draw the knob painter.drawPixmap(0, knobPosY() - m_knob.height(), m_knob); } -void Fader::paintDBFSLevels(QPaintEvent * ev, QPainter & painter) +class PaintHelper { - int height = m_back.height(); - int width = m_back.width() / 2; - int center = m_back.width() - width; - - float const maxDB(ampToDbfs(m_fMaxPeak)); - float const minDB(ampToDbfs(m_fMinPeak)); - - // 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); - - - // 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 ) +public: + PaintHelper(float min, float max) : + m_min(min), + m_max(max), + // 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. + m_fullSpanReciprocal(1. / (max - min)) { - persistentPeak_L = 4; } - if( persistentLeftPeakDBFS > minDB ) + + float mapMaxZeroAndMinOne(float value) { - QColor const & peakColor = clips(m_persistentPeak_L) ? peakRed() : - persistentLeftPeakDBFS >= -6 ? peakYellow() : peakGreen(); - painter.fillRect( QRect( 2, persistentPeak_L, 7, 1 ), peakColor ); + return (m_max - value) * m_fullSpanReciprocal; } - - // 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 ) + float mapMaxZeroAndMinOneClamped(float value) { - persistentPeak_R = 4; + return std::clamp(mapMaxZeroAndMinOne(value), 0.f, 1.f); } - if( persistentRightPeakDBFS > minDB ) + + float mapMinZeroAndMaxOne(float value) { - QColor const & peakColor = clips(m_persistentPeak_R) ? peakRed() : - persistentRightPeakDBFS >= -6 ? peakYellow() : peakGreen(); - painter.fillRect( QRect( 14, persistentPeak_R, 7, 1 ), peakColor ); + return 1. - mapMaxZeroAndMinOne(value); } -} -void Fader::paintLinearLevels(QPaintEvent * ev, QPainter & painter) -{ - // peak leds - //float fRange = abs( m_fMaxPeak ) + abs( m_fMinPeak ); + float mapMinZeroAndMaxOneClamped(float value) + { + return std::clamp(mapMinZeroAndMaxOne(value), 0.f, 1.f); + } - int height = m_back.height(); - int width = m_back.width() / 2; - int center = m_back.width() - width; + QRect getMeterRect(QRect const & meterRect, float peak) + { + float const span = peak - m_min; + int mappedHeight = meterRect.height() * span * m_fullSpanReciprocal; - 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)); + return meterRect.adjusted(0, meterRect.height() - mappedHeight, 0, 0); + } - if( m_persistentPeak_L > 0.05 ) + QRect getPersistentPeakRect(QRect const & meterRect, float peak) { - painter.fillRect( QRect( 2, persistentPeak_L, 7, 1 ), ( m_persistentPeak_L < 1.0 ) - ? peakGreen() - : peakRed() ); + int persistentPeak_L = meterRect.height() * (1 - (peak - m_min) * m_fullSpanReciprocal); + + return QRect(meterRect.x(), persistentPeak_L, meterRect.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)); +private: + float const m_min; + float const m_max; + float const m_fullSpanReciprocal; +}; + +void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) +{ + std::function mapper = [this](float value) { return ampToDbfs(qMax(0.0001, value)); }; - if( m_persistentPeak_R > 0.05 ) + if (linear) { - painter.fillRect( QRect( 14, persistentPeak_R, 7, 1 ), ( m_persistentPeak_R < 1.0 ) - ? peakGreen() - : peakRed() ); + mapper = [this](float value) { return value; }; } -} + painter.save(); + + QRect const baseRect = rect(); + + int const height = baseRect.height(); + + int const margin = 2; + int const distanceBetweenMeters = 2; + + int const numberOfMeters = 2; + int const meterWidth = (baseRect.width() - 2 * margin - distanceBetweenMeters * (numberOfMeters - 1)) / numberOfMeters; + + QRect leftMeterRect(margin, margin, meterWidth, height - 2 * margin); + QRect rightMeterRect(baseRect.width() - margin - meterWidth, margin, meterWidth, height - 2 * margin); + + QPainterPath path; + qreal radius = 1; + path.addRoundedRect(leftMeterRect, radius, radius); + path.addRoundedRect(rightMeterRect, radius, radius); + painter.fillPath(path, Qt::black); + + // Now clip everything to the paths of the meters + painter.setClipPath(path); + + float const mappedMinPeak(mapper(m_fMinPeak)); + float const mappedMaxPeak(mapper(m_fMaxPeak)); + float const mappedPeakL(mapper(m_fPeakValue_L)); + float const mappedPeakR(mapper(m_fPeakValue_R)); + float const mappedPersistentPeakL(mapper(m_persistentPeak_L)); + float const mappedPersistentPeakR(mapper(m_persistentPeak_R)); + float const mappedUnity(mapper(1.f)); + float const mappedLastOk(mapper(dbfsToAmp(-12.f))); + + PaintHelper ph(mappedMinPeak, mappedMaxPeak); + + // Prepare the gradient for the meters + // TODO Enable for style sheets + QColor const clippingColor = QColor(193, 32, 56); //Qt::red; + QColor const warnColor = QColor(214, 236, 82); //Qt::yellow; + QColor const okColor = QColor(10, 212, 92); //Qt::green; + + QLinearGradient linearGrad(0, margin, 0, leftMeterRect.y() + leftMeterRect.height()); + linearGrad.setColorAt(0, clippingColor); + linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedUnity), warnColor); + linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedLastOk), okColor); + linearGrad.setColorAt(1, okColor); + + QColor unityMarkerColor(127, 127, 127, 127); + + // Draw left levels + QRect leftMeterMargins = leftMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); + painter.fillRect(ph.getMeterRect(leftMeterMargins, mappedPeakL), linearGrad); + + // Draw left peaks + auto const peakRectL = ph.getPersistentPeakRect(leftMeterMargins, mappedPersistentPeakL); + painter.fillRect(peakRectL, linearGrad); + + // Draw unity line (0 dbFS, 1.0 amplitude) + auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); + painter.fillRect(unityRectL, unityMarkerColor); + + // Draw right levels + QRect rightMeterMargins = rightMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); + painter.fillRect(ph.getMeterRect(rightMeterMargins, mappedPeakR), linearGrad); + + // Draw right peaks + auto const peakRectR = ph.getPersistentPeakRect(rightMeterMargins, mappedPersistentPeakR); + painter.fillRect(peakRectR, linearGrad); + + // Draw unity line (0 dbFS, 1.0 amplitude) + auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); + painter.fillRect(unityRectR, unityMarkerColor); + + // TODO + QPen pen(QColor(255, 255, 255, 18)); + pen.setWidth(2); + painter.setPen(pen); + painter.drawPath(path); + + painter.restore(); +} QColor const & Fader::peakGreen() const { From dac9208321279d7d3b749faa4d29ff1eaffec50b Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 30 Dec 2023 18:18:51 +0100 Subject: [PATCH 02/36] Remove unused pixmaps from `Fader` Remove the now unused pixmaps for the background and the LEDs from the `Fader` class and remove the files from the default and classic theme directories. --- data/themes/classic/fader_background.png | Bin 1391 -> 0 bytes data/themes/classic/fader_leds.png | Bin 3638 -> 0 bytes data/themes/default/fader_background.png | Bin 905 -> 0 bytes data/themes/default/fader_leds.png | Bin 295 -> 0 bytes include/Fader.h | 2 -- src/gui/widgets/Fader.cpp | 2 +- 6 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 data/themes/classic/fader_background.png delete mode 100644 data/themes/classic/fader_leds.png delete mode 100644 data/themes/default/fader_background.png delete mode 100644 data/themes/default/fader_leds.png diff --git a/data/themes/classic/fader_background.png b/data/themes/classic/fader_background.png deleted file mode 100644 index 682ff4c92815efe638b9adfd9b7ef723639ccd3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1391 zcmV-#1(5oQP))#srQ|EuLfBj_~LCj!sG-WQZtWe9i zyuJNU$LV|qlYoSghU9N)8K#Qc_4?`TPe%SSf|(t?2#Og@6{?EMUoSk{gIDj>v0lp-I7glz0>F8`3#|@TfE-h>j(6?2#6RgwdPMuXx%MYVW!Z0NX^-i z3o~pk(5z5XT;Kk_Q}b7Fyd@0@Sp&KDulWRK0*Qc$QHuAun&EN>`E-5-6M3Jf1T}@_ z3{}JJcIk-xH2PNbUuB{U+d)p`tW}vvV=KOQt@&v+q0EFb&y5!^mpjO(*T%PL7@%rx zLOUaW86oTw$IO_EdGGEp5wXw2kO&%QgZ;Zs=;RX@TX8l=t~>jjEAmfUQE|IoI@g?o zKZyl%DUSTXZt~}`^wxPoC!fyP7q#Z5 zd8f~%)m&qP`fj-#uvOQw%|L$9{_BgYIZh2BG z#)Q^hfA8;!!c{Pd`_SOTO?@7mn}*apsOH{o?i4<>PH8EwavyC)mRfV4PSxHucirNh z!pyKzT)FCYw-CD`riwh=-x0`HZmyK3T=zJXL!VdOa)jbq^!aD@w{6|R^qKu@YH>{7 zA~B(*KtqdcbEuznPn28TJ5OlTTq3txJkj<(uNyRxcT0}C_h$deC$!})*4)CLv*4Oq z#76W9y>#vtlGrUxab=k9_)xBH&K-&$OIvA_K(DE zJ1L4cP03w|+7Y?pI)$dC&uvHLRxO{>;^z9N(5F@2BH=7l?V&zrj^tmLyrr*$UiSHl z{g)fAjihL`TY^9P@AHbhvj1!)lAlMnEsSBs{s$nhcXRA$JU{mgWjo^{pX#A{|0C|^ z+=ohY#Wg>FeA^;zLRA&HdunltJBvD{rQTVn;(8~A9;erEf9v~DulxH!`rOekiRiY2 zW?H3l?atz;`%rfaj53?==Lh;+gpmgFdLMHi8qT7+1yBC%i4>Y5`OmG_kC;%OxR!B6 zs=TLiNmdz`<^z%<=TK@|agNkNcT$Tw(VqOfR#da@96Gt$TB}^m$k{e`i%8rmu2pXT zTgBMt6uoO@{vTR#KvoOYb%-aDCF3f^pxL}zHop=Puu$uBJ*dyemim+UO>Rwp_EYGZ zTI81gA8=>!MW366o7>EC1Nlmys~*Ar68l_O+7}DYWV!yuLgeS&YrZhil0sJ`n?AJN xS)|pS#g9z%@c_lg7v#^L|9Kzg{d(>`{{j1^Dm5N5f$IPO002ovPDHLkV1jua!}|aL diff --git a/data/themes/classic/fader_leds.png b/data/themes/classic/fader_leds.png deleted file mode 100644 index 6c673cf36d1841a9c2206f6ac523fe3618405624..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3638 zcmV-64$1L}P)Q6o|MY)b}5;%bD#OBbOk&Foz;4Hagk^$&%x;w*FW30GCX9+ zTTSv~!0Q#{XM=Q_ zBw1i!I>q$|23Lj$KzfXsd+g}pi!cKGPX+mzOY$mE704{;@_ry;mhb)4Ch2bW5)Rbh zt*JuO6cU9ZBeMlA`Hx>&!k_(zGi7bPi=fMnswiaU7KkS27?{X%!;g-v4EKX<0ov@~ zap>}RUYGy6g8Ymnxl5O)=V5FS27shl{*5a?B;73@!T~4VT2*gLZh>R71$OT3vxGl= zL$7q!I|;b#s48UU%8VuE7#PoT;}3tkGTaB!4TN3bt%b4%$sCN7;9v#$Hjs{L2)fb3 z3ousDTf(2ZWs7t))DUo28#7;IEH=mB zSe~07A6^;m1=$RQ{or*jlV_p7g1iT0tp@@gqv!K5mVm>0=U0Y*{d4Wo-RdG7a^QB^ z(KL-jc9G*J=DGadH!a~$-nKzHR@V^lRG}&g*}@{@@gf6}JYV?k=*n<6$QB#4)PtuM zGz}7YI39z+3i8b$9YI5`LaqSgvoKhOoLT<0-C^0>?xbavLvM?wx8?YBiBH`%WC{P# zon6wg+JWC|$EGM`3uVS)MGlV^_~QPtmElg1&9%_73Or6-p3K7WX*eQQ`6dPFSOb1T zo-M%mNjN+Q1+)As*EY%K_F9@(RpW81Xqu4Blo_2a^4E8aTEd^WyF)tGI0$%D6q`aW zS7zem0)xlrxb@qUE5mC*HhH0C^)h(|MyKG-l2yK;8fkBYfEN@Ma(Nh=fg>51H_Pw6 zVYO^rTSH4j6&|;WXb{ho8J$?*%G<^);s1GWSlXJa2zaYdRfTN6%=n2#j*iT6+uoU# z;ng6ULeRV#JT4Fo5*ZksfVcBj`Fa=9-lDffQ6Za$i4$-n1|_rno|{9mxywQ0YCB%H zif9_~v_^Ddkx$<|WeNYm{f*MrWG7Ikpr{I&oG>-Lz~N&>ZofaaGQ0|8W1}H=0|N0h zM8;t_X_a^Rk+xiStr_~Q@O zOM8nQzfVO`AeYw|pDuHBsKmd0CAl)(2C}gYnj67o%siEb(Qz1=vC7vrAZ;z+_hE#? zvoT9TyLkT$%fmdA_B=&nbEN_f43)T34d&#U)sVp{B^c>Kkgtx#vk^Ldz@grmbCX8D)ybjrpJRWvoJ zxZNruLMo{diE4cI>Z~RFdyjghwN=6IH)fs_CMPwHzFFqWcjZlT1^LhhXl@3#TR%e+ zNf?Vjbkr(uZ9~Fs5bzs+p*dat)=@xA@;mQ#$e(Sn(bTNq_9&o1A}K^88h?M)oF)9x z$7?0ruHdgzQ54a`Cxo}&EOXZ#MU&i)tlI=l&EWFrJx?Vd8iDb*t@4)jy4)YoXP(W% z)C3G20TxX1JN~^&Hf&N@6IO70Ks1F^LL)i~yZ>gv68^{&c4=)_sPluODCDxj^aQ+l zSmW-0Sv1L=NY`dq(}EEWsU$>?!_*P0ym1rK+JPRfLM{u_V=#OKD4688e_fIF-O$vc zk3}?nEMp_E=aXUy-}j^<;STUG`$DJ2;kN^D&lkib_aNVihkvoJXZkwGA9lHYn?m8{>Q&)j9)L#GnL_y}CL%R2K157;H#0luJuqC!3cC&q-g z28FNQVxGAdY1*RC+~or)LplNDBao;d_ix1r*T<4i!}K^z4gwjI{FeJ`WZf1UtHUZT zuYSyB62kb1aMNXZOZWp%Ii;mT#T!tt*&v%1X2yh}L5=%vo-@gP$g0h-I*cAJkdDLT zame;r<({obQz!WRpxTzk0w)K7v`PN?2i(%R#ZE(5#qHHk|8zoQ@_3nl-kG+9fAuM! zG_AGa3#cfnLO!c;B3kCy;39i(%30-g-OvyQr&phOCIOQpP^=(#Y(tvXf;XVwx8&0> zGXbgo3i9h7sFRK!2MsMMPM^&PUu1G*kvn$AEa7)Q9g?O_JKlf|Re^k_%*>d^$UupQ zZ!(=k)FIAga!rG50;Z0EcF-zUw;_#d!E3aokb#*oC=388lYGxN>ZQHML48XVPOlBo zG%`tHdbq@wcUn*XFFn&Jjh)qa0xGJikWXuz94`^+FR|~&S(Dt4*tbA^>q_~o{!nBI z=M1F26FkPu3mKS=!onbsG|8|2W}~!q*ANQZarta$Wg(j^GjpuOJ(or-;s5$fo2>4t z#uKois0wqLGPBVVk%1zQetya-rw4*dZ4t=EA${y!@rc5kaB05muu^UYH=LB@Q zXQ?d$xfsli0KcjrKNG243m#+PGM9#I6#a27VUmA(Z-<0?Tm)NdsP$H%X+l1>z|6=z z-@N3gCH%%`H^{0^C+?sz^K_ZS*gVnxJU_VMxJe$=<<(1VDMKy++VH!})h>PJ*mQYm zNgg-JulUw_Y3gwkY^}lJtpW{l@e;Gg=6Lwy{g&|Se%vGVolaaqJBkYPnMLB!c_#aF zJn>I&o8%#cZhdW0Yn(*$31i{%Mg{qwBXohoIEjiGkfpVSS$_G08>Okoi@&vo8m}Eq zgF?JSY^1;=7hAU$yMJ<~ggTu#gViW16f+AXBlAoQWH@mB(RY!zgW}cY#L(9kuUC+t zh0qC#@xMjO8cVKzAZC*9e5hO2bl2f;bK>yoo1#LjMEqEm?_F%&6n*xm=SZ;2g)`{T z<>^I|kpk2GDW1N5z$CBN+fs2oS4n=hK6A@@t{<2+$v^(k8Pd>GM_s!Mhu4mjVJ==I zF`VW57r$f)|J$FQFM%!(wIPS`g)Wea=9%eF^5bg{n&hkAL;lMO@{d%IN8ed2t_;8E z;j?7*)*zlXw?1Asq3nv zCgea-6-wzMnMjV=z8EiE_v(Ad>rC=jE6BH3nEB|t$hSXyzJ#`}!rktr+Ehg&$AIW{%+#O?wei$verSrr*PQmYY-_@K3Oz4Gl4K74A=>gs+VlOFi?_G&)MwsTsVz%q=&8#4 zDx9Hz#691?OT1g(hqnAd&QNdf`!Msq(|!_t06qWH_5bYpU-z~ZuJTmYET1PB!+c&g zSXQ@K)2AvIgQYT|OgX1++byuee-fHtjB!HD&Ipa;4a?(APVVmwGqmuEtMfo& zs*>@Zl|}9jP8e?~Z?F!{ZDzv~*l)?*T+rgCKlxyuaWWuzgxsHG00000NkvXXu0mjfa1gIE diff --git a/data/themes/default/fader_leds.png b/data/themes/default/fader_leds.png deleted file mode 100644 index 707902e04c62f0158a7e6690497d68a1f00e20c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^;y_%&!3HGryjF$)DVAa<&kznEsNqQI0P;BtJR*yM z>aT+^qm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0vZJY5_^ zG8*6BQsg^iAj0-w+JX%%&5!vwM8x{e=x`mB-4MeNdu3W{?~-Im&&}^wK70Cp`m@e! zCd;NA3fVftM^7sLTKDUB1)PfWc1;YCmEZn3-CX^?Rb_lZ%>Fww4?irh*b{r!d&|yz z_S`ckr(26z$k;{i*(v({{MG9hvhTiq`sB1Mw+vr9NFgd!^Q~glFXjE;7ys|7KYrge XUC}b^)r6lw_cD08`njxgN@xNA2mo}K diff --git a/include/Fader.h b/include/Fader.h index cf0164b7b0f..9ed4fc04d7e 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -150,8 +150,6 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView QElapsedTimer m_lastPeakTimer_L; QElapsedTimer m_lastPeakTimer_R; - QPixmap m_back = embed::getIconPixmap("fader_background"); - QPixmap m_leds = embed::getIconPixmap("fader_leds"); QPixmap m_knob = embed::getIconPixmap("fader_knob"); bool m_levelsDisplayedInDBFS; diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index a2c6f5cf887..e98c2e2c2dc 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -116,7 +116,7 @@ void Fader::init(FloatModel * model, QString const & name) { setWindowTitle( name ); setAttribute( Qt::WA_OpaquePaintEvent, false ); - // TODO For now set to the size of fader_background.png of the classic and default theme. + // TODO For now resize the widget to the size of the previous background image "fader_background.png" as found in the classic and default theme setMinimumSize(23, 116); setModel( model ); setHintText( "Volume:","%"); From 9a4082ac67b9601339fe04d43277144f305368ac Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 30 Dec 2023 19:04:37 +0100 Subject: [PATCH 03/36] Rename peak properties and use them to render levels Rename the peak properties as follows: * peakGreen -> peakOk * peakRed -> peakClip * peakYellow -> peakWarn The reasoning is that a style might for example use a different color than green to indicate levels that are ok. Use the properties to initialize the gradient that is used to render the levels. Initialize the properties to the colors of the current default theme so that it's not mandatory to set them in a style sheet. Up until now they have all been initialized as black. --- data/themes/classic/style.css | 6 ++--- data/themes/default/style.css | 6 ++--- include/Fader.h | 26 +++++++++++----------- src/gui/widgets/Fader.cpp | 42 +++++++++++++++++------------------ 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/data/themes/classic/style.css b/data/themes/classic/style.css index f61d4ba580c..116dc08a050 100644 --- a/data/themes/classic/style.css +++ b/data/themes/classic/style.css @@ -651,9 +651,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/style.css b/data/themes/default/style.css index e1f0cf395b7..f9211f3a0e8 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -692,9 +692,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 9ed4fc04d7e..48292c01008 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -66,10 +66,10 @@ 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 ) + Q_PROPERTY(QColor peakOk READ peakOk WRITE setPeakOk) + Q_PROPERTY(QColor peakClip READ peakClip WRITE setPeakClip) + Q_PROPERTY(QColor peakWarn READ peakWarn WRITE setPeakWarn) + 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 ); @@ -89,14 +89,14 @@ 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 & peakOk() const; + void setPeakOk(const QColor& c); - QColor const & peakRed() const; - void setPeakRed( const QColor & c ); + QColor const & peakClip() const; + void setPeakClip(const QColor& c); - QColor const & peakYellow() const; - void setPeakYellow( const QColor & c ); + QColor const & peakWarn() const; + void setPeakWarn(const QColor& c); inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; } inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; } @@ -159,9 +159,9 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView static SimpleTextFloat * s_textFloat; - QColor m_peakGreen; - QColor m_peakRed; - QColor m_peakYellow; + QColor m_peakOk; + QColor m_peakClip; + QColor m_peakWarn; } ; diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index e98c2e2c2dc..51f4a70ba61 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -74,9 +74,9 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : m_levelsDisplayedInDBFS(false), m_moveStartPoint( -1 ), m_startValue( 0 ), - m_peakGreen( 0, 0, 0 ), - m_peakRed( 0, 0, 0 ), - m_peakYellow( 0, 0, 0 ) + m_peakOk(10, 212, 92), + m_peakClip(193, 32, 56), + m_peakWarn(214, 236, 82) { if( s_textFloat == nullptr ) { @@ -101,8 +101,9 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma m_levelsDisplayedInDBFS(false), m_moveStartPoint( -1 ), m_startValue( 0 ), - m_peakGreen( 0, 0, 0 ), - m_peakRed( 0, 0, 0 ) + m_peakOk(10, 212, 92), + m_peakClip(193, 32, 56), + m_peakWarn(214, 236, 82) { if( s_textFloat == nullptr ) { @@ -411,10 +412,9 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) PaintHelper ph(mappedMinPeak, mappedMaxPeak); // Prepare the gradient for the meters - // TODO Enable for style sheets - QColor const clippingColor = QColor(193, 32, 56); //Qt::red; - QColor const warnColor = QColor(214, 236, 82); //Qt::yellow; - QColor const okColor = QColor(10, 212, 92); //Qt::green; + QColor const & clippingColor = peakClip(); + QColor const & warnColor = peakWarn(); + QColor const & okColor = peakOk(); QLinearGradient linearGrad(0, margin, 0, leftMeterRect.y() + leftMeterRect.height()); linearGrad.setColorAt(0, clippingColor); @@ -457,34 +457,34 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) painter.restore(); } -QColor const & Fader::peakGreen() const +QColor const & Fader::peakOk() const { - return m_peakGreen; + return m_peakOk; } -QColor const & Fader::peakRed() const +QColor const & Fader::peakClip() const { - return m_peakRed; + return m_peakClip; } -QColor const & Fader::peakYellow() const +QColor const & Fader::peakWarn() const { - return m_peakYellow; + return m_peakWarn; } -void Fader::setPeakGreen( const QColor & c ) +void Fader::setPeakOk(const QColor& c) { - m_peakGreen = c; + m_peakOk = c; } -void Fader::setPeakRed( const QColor & c ) +void Fader::setPeakClip(const QColor& c) { - m_peakRed = c; + m_peakClip = c; } -void Fader::setPeakYellow( const QColor & c ) +void Fader::setPeakWarn(const QColor& c) { - m_peakYellow = c; + m_peakWarn = c; } From c9e83a331693444934d87e2e8374a020568f9455 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 30 Dec 2023 22:30:31 +0100 Subject: [PATCH 04/36] Always render the knob in the middle of the fader Render the knob in the middle of the fader regardless of the width. The previous implementation was dependent on the fader pixmap having a matching width because it always rendered at x=0. --- src/gui/widgets/Fader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 51f4a70ba61..b7c55ad1c03 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -311,7 +311,7 @@ void Fader::paintEvent( QPaintEvent * ev) paintLevels(ev, painter, !getLevelsDisplayedInDBFS()); // Draw the knob - painter.drawPixmap(0, knobPosY() - m_knob.height(), m_knob); + painter.drawPixmap((width() - m_knob.width()) / 2, knobPosY() - m_knob.height(), m_knob); } class PaintHelper From ec4830feca532cb3abb78bd71a8f504169c196df Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 30 Dec 2023 22:31:59 +0100 Subject: [PATCH 05/36] Set size policy of fader to minimum expanding Set the size policy of the fader to minimum expanding in both directions. This will make the fader grow in layouts if there is space. --- src/gui/widgets/Fader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index b7c55ad1c03..a30edaef990 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -119,6 +119,7 @@ void Fader::init(FloatModel * model, QString const & name) setAttribute( Qt::WA_OpaquePaintEvent, false ); // TODO For now resize the widget to the size of the previous background image "fader_background.png" as found in the classic and default theme setMinimumSize(23, 116); + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setModel( model ); setHintText( "Volume:","%"); } From 8051134f119e51ca8d80c44f14855682b45df1d0 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 1 Jan 2024 14:44:27 +0100 Subject: [PATCH 06/36] Default dbFS levels and better peak values Default to dbFS levels for all faders and set some better minimum and maximum peak values. --- src/gui/MixerChannelView.cpp | 3 --- src/gui/widgets/Fader.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/gui/MixerChannelView.cpp b/src/gui/MixerChannelView.cpp index 0f8ccedeac8..a6f233951d2 100644 --- a/src/gui/MixerChannelView.cpp +++ b/src/gui/MixerChannelView.cpp @@ -120,9 +120,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 a30edaef990..a22fc12abc5 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -69,9 +69,9 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : m_fPeakValue_R( 0.0 ), m_persistentPeak_L( 0.0 ), m_persistentPeak_R( 0.0 ), - m_fMinPeak( 0.01f ), - m_fMaxPeak( 1.1 ), - m_levelsDisplayedInDBFS(false), + m_fMinPeak(dbfsToAmp(-42)), + m_fMaxPeak(dbfsToAmp(9)), + m_levelsDisplayedInDBFS(true), m_moveStartPoint( -1 ), m_startValue( 0 ), m_peakOk(10, 212, 92), @@ -96,9 +96,9 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma m_fPeakValue_R( 0.0 ), m_persistentPeak_L( 0.0 ), m_persistentPeak_R( 0.0 ), - m_fMinPeak( 0.01f ), - m_fMaxPeak( 1.1 ), - m_levelsDisplayedInDBFS(false), + m_fMinPeak(dbfsToAmp(-42)), + m_fMaxPeak(dbfsToAmp(9)), + m_levelsDisplayedInDBFS(true), m_moveStartPoint( -1 ), m_startValue( 0 ), m_peakOk(10, 212, 92), From 3b7cc154178b96e82c8e106e7c7b56441945c37c Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 1 Jan 2024 16:57:24 +0100 Subject: [PATCH 07/36] Fix faders of Crossover EQ Fix the faders of the Crossover EQ which were initialized and rendered much too wide and with a line at unity. The large width also resulted in the knobs being rendered outside of view. Resize the fader to the minimum size so that it is constructed at a sane default. Introduce a property that allows to control if the unity line is rendered. The property is available in style sheets and defaults to the unity lines being rendered. Adjust the paint code to evaluate the property. Initialize the faders of the Crossover EQ such that the unity line is not drawn. --- include/Fader.h | 6 +++++ .../CrossoverEQ/CrossoverEQControlDialog.cpp | 4 +++ src/gui/widgets/Fader.cpp | 26 +++++++++++++------ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index 48292c01008..a84329af445 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -70,6 +70,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView Q_PROPERTY(QColor peakClip READ peakClip WRITE setPeakClip) Q_PROPERTY(QColor peakWarn READ peakWarn WRITE setPeakWarn) Q_PROPERTY(bool levelsDisplayedInDBFS READ getLevelsDisplayedInDBFS WRITE setLevelsDisplayedInDBFS) + Q_PROPERTY(bool renderUnityLine READ getRenderUnityLine WRITE setRenderUnityLine) Fader( FloatModel * _model, const QString & _name, QWidget * _parent ); Fader( FloatModel * _model, const QString & _name, QWidget * _parent, QPixmap * back, QPixmap * leds, QPixmap * knob ); @@ -101,6 +102,9 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; } inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; } + inline bool getRenderUnityLine() const { return m_renderUnityLine; } + inline void setRenderUnityLine(bool value = true) { m_renderUnityLine = value; } + void setDisplayConversion( bool b ) { m_conversionFactor = b ? 100.0 : 1.0; @@ -162,6 +166,8 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView QColor m_peakOk; QColor m_peakClip; QColor m_peakWarn; + + bool m_renderUnityLine; } ; diff --git a/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp index 12b560b2370..3cbca5dbe8d 100644 --- a/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp +++ b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp @@ -73,21 +73,25 @@ CrossoverEQControlDialog::CrossoverEQControlDialog( CrossoverEQControls * contro 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); 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); 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); 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/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index a22fc12abc5..bd6cf6f2c7b 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -76,7 +76,8 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : m_startValue( 0 ), m_peakOk(10, 212, 92), m_peakClip(193, 32, 56), - m_peakWarn(214, 236, 82) + m_peakWarn(214, 236, 82), + m_renderUnityLine(true) { if( s_textFloat == nullptr ) { @@ -103,7 +104,8 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma m_startValue( 0 ), m_peakOk(10, 212, 92), m_peakClip(193, 32, 56), - m_peakWarn(214, 236, 82) + m_peakWarn(214, 236, 82), + m_renderUnityLine(true) { if( s_textFloat == nullptr ) { @@ -117,8 +119,10 @@ void Fader::init(FloatModel * model, QString const & name) { setWindowTitle( name ); setAttribute( Qt::WA_OpaquePaintEvent, false ); - // TODO For now resize the widget to the size of the previous background image "fader_background.png" as found in the classic and default theme - setMinimumSize(23, 116); + // 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 + QSize minimumSize(23, 116); + setMinimumSize(minimumSize); + resize(minimumSize); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setModel( model ); setHintText( "Volume:","%"); @@ -434,8 +438,11 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) painter.fillRect(peakRectL, linearGrad); // Draw unity line (0 dbFS, 1.0 amplitude) - auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); - painter.fillRect(unityRectL, unityMarkerColor); + if (getRenderUnityLine()) + { + auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); + painter.fillRect(unityRectL, unityMarkerColor); + } // Draw right levels QRect rightMeterMargins = rightMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); @@ -446,8 +453,11 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) painter.fillRect(peakRectR, linearGrad); // Draw unity line (0 dbFS, 1.0 amplitude) - auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); - painter.fillRect(unityRectR, unityMarkerColor); + if (getRenderUnityLine()) + { + auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); + painter.fillRect(unityRectR, unityMarkerColor); + } // TODO QPen pen(QColor(255, 255, 255, 18)); From 796661a8b969448a82dbeb64603c84bc3877f95d Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 1 Jan 2024 17:26:10 +0100 Subject: [PATCH 08/36] Remove EqFader constructor with pixmaps Remove the constructor of `EqFader` that takes the pixmaps to the fader background, leds and knob. The background and leds pixmaps are not used by the base class `Fader` for rendering anymore to make the `Fader` resizable. A pixmap is still used to render the knob but the constructor that takes the knob as an argument does not do anything meaningful with it, i.e. all faders are rendered with the default knob anyway. Remove the resources for the fader background, leds and knob as they are not used and the knob was the same image as the default knob anyway. Remove the static pixmaps from the constructor of `EqControlsDialog`. Switch the instantiations of the EQ's faders to use the remaining constructor of `EqFader`. This constructor sets a different fixed size of (23, 116) compared to the removed constructor which set a size of (23, 80). Therefore all faders that used the removed constructor are now set explicitly to a fixed size of (23, 80). The constructor that's now used also calls a different base constructor than the removed one. The difference between the two base constructors of `Fader` is that one of them sets the member `m_conversionFactor` to 100.0 whereas the other one keeps the default of 1.0. The adjusted faders in `EqControlsDialog` are thus now constructed with the conversion factor set to 100. However, all of them already call `setDisplayConversion` with `false` after construction which results in the conversion factor being reset to 1.0. So the result should be the same as before the changes. --- plugins/Eq/EqControlsDialog.cpp | 17 ++++++++--------- plugins/Eq/EqFader.h | 14 -------------- plugins/Eq/faderback.png | Bin 700 -> 0 bytes plugins/Eq/faderknob.png | Bin 350 -> 0 bytes plugins/Eq/faderleds.png | Bin 280 -> 0 bytes 5 files changed, 8 insertions(+), 23 deletions(-) delete mode 100644 plugins/Eq/faderback.png delete mode 100755 plugins/Eq/faderknob.png delete mode 100644 plugins/Eq/faderleds.png 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/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 2a03c3a5c1e6c1469d3f3bc9887f0340cf909ee0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 700 zcmV;t0z>_YP)Uq`u<52<($j6>xy;fp;+A#SwQ6_&36G;FNc~XQEBlrzui)v z^6&q*w<|3Q^4)SyysuRh=o$XU%tWY}pngEd_1Jhs9jfMkh|epJTb9oS5mfx*4RiSQ z`n*v<32^GSV-vF@Yl%0gv;2wjt*hKQ+ZK5~za^rP48LBVhx;wg_Nk(X&hYEaP%EIt z3d##;nO|?k^a&Gw;S3Jv>v;f47-NnA&evzuyaDk3_;CL+J>VV2nB(Ka{R@EcUqv;48Oz86fDPhF iH30Y!k<;W3CI1EQEiz6+DKUQl0000aT+^qm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0wwJzX3_ zJUZWAv*uzl6li!@pHiEk9#zTB9nP};k?Wehv)@EjFiUI4N38v!l)P5W?IH&wyHl4+ ze49awV5n-yl%|sl3q!spGB7JJe`%e_$UIwlo4NSJHJ9Hm?@c>B`%d2OM6)X@UuU;+{nNVKt=T|tGI+ZBxvX1LivkZ+cTDT%wSn;@#WCY;2kpdD$y#d zgMS>Z$ez2zeM!OL-#6D^x2)Y6(Y{cn_Nr=K&Sw3^2R)hP=62hgtk2%H>TsxE{`aT@ z2jSp9`~3O3-~G3~K0N2%yR8k)a3FsycF|0s-+T8i{K>c=Qk3C$4c~g80~tJB{an^L HB{Ts5T`6*6 From cc6a7d9136c857864e97f7df7ed7222079578bd2 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 1 Jan 2024 18:14:16 +0100 Subject: [PATCH 09/36] Remove background and LEDs pixmap from Fader constructor Remove the parameters for the background and LEDs pixmap from the second `Fader` constructor. Make the knob pixmap parameter in the constructor a const reference. Assign the reference to the knob pixmap of the `Fader` itself. This enables clients to use their own fader knobs as is the case with the Crossover EQ. The EQ now renders using it's own knobs again. Make the second constructor delegate to the first one. This will additionally set the conversion factor to 100 but this is not a problem with the current code because the only user of the second constructor, the Crossover EQ, already calls `setDisplayConversion` with the parameter set to `false`, hence reinstating a conversion factor of 1. Remove the resources for the background and LEDs from the Crossover EQ as they are not used anymore. Remove the three QPixmap members from `CrossoverEQControlDialog` as they are not needed. The background and LEDs are not used anyway and the knob is passed in as a constant reference which is copied. Hence we can use a local variable in the constructor of `CrossoverEQControlDialog`. --- include/Fader.h | 2 +- .../CrossoverEQ/CrossoverEQControlDialog.cpp | 15 ++++++----- .../CrossoverEQ/CrossoverEQControlDialog.h | 6 ----- plugins/CrossoverEQ/fader_bg.png | Bin 340 -> 0 bytes plugins/CrossoverEQ/fader_empty.png | Bin 230 -> 0 bytes src/gui/widgets/Fader.cpp | 25 +++--------------- 6 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 plugins/CrossoverEQ/fader_bg.png delete mode 100644 plugins/CrossoverEQ/fader_empty.png diff --git a/include/Fader.h b/include/Fader.h index a84329af445..18c9c9f8687 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -73,7 +73,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView Q_PROPERTY(bool renderUnityLine READ getRenderUnityLine WRITE setRenderUnityLine) Fader( FloatModel * _model, const QString & _name, QWidget * _parent ); - Fader( FloatModel * _model, const QString & _name, QWidget * _parent, QPixmap * back, QPixmap * leds, QPixmap * knob ); + Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob); ~Fader() override = default; void init(FloatModel * model, QString const & name); diff --git a/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp b/plugins/CrossoverEQ/CrossoverEQControlDialog.cpp index 3cbca5dbe8d..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,28 @@ 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" ); 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 ca4eedafdc951c9741a3a9b3e520de47f1c8adc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^3P7B~!3HFsZ#L=!QY^(zo*^7SP{WbZ0pxQQctjQh z)n5l;MkkHg6+l7B64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1Spdb&7< zWHi3L<;d0Kz~FGPr|-&4tB~|pe%mr1F3MpO*MD)|Es)**-}wU#r+2MWw>vKc_^l17D?|1H qmxTi^lYZPQczOR51JjS{2KC%hoB3*oLR^5JWAJqKb6Mw<&;$U+GI-kn diff --git a/plugins/CrossoverEQ/fader_empty.png b/plugins/CrossoverEQ/fader_empty.png deleted file mode 100644 index 797a0d3bc2d06622281319ac066f484753e8cb6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^3P7B~!3HFsZ#L=!Qfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#0f(rF9y@dPsa&9tWQl7;iF1B#Zfaf$gL6@8Vo7R> zLV0FMhJw4NZ$Nk>pEyvFpQnpsNXEUl=L{Jc7&w?0Wd1*A+{UkxaO>ISXEPf}1P2(a XT$qnaRDQSyG?~HE)z4*}Q$iB}YtT!* diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index bd6cf6f2c7b..55d63bdb7f8 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -90,29 +90,10 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : } -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(dbfsToAmp(-42)), - m_fMaxPeak(dbfsToAmp(9)), - m_levelsDisplayedInDBFS(true), - m_moveStartPoint( -1 ), - m_startValue( 0 ), - m_peakOk(10, 212, 92), - m_peakClip(193, 32, 56), - m_peakWarn(214, 236, 82), - m_renderUnityLine(true) +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) From 50781de57d4ce85422cfb6923670786c8ca4364a Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 1 Jan 2024 18:20:42 +0100 Subject: [PATCH 10/36] Remove the init method from Fader Remove the `init` method from `Fader` as it is not needed anymore due to the constructor delegation. Tidy up the parameter lists and use of spaces in the constructor. --- include/Fader.h | 4 +--- src/gui/widgets/Fader.cpp | 40 +++++++++++++++++---------------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index 18c9c9f8687..3f2a5f391e8 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -72,12 +72,10 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView Q_PROPERTY(bool levelsDisplayedInDBFS READ getLevelsDisplayedInDBFS WRITE setLevelsDisplayedInDBFS) Q_PROPERTY(bool renderUnityLine READ getRenderUnityLine WRITE setRenderUnityLine) - Fader( FloatModel * _model, const QString & _name, QWidget * _parent ); + 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 ); float getPeak_L() { return m_fPeakValue_L; } diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 55d63bdb7f8..72b2011a707 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -62,18 +62,18 @@ 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 ), +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(dbfsToAmp(-42)), m_fMaxPeak(dbfsToAmp(9)), m_levelsDisplayedInDBFS(true), - m_moveStartPoint( -1 ), - m_startValue( 0 ), + m_moveStartPoint(-1), + m_startValue(0), m_peakOk(10, 212, 92), m_peakClip(193, 32, 56), m_peakWarn(214, 236, 82), @@ -84,20 +84,6 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) : s_textFloat = new SimpleTextFloat; } - init(_model, _name); - - m_conversionFactor = 100.0; -} - - -Fader::Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob) : - Fader(model, name, parent) -{ - m_knob = knob; -} - -void Fader::init(FloatModel * model, QString const & 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 @@ -107,9 +93,17 @@ void Fader::init(FloatModel * model, QString const & name) setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setModel( model ); setHintText( "Volume:","%"); + + m_conversionFactor = 100.0; } +Fader::Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob) : + Fader(model, name, parent) +{ + m_knob = knob; +} + void Fader::contextMenuEvent( QContextMenuEvent * _ev ) { From 045a2cd5c3f9956b912100dfd5aeb0ef2ee5cf87 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Jan 2024 16:53:21 +0100 Subject: [PATCH 11/36] Draw unity lines last Draw the unity lines last so that they are not affected by the white-ish overdraw in line 423 (after the changes). --- src/gui/widgets/Fader.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index eae14c4b8ac..e0c671ad875 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -403,8 +403,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedLastOk), okColor); linearGrad.setColorAt(1, okColor); - QColor unityMarkerColor(127, 127, 127, 127); - // Draw left levels QRect leftMeterMargins = leftMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); painter.fillRect(ph.getMeterRect(leftMeterMargins, mappedPeakL), linearGrad); @@ -413,13 +411,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) auto const peakRectL = ph.getPersistentPeakRect(leftMeterMargins, mappedPersistentPeakL); painter.fillRect(peakRectL, linearGrad); - // Draw unity line (0 dbFS, 1.0 amplitude) - if (getRenderUnityLine()) - { - auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); - painter.fillRect(unityRectL, unityMarkerColor); - } - // Draw right levels QRect rightMeterMargins = rightMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); painter.fillRect(ph.getMeterRect(rightMeterMargins, mappedPeakR), linearGrad); @@ -428,18 +419,27 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) auto const peakRectR = ph.getPersistentPeakRect(rightMeterMargins, mappedPersistentPeakR); painter.fillRect(peakRectR, linearGrad); - // Draw unity line (0 dbFS, 1.0 amplitude) + // TODO + QPen pen(QColor(255, 255, 255, 18)); + pen.setWidth(2); + painter.setPen(pen); + painter.drawPath(path); + + // Draw left and right unity lines (0 dbFS, 1.0 amplitude) + QColor unityMarkerColor(127, 127, 127, 127); + + if (getRenderUnityLine()) + { + auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); + painter.fillRect(unityRectL, unityMarkerColor); + } + if (getRenderUnityLine()) { auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); painter.fillRect(unityRectR, unityMarkerColor); } - // TODO - QPen pen(QColor(255, 255, 255, 18)); - pen.setWidth(2); - painter.setPen(pen); - painter.drawPath(path); painter.restore(); } From a644bdcd4f8db2a515a039a15fc15c068b91c6b4 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 15:43:26 +0100 Subject: [PATCH 12/36] Introduce range with solid warn color Introduce a second point in the gradient for the warn colors so that we get a certain range with the full/solid warn color. The colors are distributed as follows now. The solid ok range goes from -inf dbFS to -12 dbFS. The warn range goes from -6 dbFS to 0 dbFS. In between the colors are interpolated. Values above 0 dbFS interpolate from the warn color to the clip color. This is now quite similar to the previous implementation. # Analysis of the previous pixmap implementation The pixmap implementation used pixmaps with a height of 116 pixels to map 51 dbFS (-42 dbFS to 9 dbFS) across the whole height. The pixels of the LED pixmap were distributed as follows along the Y-axis: * Margin: 4 * Red: 18 * Yellow: 14 * Green: 76 * Margin: 4 Due to the margins the actual red, yellow and green areas only represent a range of (1 - (4+4) / 116) * 51 ~ 47,48 dbFS. This range is distributed as follows across the colors: Red: 7.91 dbFS Yellow: 6.16 dbFS Green: 33.41 dbFS The borders between the colors are located along the following dbFS values: * Red/yellow: 9 - (4 + 18) / 116 * 51 dbFS ~ -0.67 dbFS * Yellow/green: 9 - (4 + 18 + 14) / 116 * 51 dbFS ~ -6.83 dbFS * The green marker is rendered for values above -40.24 dbFS. --- src/gui/widgets/Fader.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index e0c671ad875..6f5987d422e 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -388,7 +388,9 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) float const mappedPersistentPeakL(mapper(m_persistentPeak_L)); float const mappedPersistentPeakR(mapper(m_persistentPeak_R)); float const mappedUnity(mapper(1.f)); - float const mappedLastOk(mapper(dbfsToAmp(-12.f))); + float const mappedWarnEnd(mappedUnity); + float const mappedWarnStart(mapper(dbfsToAmp(-6.f))); + float const mappedOkEnd(mapper(dbfsToAmp(-12.f))); PaintHelper ph(mappedMinPeak, mappedMaxPeak); @@ -399,8 +401,9 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) QLinearGradient linearGrad(0, margin, 0, leftMeterRect.y() + leftMeterRect.height()); linearGrad.setColorAt(0, clippingColor); - linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedUnity), warnColor); - linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedLastOk), okColor); + linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedWarnEnd), warnColor); + linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedWarnStart), warnColor); + linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedOkEnd), okColor); linearGrad.setColorAt(1, okColor); // Draw left levels From 381257b1c896bdc74644cfb915363fcf21895d13 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 17:49:40 +0100 Subject: [PATCH 13/36] Remove unused method Fader::clips --- include/Fader.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index ff45d692a87..ff269a66405 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -124,8 +124,6 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView void wheelEvent( QWheelEvent *ev ) override; void paintEvent( QPaintEvent *ev ) override; - inline bool clips(float const & value) const { return value >= 1.0f; } - void paintLevels(QPaintEvent *ev, QPainter & painter, bool linear = false); int knobPosY() const From 0aebb8c745b2ee7d144df06808435636575c1105 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 19:22:36 +0100 Subject: [PATCH 14/36] Fader: Correctly render arbitrary ranges Adjust the `Fader` so that it can correctly render arbitrary ranges of min and max peak values, e.g. that it would render a display range of [-12 dbFS, -42 dbFS] correctly. Until now the gradient was defined to start at the top of the levels rectangle and end at the bottom. As a result the top was always rendered in the "clip" color and the bottom in the "ok" color. However, this is wrong, e.g. if we configure the `Fader` with a max value of -12 dbFS and a min value of -42 dbFS. In that case the whole range of the fader should be rendered with the "ok" color. The fix is to compute the correct window coordinates of the start and end point of gradient using from the "window" of values that the `Fader` displays and then to map the in-between colors accordingly. See the added comments in the code for more details. Add the templated helper class `LinearMap` to `lmms_math.h`. The class defines a linear function/map which is initialized using two points. With the `map` function it is then possible to evaluate arbitrary X-coordinates. --- include/lmms_math.h | 22 ++++++++++++++++++++ src/gui/widgets/Fader.cpp | 43 ++++++++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/include/lmms_math.h b/include/lmms_math.h index ea0a75581e8..a3a9712022f 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -351,6 +351,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/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 6f5987d422e..a561bcbbebf 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -388,23 +388,42 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) float const mappedPersistentPeakL(mapper(m_persistentPeak_L)); float const mappedPersistentPeakR(mapper(m_persistentPeak_R)); float const mappedUnity(mapper(1.f)); + + // 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. + float const mappedClipStarts(mapper(dbfsToAmp(6.f))); float const mappedWarnEnd(mappedUnity); float const mappedWarnStart(mapper(dbfsToAmp(-6.f))); float const mappedOkEnd(mapper(dbfsToAmp(-12.f))); - PaintHelper ph(mappedMinPeak, mappedMaxPeak); - // Prepare the gradient for the meters - QColor const & clippingColor = peakClip(); - QColor const & warnColor = peakWarn(); - QColor const & okColor = peakOk(); - - QLinearGradient linearGrad(0, margin, 0, leftMeterRect.y() + leftMeterRect.height()); - linearGrad.setColorAt(0, clippingColor); - linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedWarnEnd), warnColor); - linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedWarnStart), warnColor); - linearGrad.setColorAt(ph.mapMaxZeroAndMinOne(mappedOkEnd), okColor); - linearGrad.setColorAt(1, okColor); + // + // 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. + LinearMap const valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); + 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]. + LinearMap const mapBetweenClipAndOk(mappedClipStarts, 0.f, mappedOkEnd, 1.f); + + linearGrad.setColorAt(0, peakClip()); + linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnEnd), peakWarn()); + linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnStart), peakWarn()); + linearGrad.setColorAt(1, peakOk()); + + PaintHelper ph(mappedMinPeak, mappedMaxPeak); // Draw left levels QRect leftMeterMargins = leftMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); From e4b8b6b397027c522b0f39a6cf69a0714e40867a Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 20:12:41 +0100 Subject: [PATCH 15/36] Fix whitespace --- src/gui/widgets/Fader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index a561bcbbebf..d40592bb02e 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -62,7 +62,7 @@ namespace lmms::gui SimpleTextFloat * Fader::s_textFloat = nullptr; -Fader::Fader(FloatModel* model, const QString& name, QWidget* parent ) : +Fader::Fader(FloatModel* model, const QString& name, QWidget* parent) : QWidget(parent), FloatModelView(model, this), m_fPeakValue_L(0.0), From e48bbb8c7e34311a8fe6c38fd2ede19d1063c24e Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 20:20:52 +0100 Subject: [PATCH 16/36] Remove unused methods in PaintHelper Remove the now unused mapping methods from `PaintHelper`. Their functionality has been replaced with the usage of `LinearMap` in the code. --- src/gui/widgets/Fader.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index d40592bb02e..385bb2b95c0 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -307,26 +307,6 @@ class PaintHelper { } - float mapMaxZeroAndMinOne(float value) - { - return (m_max - value) * m_fullSpanReciprocal; - } - - float mapMaxZeroAndMinOneClamped(float value) - { - return std::clamp(mapMaxZeroAndMinOne(value), 0.f, 1.f); - } - - float mapMinZeroAndMaxOne(float value) - { - return 1. - mapMaxZeroAndMinOne(value); - } - - float mapMinZeroAndMaxOneClamped(float value) - { - return std::clamp(mapMinZeroAndMaxOne(value), 0.f, 1.f); - } - QRect getMeterRect(QRect const & meterRect, float peak) { float const span = peak - m_min; From e1fd07f4e62b40bd3d5f5661d328438f45c970cb Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 20:28:33 +0100 Subject: [PATCH 17/36] Fix some builds Include `cassert` for some builds that otherwise fail. --- include/lmms_math.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/lmms_math.h b/include/lmms_math.h index a3a9712022f..fcbc841ec80 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -30,6 +30,7 @@ #include "lmmsconfig.h" #include +#include #include namespace lmms From 99113c3b309cbd10900be8ab7daab1b86be74c6b Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 6 Jan 2024 21:48:01 +0100 Subject: [PATCH 18/36] Opaque unity marker with styling option Make the unity marker opaque by default and enable to style it with the style sheets. None of the two style sheets uses this option though. --- include/Fader.h | 5 +++++ src/gui/widgets/Fader.cpp | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index ff269a66405..e82a3c10444 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -71,6 +71,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView Q_PROPERTY(QColor peakWarn READ peakWarn WRITE setPeakWarn) Q_PROPERTY(bool levelsDisplayedInDBFS READ getLevelsDisplayedInDBFS WRITE setLevelsDisplayedInDBFS) Q_PROPERTY(bool renderUnityLine READ getRenderUnityLine WRITE setRenderUnityLine) + Q_PROPERTY(QColor unityMarker READ getUnityMarker WRITE setUnityMarker) Fader(FloatModel* model, const QString& name, QWidget* parent); Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob); @@ -97,6 +98,9 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView QColor const & peakWarn() const; void setPeakWarn(const QColor& c); + QColor const & getUnityMarker() const; + void setUnityMarker(const QColor& c); + inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; } inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; } @@ -162,6 +166,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView QColor m_peakOk; QColor m_peakClip; QColor m_peakWarn; + QColor m_unityMarker; bool m_renderUnityLine; } ; diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 385bb2b95c0..63400bfc7d0 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -78,6 +78,7 @@ Fader::Fader(FloatModel* model, const QString& name, QWidget* parent) : m_peakOk(10, 212, 92), m_peakClip(193, 32, 56), m_peakWarn(214, 236, 82), + m_unityMarker(127, 127, 127, 255), m_renderUnityLine(true) { if( s_textFloat == nullptr ) @@ -428,18 +429,16 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) painter.drawPath(path); // Draw left and right unity lines (0 dbFS, 1.0 amplitude) - QColor unityMarkerColor(127, 127, 127, 127); - if (getRenderUnityLine()) { auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); - painter.fillRect(unityRectL, unityMarkerColor); + painter.fillRect(unityRectL, getUnityMarker()); } if (getRenderUnityLine()) { auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); - painter.fillRect(unityRectR, unityMarkerColor); + painter.fillRect(unityRectR, getUnityMarker()); } @@ -476,5 +475,15 @@ void Fader::setPeakWarn(const QColor& c) m_peakWarn = c; } +QColor const & Fader::getUnityMarker() const +{ + return m_unityMarker; +} + +void Fader::setUnityMarker(const QColor& c) +{ + m_unityMarker = c; +} + } // namespace lmms::gui From a44b654f31aa727e88419f75c2c412b7d653e12d Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sun, 7 Jan 2024 10:18:45 +0100 Subject: [PATCH 19/36] Darker default color for the unity line --- src/gui/widgets/Fader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 63400bfc7d0..3ac71252db0 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -78,7 +78,7 @@ Fader::Fader(FloatModel* model, const QString& name, QWidget* parent) : m_peakOk(10, 212, 92), m_peakClip(193, 32, 56), m_peakWarn(214, 236, 82), - m_unityMarker(127, 127, 127, 255), + m_unityMarker(63, 63, 63, 255), m_renderUnityLine(true) { if( s_textFloat == nullptr ) From e67f5f8cb5884cbddca53aa1b6879a060a3bd517 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sun, 7 Jan 2024 10:20:29 +0100 Subject: [PATCH 20/36] Remove TODO --- src/gui/widgets/Fader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 3ac71252db0..9a1d328c7be 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -422,7 +422,8 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) auto const peakRectR = ph.getPersistentPeakRect(rightMeterMargins, mappedPersistentPeakR); painter.fillRect(peakRectR, linearGrad); - // TODO + // Draw a transparent white line around the levels outlines to make it look similar to the pixmaps + // that were used before the change to painting the levels in code. QPen pen(QColor(255, 255, 255, 18)); pen.setWidth(2); painter.setPen(pen); From bb39d5a79ee662a96eae1b32180b038a8708b271 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 8 Jan 2024 17:25:32 +0100 Subject: [PATCH 21/36] Move code Move the computation of most mapped values at the top right after the definition of the mapper so that it is readily available in all phases of the painting code. --- src/gui/widgets/Fader.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 9a1d328c7be..f2c23fdbc09 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -338,6 +338,14 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) mapper = [this](float value) { return value; }; } + float const mappedMinPeak(mapper(m_fMinPeak)); + float const mappedMaxPeak(mapper(m_fMaxPeak)); + float const mappedPeakL(mapper(m_fPeakValue_L)); + float const mappedPeakR(mapper(m_fPeakValue_R)); + float const mappedPersistentPeakL(mapper(m_persistentPeak_L)); + float const mappedPersistentPeakR(mapper(m_persistentPeak_R)); + float const mappedUnity(mapper(1.f)); + painter.save(); QRect const baseRect = rect(); @@ -362,14 +370,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // Now clip everything to the paths of the meters painter.setClipPath(path); - float const mappedMinPeak(mapper(m_fMinPeak)); - float const mappedMaxPeak(mapper(m_fMaxPeak)); - float const mappedPeakL(mapper(m_fPeakValue_L)); - float const mappedPeakR(mapper(m_fPeakValue_R)); - float const mappedPersistentPeakL(mapper(m_persistentPeak_L)); - float const mappedPersistentPeakR(mapper(m_persistentPeak_R)); - float const mappedUnity(mapper(1.f)); - // 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" From 5627384833a9ca0cd7159dd0a6ca44bb91054012 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 8 Jan 2024 17:29:36 +0100 Subject: [PATCH 22/36] Render unity lines in background Render the unity lines before rendering the levels so that they get overdrawn and do not stick out when they are crossed. --- src/gui/widgets/Fader.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index f2c23fdbc09..3a8fa7dcaa5 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -370,6 +370,21 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // Now clip everything to the paths of the meters painter.setClipPath(path); + PaintHelper ph(mappedMinPeak, mappedMaxPeak); + + // Draw left and right unity lines (0 dbFS, 1.0 amplitude) + if (getRenderUnityLine()) + { + auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); + painter.fillRect(unityRectL, getUnityMarker()); + } + + if (getRenderUnityLine()) + { + auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); + painter.fillRect(unityRectR, getUnityMarker()); + } + // 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" @@ -404,8 +419,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnStart), peakWarn()); linearGrad.setColorAt(1, peakOk()); - PaintHelper ph(mappedMinPeak, mappedMaxPeak); - // Draw left levels QRect leftMeterMargins = leftMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); painter.fillRect(ph.getMeterRect(leftMeterMargins, mappedPeakL), linearGrad); @@ -429,20 +442,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) painter.setPen(pen); painter.drawPath(path); - // Draw left and right unity lines (0 dbFS, 1.0 amplitude) - if (getRenderUnityLine()) - { - auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); - painter.fillRect(unityRectL, getUnityMarker()); - } - - if (getRenderUnityLine()) - { - auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); - painter.fillRect(unityRectR, getUnityMarker()); - } - - painter.restore(); } From b639dc546653184990f0b44bdc7af2173d435082 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 8 Jan 2024 17:30:47 +0100 Subject: [PATCH 23/36] Don't draw transparent white lines anymore Don't draw the transparent white lines anymore as they were mostly clipped anyway and only create "smudge". --- src/gui/widgets/Fader.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 3a8fa7dcaa5..583805d9e44 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -435,13 +435,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) auto const peakRectR = ph.getPersistentPeakRect(rightMeterMargins, mappedPersistentPeakR); painter.fillRect(peakRectR, linearGrad); - // Draw a transparent white line around the levels outlines to make it look similar to the pixmaps - // that were used before the change to painting the levels in code. - QPen pen(QColor(255, 255, 255, 18)); - pen.setWidth(2); - painter.setPen(pen); - painter.drawPath(path); - painter.restore(); } From 3bfc4e48273b10137c2ee5b0577a8c071683c192 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 8 Jan 2024 22:28:05 +0100 Subject: [PATCH 24/36] Full on clip color at unity Adjust the gradient so that the full on clip color shows starting at unity. There is only a very short transistion from the end of warning to clipping making it look like a solid color "standing" on top of a gradient. --- src/gui/widgets/Fader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 583805d9e44..fbfe0c3950f 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -390,8 +390,8 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // 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. - float const mappedClipStarts(mapper(dbfsToAmp(6.f))); - float const mappedWarnEnd(mappedUnity); + float const mappedClipStarts(mapper(dbfsToAmp(0.f))); + float const mappedWarnEnd(mapper(dbfsToAmp(-0.01))); float const mappedWarnStart(mapper(dbfsToAmp(-6.f))); float const mappedOkEnd(mapper(dbfsToAmp(-12.f))); From c2dd2091c3b0cfc9f2e24d52951a3a5c7bb4f078 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Mon, 8 Jan 2024 22:40:24 +0100 Subject: [PATCH 25/36] Fix discrepancy between levels and unity markers This commit removes the helper class `PaintHelper` and now uses two lambdas to compute the rectangles for the peak indicators and levels. It uses the linear map which maps the peak values (in dbFS or linear) to window coordinates of the widget. The change fixes a discrepancy in the following implementation for which the full on clip rectangle rendered slightly below the unity marker. --- src/gui/widgets/Fader.cpp | 72 +++++++++++++++------------------------ 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index fbfe0c3950f..5cc906ab8de 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -296,39 +296,6 @@ void Fader::paintEvent( QPaintEvent * ev) painter.drawPixmap((width() - m_knob.width()) / 2, knobPosY() - m_knob.height(), m_knob); } -class PaintHelper -{ -public: - PaintHelper(float min, float max) : - m_min(min), - m_max(max), - // 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. - m_fullSpanReciprocal(1. / (max - min)) - { - } - - QRect getMeterRect(QRect const & meterRect, float peak) - { - float const span = peak - m_min; - int mappedHeight = meterRect.height() * span * m_fullSpanReciprocal; - - return meterRect.adjusted(0, meterRect.height() - mappedHeight, 0, 0); - } - - QRect getPersistentPeakRect(QRect const & meterRect, float peak) - { - int persistentPeak_L = meterRect.height() * (1 - (peak - m_min) * m_fullSpanReciprocal); - - return QRect(meterRect.x(), persistentPeak_L, meterRect.width(), 1); - } - -private: - float const m_min; - float const m_max; - float const m_fullSpanReciprocal; -}; - void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) { std::function mapper = [this](float value) { return ampToDbfs(qMax(0.0001, value)); }; @@ -370,18 +337,36 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // Now clip everything to the paths of the meters painter.setClipPath(path); - PaintHelper ph(mappedMinPeak, mappedMaxPeak); + // 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 + LinearMap const valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); + + // 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. + auto const computePeakRect = [&valuesToWindowCoordinates](QRect const & rect, float peak) -> QRect + { + return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); + }; + + // 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. + auto const computeLevelRect = [&valuesToWindowCoordinates](QRect const & rect, float peak) -> QRect + { + QRect result(rect); + result.setTop(valuesToWindowCoordinates.map(peak)); + + return result; + }; // Draw left and right unity lines (0 dbFS, 1.0 amplitude) if (getRenderUnityLine()) { - auto const unityRectL = ph.getPersistentPeakRect(leftMeterRect, mappedUnity); + auto const unityRectL = computePeakRect(leftMeterRect, mappedUnity); painter.fillRect(unityRectL, getUnityMarker()); - } - if (getRenderUnityLine()) - { - auto const unityRectR = ph.getPersistentPeakRect(rightMeterRect, mappedUnity); + auto const unityRectR = computePeakRect(rightMeterRect, mappedUnity); painter.fillRect(unityRectR, getUnityMarker()); } @@ -404,7 +389,6 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // 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. - LinearMap const valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); float clipStartYCoord = valuesToWindowCoordinates.map(mappedClipStarts); float okEndYCoord = valuesToWindowCoordinates.map(mappedOkEnd); @@ -421,18 +405,18 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // Draw left levels QRect leftMeterMargins = leftMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); - painter.fillRect(ph.getMeterRect(leftMeterMargins, mappedPeakL), linearGrad); + painter.fillRect(computeLevelRect(leftMeterMargins, mappedPeakL), linearGrad); // Draw left peaks - auto const peakRectL = ph.getPersistentPeakRect(leftMeterMargins, mappedPersistentPeakL); + auto const peakRectL = computePeakRect(leftMeterMargins, mappedPersistentPeakL); painter.fillRect(peakRectL, linearGrad); // Draw right levels QRect rightMeterMargins = rightMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); - painter.fillRect(ph.getMeterRect(rightMeterMargins, mappedPeakR), linearGrad); + painter.fillRect(computeLevelRect(rightMeterMargins, mappedPeakR), linearGrad); // Draw right peaks - auto const peakRectR = ph.getPersistentPeakRect(rightMeterMargins, mappedPersistentPeakR); + auto const peakRectR = computePeakRect(rightMeterMargins, mappedPersistentPeakR); painter.fillRect(peakRectR, linearGrad); painter.restore(); From 449ab02ab5adb783583ad6f0e068e60721c084c3 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sat, 24 Feb 2024 00:17:02 +0100 Subject: [PATCH 26/36] Fix fader display for Equalizer shelves and peaks The peak values for the shelves and peaks of the Equalizer plugin are computed in `EqEffect::peakBand`. The previous implementation evaluated the bins of the corresponding frequency spectrum and determined the "loudest" one. The value of this bin was then converted to dbFS and mapped to the interval [0, inf[ where all values less or equal to -60 dbFS were mapped to 0 and a value of 40 dbFS was mapped to 1. So effectively everything was mapped somewhere into [0, 1] yet in a quite "distorted" way because a signal of 40 dbFS resulted in being displayed as unity in the fader. This commit directly returns the value of the maximum bin, i.e. it does not map first to dbFS and then linearize the result anymore. This should work because the `Fader` class assumes a "linear" input signal and if the value of the bin was previously mapped to dbFS it should have some "linear" character. Please note that this is still somewhat of a "proxy" value because ideally the summed amplitude of all relevant bins in the frequency range would be shown and not just the "loudest" one. ## Other changes Rename `peakBand` to `linearPeakBand` to make more clear that a linear value is returned. Handle a potential division by zero by checking the value of `fft->getEnergy()` before using it. Index into `fft->m_bands` so that no parallel incrementing of the pointer is needed. This also enables the removal of the local variable `b`. --- plugins/Eq/EqControls.h | 2 ++ plugins/Eq/EqEffect.cpp | 35 ++++++++++++++++++++--------------- plugins/Eq/EqEffect.h | 2 +- 3 files changed, 23 insertions(+), 16 deletions(-) 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/EqEffect.cpp b/plugins/Eq/EqEffect.cpp index 8a795414429..9361881938a 100644 --- a/plugins/Eq/EqEffect.cpp +++ b/plugins/Eq/EqEffect.cpp @@ -287,21 +287,26 @@ 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) { - float peak = -60; - float *b = fft->m_bands; - float h = 0; - for( int x = 0; x < MAX_BANDS; x++, b++ ) + auto const fftEnergy = fft->getEnergy(); + if (fftEnergy == 0) { - if( bandToFreq( x ,sr) >= minF && bandToFreq( x,sr ) <= maxF ) + // No energy -> no signal + return 0; + } + + float peakLinear = 0.; + + for (int i = 0; i < MAX_BANDS; ++i) + { + if (bandToFreq(i, sr) >= minF && bandToFreq(i, sr) <= maxF) { - h = 20 * ( log10( *b / fft->getEnergy() ) ); - peak = h > peak ? h : peak; + peakLinear = std::max(peakLinear, fft->m_bands[i] / fftEnergy); } } - return ( peak + 60 ) / 100; + return peakLinear; } @@ -310,41 +315,41 @@ float EqEffect::peakBand( float minF, float maxF, EqAnalyser *fft, int sr ) void EqEffect::setBandPeaks( EqAnalyser *fft, int samplerate ) { m_eqControls.m_lowShelfPeakR = m_eqControls.m_lowShelfPeakL = - peakBand( m_eqControls.m_lowShelfFreqModel.value() + 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() + linearPeakBand( 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 ); m_eqControls.m_para2PeakL = m_eqControls.m_para2PeakR = - peakBand( m_eqControls.m_para2FreqModel.value() + linearPeakBand( 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 ); m_eqControls.m_para3PeakL = m_eqControls.m_para3PeakR = - peakBand( m_eqControls.m_para3FreqModel.value() + linearPeakBand( 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 ); m_eqControls.m_para4PeakL = m_eqControls.m_para4PeakR = - peakBand( m_eqControls.m_para4FreqModel.value() + linearPeakBand( 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 ); m_eqControls.m_highShelfPeakL = m_eqControls.m_highShelfPeakR = - peakBand( m_eqControls.m_highShelfFreqModel.value(), + linearPeakBand( m_eqControls.m_highShelfFreqModel.value(), m_eqControls.m_highShelfFreqModel.value() * ( 1 + m_eqControls.m_highShelfResModel.value() * 0.5 ), fft, samplerate ); 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 ) { From b4bfc7174fa6f551e85fd7ecf2fd650157588c74 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Sun, 10 Mar 2024 19:47:10 +0100 Subject: [PATCH 27/36] Improve the rendering of the levels The levels rendering now more explicitly distinguished between the rendering of the level outline/border and the level meters. The level rectangles are "inset" with regards to the borders so that there is a margin between the level borders and the meter readings. This margin is now also applied to the top and bottom of the levels. Levels are now also rendered as rounded rectangles similar to the level borders. Only render the levels and peaks if their values are greater than the minimum level. Make the radius of the rounded rectangles more pronounced by increasing its value from 1 to 2. Decrease the margins so that the level readings become wider, i.e. so that they are rendered with more pixels. Add the lambda `computeLevelMarkerRect` so that the rendering of the level markers is more decoupled from the rendering of the peak markers. --- src/gui/widgets/Fader.cpp | 59 ++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 5cc906ab8de..eaa8480ce2a 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -319,19 +319,23 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) int const height = baseRect.height(); - int const margin = 2; + int const margin = 1; int const distanceBetweenMeters = 2; int const numberOfMeters = 2; int const meterWidth = (baseRect.width() - 2 * margin - distanceBetweenMeters * (numberOfMeters - 1)) / numberOfMeters; - QRect leftMeterRect(margin, margin, meterWidth, height - 2 * margin); - QRect rightMeterRect(baseRect.width() - margin - meterWidth, margin, meterWidth, height - 2 * margin); + QRect leftMeterOutlineRect(margin, margin, meterWidth, height - 2 * margin); + QRect rightMeterOutlineRect(baseRect.width() - margin - meterWidth, margin, meterWidth, height - 2 * margin); + + QMargins removedMargins(1, 1, 1, 1); + QRect leftMeterRect = leftMeterOutlineRect.marginsRemoved(removedMargins); + QRect rightMeterRect = rightMeterOutlineRect.marginsRemoved(removedMargins); QPainterPath path; - qreal radius = 1; - path.addRoundedRect(leftMeterRect, radius, radius); - path.addRoundedRect(rightMeterRect, radius, radius); + qreal radius = 2; + path.addRoundedRect(leftMeterOutlineRect, radius, radius); + path.addRoundedRect(rightMeterOutlineRect, radius, radius); painter.fillPath(path, Qt::black); // Now clip everything to the paths of the meters @@ -342,6 +346,13 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) // It is for example used to determine the height of peaks, markers and to define the gradient for the levels LinearMap const valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); + // 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. + auto const computeLevelMarkerRect = [&valuesToWindowCoordinates](QRect const & rect, float peak) -> QRect + { + return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); + }; + // 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. @@ -360,13 +371,13 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) return result; }; - // Draw left and right unity lines (0 dbFS, 1.0 amplitude) + // Draw left and right level markers for the unity lines (0 dbFS, 1.0 amplitude) if (getRenderUnityLine()) { - auto const unityRectL = computePeakRect(leftMeterRect, mappedUnity); + auto const unityRectL = computeLevelMarkerRect(leftMeterRect, mappedUnity); painter.fillRect(unityRectL, getUnityMarker()); - auto const unityRectR = computePeakRect(rightMeterRect, mappedUnity); + auto const unityRectR = computeLevelMarkerRect(rightMeterRect, mappedUnity); painter.fillRect(unityRectR, getUnityMarker()); } @@ -404,20 +415,34 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) linearGrad.setColorAt(1, peakOk()); // Draw left levels - QRect leftMeterMargins = leftMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); - painter.fillRect(computeLevelRect(leftMeterMargins, mappedPeakL), linearGrad); + if (mappedPeakL > mappedMinPeak) + { + QPainterPath leftMeterPath; + leftMeterPath.addRoundedRect(computeLevelRect(leftMeterRect, mappedPeakL), radius, radius); + painter.fillPath(leftMeterPath, linearGrad); + } // Draw left peaks - auto const peakRectL = computePeakRect(leftMeterMargins, mappedPersistentPeakL); - painter.fillRect(peakRectL, linearGrad); + if (mappedPersistentPeakL > mappedMinPeak) + { + auto const peakRectL = computePeakRect(leftMeterRect, mappedPersistentPeakL); + painter.fillRect(peakRectL, linearGrad); + } // Draw right levels - QRect rightMeterMargins = rightMeterRect.marginsRemoved(QMargins(1, 0, 1, 0)); - painter.fillRect(computeLevelRect(rightMeterMargins, mappedPeakR), linearGrad); + if (mappedPeakR > mappedMinPeak) + { + QPainterPath rightMeterPath; + rightMeterPath.addRoundedRect(computeLevelRect(rightMeterRect, mappedPeakR), radius, radius); + painter.fillPath(rightMeterPath, linearGrad); + } // Draw right peaks - auto const peakRectR = computePeakRect(rightMeterMargins, mappedPersistentPeakR); - painter.fillRect(peakRectR, linearGrad); + if (mappedPersistentPeakR > mappedMinPeak) + { + auto const peakRectR = computePeakRect(rightMeterRect, mappedPersistentPeakR); + painter.fillRect(peakRectR, linearGrad); + } painter.restore(); } From f2d63ecca1b512a31c4e123608410707cbd2ec83 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 11:52:36 +0200 Subject: [PATCH 28/36] Reduce code repetition Reduce code repetition in `EqEffect::setBandPeaks` by introducing a lambda. Adjust code formatting. --- plugins/Eq/EqEffect.cpp | 44 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/plugins/Eq/EqEffect.cpp b/plugins/Eq/EqEffect.cpp index 2cf986e643f..7e8d789af0f 100644 --- a/plugins/Eq/EqEffect.cpp +++ b/plugins/Eq/EqEffect.cpp @@ -311,45 +311,37 @@ float EqEffect::linearPeakBand(float minF, float maxF, EqAnalyser* fft, int sr) void EqEffect::setBandPeaks( EqAnalyser *fft, int samplerate ) { + auto computePeakBand = [this, fft, samplerate](FloatModel const & freqModel, FloatModel const & 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 = - linearPeakBand( m_eqControls.m_lowShelfFreqModel.value() - * ( 1 - m_eqControls.m_lowShelfResModel.value() * 0.5 ), + linearPeakBand(m_eqControls.m_lowShelfFreqModel.value() + * (1 - m_eqControls.m_lowShelfResModel.value() * 0.5), m_eqControls.m_lowShelfFreqModel.value(), - fft , samplerate ); + fft , samplerate); m_eqControls.m_para1PeakL = m_eqControls.m_para1PeakR = - linearPeakBand( 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 = - linearPeakBand( 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 = - linearPeakBand( 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 = - linearPeakBand( 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 = - linearPeakBand( m_eqControls.m_highShelfFreqModel.value(), + linearPeakBand(m_eqControls.m_highShelfFreqModel.value(), m_eqControls.m_highShelfFreqModel.value() - * ( 1 + m_eqControls.m_highShelfResModel.value() * 0.5 ), - fft, samplerate ); + * (1 + m_eqControls.m_highShelfResModel.value() * 0.5), + fft, samplerate); } extern "C" From 2bec339fb8ab19a6c9998ad1e9c9376171a87c51 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 12:13:02 +0200 Subject: [PATCH 29/36] Code review changes Code review changes in `Fader.cpp`. Mostly whitespace adjustments. Split up the calculation of the meter width to make it more understandable. This also reduces the number of parentheses. --- src/gui/widgets/Fader.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index eaa8480ce2a..314a99dc183 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -86,15 +86,15 @@ Fader::Fader(FloatModel* model, const QString& name, QWidget* parent) : s_textFloat = new SimpleTextFloat; } - setWindowTitle( name ); - setAttribute( Qt::WA_OpaquePaintEvent, false ); + 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 QSize minimumSize(23, 116); setMinimumSize(minimumSize); resize(minimumSize); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - setModel( model ); - setHintText( "Volume:","%"); + setModel(model); + setHintText("Volume:", "%"); m_conversionFactor = 100.0; } @@ -296,7 +296,7 @@ void Fader::paintEvent( QPaintEvent * ev) painter.drawPixmap((width() - m_knob.width()) / 2, knobPosY() - m_knob.height(), m_knob); } -void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) +void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) { std::function mapper = [this](float value) { return ampToDbfs(qMax(0.0001, value)); }; @@ -323,7 +323,12 @@ void Fader::paintLevels(QPaintEvent * ev, QPainter & painter, bool linear) int const distanceBetweenMeters = 2; int const numberOfMeters = 2; - int const meterWidth = (baseRect.width() - 2 * margin - distanceBetweenMeters * (numberOfMeters - 1)) / numberOfMeters; + + // Compute the width of a single meter by removing the margins and the space between meters + int const leftAndRightMargin = 2 * margin; + int const pixelsBetweenAllMeters = distanceBetweenMeters * (numberOfMeters - 1); + int const remainingPixelsForMeters = baseRect.width() - leftAndRightMargin - pixelsBetweenAllMeters; + int const meterWidth = remainingPixelsForMeters / numberOfMeters; QRect leftMeterOutlineRect(margin, margin, meterWidth, height - 2 * margin); QRect rightMeterOutlineRect(baseRect.width() - margin - meterWidth, margin, meterWidth, height - 2 * margin); From b3a1dd9e69dcadac1ecea467b78cb2c172ce55a3 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 12:19:04 +0200 Subject: [PATCH 30/36] Move const to the left of types --- src/gui/widgets/Fader.cpp | 58 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 314a99dc183..933b2b17de4 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -305,30 +305,30 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) mapper = [this](float value) { return value; }; } - float const mappedMinPeak(mapper(m_fMinPeak)); - float const mappedMaxPeak(mapper(m_fMaxPeak)); - float const mappedPeakL(mapper(m_fPeakValue_L)); - float const mappedPeakR(mapper(m_fPeakValue_R)); - float const mappedPersistentPeakL(mapper(m_persistentPeak_L)); - float const mappedPersistentPeakR(mapper(m_persistentPeak_R)); - float const mappedUnity(mapper(1.f)); + 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)); painter.save(); - QRect const baseRect = rect(); + const QRect baseRect = rect(); - int const height = baseRect.height(); + const int height = baseRect.height(); - int const margin = 1; - int const distanceBetweenMeters = 2; + const int margin = 1; + const int distanceBetweenMeters = 2; - int const numberOfMeters = 2; + const int numberOfMeters = 2; // Compute the width of a single meter by removing the margins and the space between meters - int const leftAndRightMargin = 2 * margin; - int const pixelsBetweenAllMeters = distanceBetweenMeters * (numberOfMeters - 1); - int const remainingPixelsForMeters = baseRect.width() - leftAndRightMargin - pixelsBetweenAllMeters; - int const meterWidth = remainingPixelsForMeters / numberOfMeters; + const int leftAndRightMargin = 2 * margin; + const int pixelsBetweenAllMeters = distanceBetweenMeters * (numberOfMeters - 1); + const int remainingPixelsForMeters = baseRect.width() - leftAndRightMargin - pixelsBetweenAllMeters; + const int meterWidth = remainingPixelsForMeters / numberOfMeters; QRect leftMeterOutlineRect(margin, margin, meterWidth, height - 2 * margin); QRect rightMeterOutlineRect(baseRect.width() - margin - meterWidth, margin, meterWidth, height - 2 * margin); @@ -349,11 +349,11 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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 - LinearMap const valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); + const LinearMap valuesToWindowCoordinates(mappedMaxPeak, leftMeterRect.y(), mappedMinPeak, leftMeterRect.y() + leftMeterRect.height()); // 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. - auto const computeLevelMarkerRect = [&valuesToWindowCoordinates](QRect const & rect, float peak) -> QRect + const auto computeLevelMarkerRect = [&valuesToWindowCoordinates](const QRect & rect, float peak) -> QRect { return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); }; @@ -361,14 +361,14 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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. - auto const computePeakRect = [&valuesToWindowCoordinates](QRect const & rect, float peak) -> QRect + const auto computePeakRect = [&valuesToWindowCoordinates](const QRect & rect, float peak) -> QRect { return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); }; // 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. - auto const computeLevelRect = [&valuesToWindowCoordinates](QRect const & rect, float peak) -> QRect + const auto computeLevelRect = [&valuesToWindowCoordinates](const QRect & rect, float peak) -> QRect { QRect result(rect); result.setTop(valuesToWindowCoordinates.map(peak)); @@ -379,10 +379,10 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // Draw left and right level markers for the unity lines (0 dbFS, 1.0 amplitude) if (getRenderUnityLine()) { - auto const unityRectL = computeLevelMarkerRect(leftMeterRect, mappedUnity); + const auto unityRectL = computeLevelMarkerRect(leftMeterRect, mappedUnity); painter.fillRect(unityRectL, getUnityMarker()); - auto const unityRectR = computeLevelMarkerRect(rightMeterRect, mappedUnity); + const auto unityRectR = computeLevelMarkerRect(rightMeterRect, mappedUnity); painter.fillRect(unityRectR, getUnityMarker()); } @@ -391,10 +391,10 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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. - float const mappedClipStarts(mapper(dbfsToAmp(0.f))); - float const mappedWarnEnd(mapper(dbfsToAmp(-0.01))); - float const mappedWarnStart(mapper(dbfsToAmp(-6.f))); - float const mappedOkEnd(mapper(dbfsToAmp(-12.f))); + 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 // @@ -412,7 +412,7 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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]. - LinearMap const mapBetweenClipAndOk(mappedClipStarts, 0.f, mappedOkEnd, 1.f); + const LinearMap mapBetweenClipAndOk(mappedClipStarts, 0.f, mappedOkEnd, 1.f); linearGrad.setColorAt(0, peakClip()); linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnEnd), peakWarn()); @@ -430,7 +430,7 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // Draw left peaks if (mappedPersistentPeakL > mappedMinPeak) { - auto const peakRectL = computePeakRect(leftMeterRect, mappedPersistentPeakL); + const auto peakRectL = computePeakRect(leftMeterRect, mappedPersistentPeakL); painter.fillRect(peakRectL, linearGrad); } @@ -445,7 +445,7 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // Draw right peaks if (mappedPersistentPeakR > mappedMinPeak) { - auto const peakRectR = computePeakRect(rightMeterRect, mappedPersistentPeakR); + const auto peakRectR = computePeakRect(rightMeterRect, mappedPersistentPeakR); painter.fillRect(peakRectR, linearGrad); } From 1bd81d884cfa4c888111a82cf376da19e03d50a1 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 12:48:58 +0200 Subject: [PATCH 31/36] Use MEMBER instead of READ/WRITE Use `MEMBER` instead of `READ`/`WRITE` for some properties that are not called explicitly from outside of the class. --- include/Fader.h | 25 ++++------------- src/gui/widgets/Fader.cpp | 56 +++++---------------------------------- 2 files changed, 12 insertions(+), 69 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index e82a3c10444..48a3516e73f 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -66,12 +66,12 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView { Q_OBJECT public: - Q_PROPERTY(QColor peakOk READ peakOk WRITE setPeakOk) - Q_PROPERTY(QColor peakClip READ peakClip WRITE setPeakClip) - Q_PROPERTY(QColor peakWarn READ peakWarn WRITE setPeakWarn) - Q_PROPERTY(bool levelsDisplayedInDBFS READ getLevelsDisplayedInDBFS WRITE setLevelsDisplayedInDBFS) + 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 READ getUnityMarker WRITE setUnityMarker) + 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); @@ -89,21 +89,6 @@ 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 & peakOk() const; - void setPeakOk(const QColor& c); - - QColor const & peakClip() const; - void setPeakClip(const QColor& c); - - QColor const & peakWarn() const; - void setPeakWarn(const QColor& c); - - QColor const & getUnityMarker() const; - void setUnityMarker(const QColor& c); - - inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; } - inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; } - inline bool getRenderUnityLine() const { return m_renderUnityLine; } inline void setRenderUnityLine(bool value = true) { m_renderUnityLine = value; } diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 933b2b17de4..9eaf359fcb8 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -289,8 +289,7 @@ void Fader::paintEvent( QPaintEvent * ev) QPainter painter(this); // Draw the levels with peaks - // TODO LMMS Compressor, EQ and Delay still use linear displays... - paintLevels(ev, painter, !getLevelsDisplayedInDBFS()); + paintLevels(ev, painter, !m_levelsDisplayedInDBFS); // Draw the knob painter.drawPixmap((width() - m_knob.width()) / 2, knobPosY() - m_knob.height(), m_knob); @@ -380,10 +379,10 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) if (getRenderUnityLine()) { const auto unityRectL = computeLevelMarkerRect(leftMeterRect, mappedUnity); - painter.fillRect(unityRectL, getUnityMarker()); + painter.fillRect(unityRectL, m_unityMarker); const auto unityRectR = computeLevelMarkerRect(rightMeterRect, mappedUnity); - painter.fillRect(unityRectR, getUnityMarker()); + painter.fillRect(unityRectR, m_unityMarker); } // These values define where the gradient changes values, i.e. the ranges @@ -414,10 +413,10 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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, peakClip()); - linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnEnd), peakWarn()); - linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnStart), peakWarn()); - linearGrad.setColorAt(1, peakOk()); + linearGrad.setColorAt(0, m_peakClip); + linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnEnd), m_peakWarn); + linearGrad.setColorAt(mapBetweenClipAndOk.map(mappedWarnStart), m_peakWarn); + linearGrad.setColorAt(1, m_peakOk); // Draw left levels if (mappedPeakL > mappedMinPeak) @@ -452,45 +451,4 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) painter.restore(); } -QColor const & Fader::peakOk() const -{ - return m_peakOk; -} - -QColor const & Fader::peakClip() const -{ - return m_peakClip; -} - -QColor const & Fader::peakWarn() const -{ - return m_peakWarn; -} - -void Fader::setPeakOk(const QColor& c) -{ - m_peakOk = c; -} - -void Fader::setPeakClip(const QColor& c) -{ - m_peakClip = c; -} - -void Fader::setPeakWarn(const QColor& c) -{ - m_peakWarn = c; -} - -QColor const & Fader::getUnityMarker() const -{ - return m_unityMarker; -} - -void Fader::setUnityMarker(const QColor& c) -{ - m_unityMarker = c; -} - - } // namespace lmms::gui From ad8a31daa379c57e0f27d3d1e4fe30561fd541b4 Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 21:16:40 +0200 Subject: [PATCH 32/36] Use default member initializers for Fader Use default member initializers for the members in `Fader` that have previously been initialized in the constructor list. Mark `ampToDbfs` and `dbfsToAmp` as `constexpr`. The function `dbfsToAmp` is used in the initialzation and this way nothing has to be computed at runtime. --- include/Fader.h | 31 ++++++++++++++++--------------- include/lmms_math.h | 8 ++++---- src/gui/widgets/Fader.cpp | 19 ++----------------- 3 files changed, 22 insertions(+), 36 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index 48a3516e73f..5ad9a8cc2c9 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 @@ -129,31 +130,31 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView // 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_knob; + QPixmap m_knob {embed::getIconPixmap("fader_knob")}; - bool m_levelsDisplayedInDBFS; + bool m_levelsDisplayedInDBFS {true}; - int m_moveStartPoint; - float m_startValue; + int m_moveStartPoint {-1}; + float m_startValue {0.}; static SimpleTextFloat * s_textFloat; - QColor m_peakOk; - QColor m_peakClip; - QColor m_peakWarn; - QColor m_unityMarker; + 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}; - bool m_renderUnityLine; + bool m_renderUnityLine {true}; } ; diff --git a/include/lmms_math.h b/include/lmms_math.h index 3eb26d57e34..e6fd55cbd96 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -270,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 ) +constexpr 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 ) +constexpr float dbfsToAmp(float dbfs) { - return std::pow(10.f, dbfs * 0.05f ); + return std::pow(10.f, dbfs * 0.05f); } diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 9eaf359fcb8..83924ae7a71 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -64,22 +64,7 @@ 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(dbfsToAmp(-42)), - m_fMaxPeak(dbfsToAmp(9)), - m_knob(embed::getIconPixmap("fader_knob")), - m_levelsDisplayedInDBFS(true), - m_moveStartPoint(-1), - m_startValue(0), - m_peakOk(10, 212, 92), - m_peakClip(193, 32, 56), - m_peakWarn(214, 236, 82), - m_unityMarker(63, 63, 63, 255), - m_renderUnityLine(true) + FloatModelView(model, this) { if( s_textFloat == nullptr ) { @@ -89,7 +74,7 @@ Fader::Fader(FloatModel* model, const QString& name, QWidget* parent) : 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 - QSize minimumSize(23, 116); + constexpr QSize minimumSize(23, 116); setMinimumSize(minimumSize); resize(minimumSize); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); From a65b8aaa778fcf28d3e580c8539222fcc40bff6f Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 21:27:35 +0200 Subject: [PATCH 33/36] Remove constexpr again Remove `constexpr` from `ampToDbfs` and ` dbfsToAmp` again because the MSVC compiler does not like it. Seems that for some reason `log10f` and `std::pow` are not `constexpr` there (at least in the version used on the build server). --- include/lmms_math.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/lmms_math.h b/include/lmms_math.h index e6fd55cbd96..3f58e3b75d4 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -270,7 +270,7 @@ 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. -constexpr float ampToDbfs(float amp) +static inline float ampToDbfs(float amp) { return log10f(amp) * 20.0f; } @@ -279,7 +279,7 @@ constexpr float ampToDbfs(float amp) //! @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 -constexpr float dbfsToAmp(float dbfs) +static inline float dbfsToAmp(float dbfs) { return std::pow(10.f, dbfs * 0.05f); } From dea942386fc478edea62be6868e62bc17fef489a Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 22:47:16 +0200 Subject: [PATCH 34/36] Comprehensive code formatting in Fader class --- include/Fader.h | 34 +++++++------- src/gui/widgets/Fader.cpp | 96 +++++++++++++++++++-------------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/include/Fader.h b/include/Fader.h index 5ad9a8cc2c9..a3158a8b436 100644 --- a/include/Fader.h +++ b/include/Fader.h @@ -78,10 +78,10 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView Fader(FloatModel* model, const QString& name, QWidget* parent, const QPixmap& knob); ~Fader() override = default; - 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; } @@ -93,28 +93,28 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView inline bool getRenderUnityLine() const { return m_renderUnityLine; } inline void setRenderUnityLine(bool value = true) { m_renderUnityLine = 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; + 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 paintLevels(QPaintEvent *ev, QPainter & painter, bool linear = false); + void paintLevels(QPaintEvent* ev, QPainter& painter, bool linear = false); int knobPosY() const { @@ -124,7 +124,7 @@ 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 ); + void setPeak(float fPeak, float& targetPeak, float& persistentPeak, QElapsedTimer& lastPeakTimer); void updateTextFloat(); @@ -147,7 +147,7 @@ class LMMS_EXPORT Fader : public QWidget, public FloatModelView int m_moveStartPoint {-1}; float m_startValue {0.}; - static SimpleTextFloat * s_textFloat; + static SimpleTextFloat* s_textFloat; QColor m_peakOk {10, 212, 92}; QColor m_peakClip {193, 32, 56}; diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 83924ae7a71..38e9e41f59c 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -60,13 +60,13 @@ namespace lmms::gui { -SimpleTextFloat * Fader::s_textFloat = nullptr; +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; } @@ -92,28 +92,28 @@ Fader::Fader(FloatModel* model, const QString& name, QWidget* parent, const QPix } -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(); } @@ -122,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()) @@ -151,39 +151,39 @@ void Fader::mousePressEvent( QMouseEvent* mouseEvent ) } else { - AutomatableModelView::mousePressEvent( mouseEvent ); + AutomatableModelView::mousePressEvent(mouseEvent); } } -void Fader::mouseDoubleClickEvent( QMouseEvent* mouseEvent ) +void Fader::mouseDoubleClickEvent(QMouseEvent* mouseEvent) { bool ok; float newValue; // TODO: dbV handling - newValue = QInputDialog::getDouble( this, tr( "Set value" ), - tr( "Please enter a new value between %1 and %2:" ). - arg( model()->minValue() * m_conversionFactor ). - arg( model()->maxValue() * m_conversionFactor ), + newValue = QInputDialog::getDouble(this, tr("Set value"), + tr("Please enter a new value between %1 and %2:"). + arg(model()->minValue() * m_conversionFactor). + arg(model()->maxValue() * m_conversionFactor), model()->getRoundedValue() * m_conversionFactor, model()->minValue() * m_conversionFactor, - model()->maxValue() * m_conversionFactor, model()->getDigitCount(), &ok ) / m_conversionFactor; + model()->maxValue() * m_conversionFactor, model()->getDigitCount(), &ok) / m_conversionFactor; - if( ok ) + if (ok) { - model()->setValue( newValue ); + model()->setValue(newValue); } } -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(); } @@ -193,20 +193,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); } @@ -214,7 +214,7 @@ 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) { fPeak = std::clamp(fPeak, m_fMinPeak, m_fMaxPeak); @@ -231,23 +231,23 @@ void Fader::setPeak( float fPeak, float &targetPeak, float &persistentPeak, QEla 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); } @@ -255,21 +255,21 @@ 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)); } -void Fader::paintEvent( QPaintEvent * ev) +void Fader::paintEvent(QPaintEvent* ev) { QPainter painter(this); @@ -337,7 +337,7 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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 + const auto computeLevelMarkerRect = [&valuesToWindowCoordinates](const QRect& rect, float peak) -> QRect { return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); }; @@ -345,14 +345,14 @@ void Fader::paintLevels(QPaintEvent* ev, QPainter& painter, bool linear) // 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 + const auto computePeakRect = [&valuesToWindowCoordinates](const QRect& rect, float peak) -> QRect { return QRect(rect.x(), valuesToWindowCoordinates.map(peak), rect.width(), 1); }; // 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 + const auto computeLevelRect = [&valuesToWindowCoordinates](const QRect& rect, float peak) -> QRect { QRect result(rect); result.setTop(valuesToWindowCoordinates.map(peak)); From bb212eebbd3fbd18c9c1e21dbee31d5c8b4384dd Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 22:50:54 +0200 Subject: [PATCH 35/36] Improved capture and formatting --- plugins/Eq/EqEffect.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/plugins/Eq/EqEffect.cpp b/plugins/Eq/EqEffect.cpp index 7e8d789af0f..d8d2b2b29e2 100644 --- a/plugins/Eq/EqEffect.cpp +++ b/plugins/Eq/EqEffect.cpp @@ -311,7 +311,7 @@ float EqEffect::linearPeakBand(float minF, float maxF, EqAnalyser* fft, int sr) void EqEffect::setBandPeaks( EqAnalyser *fft, int samplerate ) { - auto computePeakBand = [this, fft, samplerate](FloatModel const & freqModel, FloatModel const & bwModel) + auto computePeakBand = [&](const FloatModel& freqModel, const FloatModel& bwModel) { float const freq = freqModel.value(); float const bw = bwModel.value(); @@ -320,10 +320,8 @@ void EqEffect::setBandPeaks( EqAnalyser *fft, int samplerate ) }; m_eqControls.m_lowShelfPeakR = m_eqControls.m_lowShelfPeakL = - linearPeakBand(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 = computePeakBand(m_eqControls.m_para1FreqModel, m_eqControls.m_para1BwModel); @@ -338,10 +336,9 @@ void EqEffect::setBandPeaks( EqAnalyser *fft, int samplerate ) computePeakBand(m_eqControls.m_para4FreqModel, m_eqControls.m_para4BwModel); m_eqControls.m_highShelfPeakL = m_eqControls.m_highShelfPeakR = - linearPeakBand(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" From b0e4586ceade83834d148bb684a22df85f47de7f Mon Sep 17 00:00:00 2001 From: Michael Gregorius Date: Wed, 3 Apr 2024 23:04:50 +0200 Subject: [PATCH 36/36] Make code clearer Make code clearer in `Fader::FadermouseDoubleClickEvent`. Only divide if the dialog was accepted with OK. --- src/gui/widgets/Fader.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 4c75cf87b9b..370cc750291 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -160,17 +160,16 @@ void Fader::mousePressEvent(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) { - model()->setValue(newValue); + model()->setValue(enteredValue / m_conversionFactor); } }