Skip to content

Commit

Permalink
Render the mixer levels in a dB FS scale (#2672)
Browse files Browse the repository at this point in the history
* Render the mixer levels in a dB FS scale

Adds the option to render the mixer levels in dB FS. By default this
option is disabled so that classes which inherit from Fader are not
affected by this change. However, in the code of the FxMixerView this
feature is enabled so that the mixer shows the levels in dB FS.

The ability to render in dB FS is exported as a property so that it can
also be set in a style sheet (not used as of now). The new property is
called "levelsDisplayedInDBFS".

There are now setters and getters for the min and max level.

Showing the levels in dB FS (which is a logarithmic scale) gives a less
"fidgety" impression when the levels are moving.

* Introduction of an init method in Fader

An init method was added to unify the initialization of the two Fader
constructors.
  • Loading branch information
michaelgregorius authored and Umcaruje committed Jul 10, 2016
1 parent 04ee091 commit 52ec387
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 26 deletions.
34 changes: 29 additions & 5 deletions include/Fader.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,40 @@ class EXPORT Fader : public QWidget, public FloatModelView
public:
Q_PROPERTY( QColor peakGreen READ peakGreen WRITE setPeakGreen )
Q_PROPERTY( QColor peakRed READ peakRed WRITE setPeakRed )
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 );
virtual ~Fader();

void init(FloatModel * model, QString const & name);

void setPeak_L( float fPeak );
float getPeak_L() { return m_fPeakValue_L; }

void setPeak_R( float fPeak );
float getPeak_R() { return m_fPeakValue_R; }

QColor peakGreen() const;
QColor peakRed() const;
inline float getMinPeak() const { return m_fMinPeak; }
inline void setMinPeak(float minPeak) { m_fMinPeak = minPeak; }

inline float getMaxPeak() const { return m_fMaxPeak; }
inline void setMaxPeak(float maxPeak) { m_fMaxPeak = maxPeak; }

QColor const & peakGreen() const;
void setPeakGreen( const QColor & c );

QColor const & peakRed() const;
void setPeakRed( const QColor & c );

inline bool getLevelsDisplayedInDBFS() const { return m_levelsDisplayedInDBFS; }
inline void setLevelsDisplayedInDBFS(bool value = true) { m_levelsDisplayedInDBFS = value; }

void setDisplayConversion( bool b )
{
m_displayConversion = b;
}

inline void setHintText( const QString & _txt_before,
const QString & _txt_after )
{
Expand All @@ -98,6 +113,11 @@ class EXPORT Fader : public QWidget, public FloatModelView
virtual void wheelEvent( QWheelEvent *ev );
virtual void paintEvent( QPaintEvent *ev );

inline bool clips(float const & value) const { return value > 1.0f; }

void paintDBFSLevels(QPaintEvent *ev, QPainter & painter);
void paintLinearLevels(QPaintEvent *ev, QPainter & painter);

int knobPosY() const
{
float fRange = model()->maxValue() - model()->minValue();
Expand All @@ -109,12 +129,16 @@ class EXPORT Fader : public QWidget, public FloatModelView
void setPeak( float fPeak, float &targetPeak, float &persistentPeak, QTime &lastPeakTime );
int calculateDisplayPeak( float fPeak );

void updateTextFloat();

// Private members
private:
float m_fPeakValue_L;
float m_fPeakValue_R;
float m_persistentPeak_L;
float m_persistentPeak_R;
const float m_fMinPeak;
const float m_fMaxPeak;
float m_fMinPeak;
float m_fMaxPeak;

QTime m_lastPeakTime_L;
QTime m_lastPeakTime_R;
Expand All @@ -128,12 +152,12 @@ class EXPORT Fader : public QWidget, public FloatModelView
QPixmap * m_knob;

bool m_displayConversion;
bool m_levelsDisplayedInDBFS;

int m_moveStartPoint;
float m_startValue;

static TextFloat * s_textFloat;
void updateTextFloat();

QColor m_peakGreen;
QColor m_peakRed;
Expand Down
6 changes: 6 additions & 0 deletions src/gui/FxMixerView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "InstrumentTrack.h"
#include "Song.h"
#include "BBTrackContainer.h"
#include "lmms_math.h"

FxMixerView::FxMixerView() :
QWidget(),
Expand Down Expand Up @@ -280,6 +281,11 @@ FxMixerView::FxChannelView::FxChannelView(QWidget * _parent, FxMixerView * _mv,

m_fader = new Fader( &fxChannel->m_volumeModel,
tr( "FX Fader %1" ).arg( channelIndex ), m_fxLine );
m_fader->setLevelsDisplayedInDBFS();
// TODO dbvToAmp is really dBFSToAmp. Rename in later commit.
m_fader->setMinPeak(dbvToAmp(-40));
m_fader->setMaxPeak(dbvToAmp(12));

m_fader->move( 16-m_fader->width()/2,
m_fxLine->height()-
m_fader->height()-5 );
Expand Down
103 changes: 82 additions & 21 deletions src/gui/widgets/Fader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "ConfigManager.h"
#include "TextFloat.h"
#include "MainWindow.h"
#include "lmms_math.h"


TextFloat * Fader::s_textFloat = NULL;
Expand All @@ -74,6 +75,7 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) :
m_fMinPeak( 0.01f ),
m_fMaxPeak( 1.1 ),
m_displayConversion( true ),
m_levelsDisplayedInDBFS(false),
m_moveStartPoint( -1 ),
m_startValue( 0 ),
m_peakGreen( 0, 0, 0 ),
Expand All @@ -100,13 +102,7 @@ Fader::Fader( FloatModel * _model, const QString & _name, QWidget * _parent ) :
m_leds = s_leds;
m_knob = s_knob;

setWindowTitle( _name );
setAttribute( Qt::WA_OpaquePaintEvent, false );
setMinimumSize( 23, 116 );
setMaximumSize( 23, 116);
resize( 23, 116 );
setModel( _model );
setHintText( "Volume:","%");
init(_model, _name);
}


Expand All @@ -120,6 +116,7 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma
m_fMinPeak( 0.01f ),
m_fMaxPeak( 1.1 ),
m_displayConversion( false ),
m_levelsDisplayedInDBFS(false),
m_moveStartPoint( -1 ),
m_startValue( 0 ),
m_peakGreen( 0, 0, 0 ),
Expand All @@ -134,13 +131,7 @@ Fader::Fader( FloatModel * model, const QString & name, QWidget * parent, QPixma
m_leds = leds;
m_knob = knob;

setWindowTitle( name );
setAttribute( Qt::WA_OpaquePaintEvent, false );
setMinimumSize( m_back->width(), m_back->height() );
setMaximumSize( m_back->width(), m_back->height() );
resize( m_back->width(), m_back->height() );
setModel( model );
setHintText( "Volume:","%");
init(model, name);
}


Expand All @@ -149,6 +140,18 @@ Fader::~Fader()
}


void Fader::init(FloatModel * model, QString const & name)
{
setWindowTitle( name );
setAttribute( Qt::WA_OpaquePaintEvent, false );
QSize backgroundSize = m_back->size();
setMinimumSize( backgroundSize );
setMaximumSize( backgroundSize );
resize( backgroundSize );
setModel( model );
setHintText( "Volume:","%");
}



void Fader::contextMenuEvent( QContextMenuEvent * _ev )
Expand Down Expand Up @@ -337,20 +340,81 @@ inline int Fader::calculateDisplayPeak( float fPeak )
return qMin( peak, m_back->height() );
}


void Fader::paintEvent( QPaintEvent * ev)
{
QPainter painter(this);

// background
// 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);
}

// Draw the knob
painter.drawPixmap( 0, knobPosY() - m_knob->height(), *m_knob );
}

void Fader::paintDBFSLevels(QPaintEvent * ev, QPainter & painter)
{
int height = m_back->height();
int width = m_back->width() / 2;
int center = m_back->width() - width;

float const maxDB(ampToDbv(m_fMaxPeak));
float const minDB(ampToDbv(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 = ampToDbv(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 = ampToDbv(m_persistentPeak_L);
int persistentPeak_L = height * (1 - (persistentLeftPeakDBFS - minDB) * fullSpanReciprocal);
if( persistentLeftPeakDBFS > minDB )
{
QColor const & peakColor = clips(m_persistentPeak_L) ? peakRed() : peakGreen();
painter.fillRect( QRect( 2, persistentPeak_L, 7, 1 ), peakColor );
}


// Draw right levels
float const rightSpan = ampToDbv(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 = ampToDbv(m_persistentPeak_R);
int persistentPeak_R = height * (1 - (persistentRightPeakDBFS - minDB) * fullSpanReciprocal);
if( persistentRightPeakDBFS > minDB )
{
QColor const & peakColor = clips(m_persistentPeak_R) ? peakRed() : peakGreen();
painter.fillRect( QRect( 14, persistentPeak_R, 7, 1 ), peakColor );
}
}

void Fader::paintLinearLevels(QPaintEvent * ev, QPainter & painter)
{
// peak leds
//float fRange = abs( m_fMaxPeak ) + abs( m_fMinPeak );

int height = m_back->height();
int width = m_back->width() / 2;
int center = m_back->width() - width;

int peak_L = calculateDisplayPeak( m_fPeakValue_L - m_fMinPeak );
int persistentPeak_L = qMax<int>( 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 ) );
Expand All @@ -372,18 +436,15 @@ void Fader::paintEvent( QPaintEvent * ev)
? peakGreen()
: peakRed() );
}

// knob
painter.drawPixmap( 0, knobPosY() - m_knob->height(), *m_knob );
}


QColor Fader::peakGreen() const
QColor const & Fader::peakGreen() const
{
return m_peakGreen;
}

QColor Fader::peakRed() const
QColor const & Fader::peakRed() const
{
return m_peakRed;
}
Expand Down

0 comments on commit 52ec387

Please sign in to comment.