Ref T731, adjusted CLevelMeter for "our needs"

* low/high color
* peak level
This commit is contained in:
Klaus Basan
2019-09-27 02:20:42 +02:00
committed by Mat Sutcliffe
parent 80a96d37fc
commit b5ad603e55
2 changed files with 68 additions and 84 deletions

View File

@@ -21,16 +21,16 @@
namespace BlackGui namespace BlackGui
{ {
CLevelMeter::CLevelMeter(QWidget *parent) CLevelMeter::CLevelMeter(QWidget *parent)
: QWidget(parent) : QFrame(parent),
, m_peakDecayRate(PeakDecayRate) m_redrawTimer(new QTimer(this)),
, m_redrawTimer(new QTimer(this)) m_lowColor(Qt::gray),
, m_rmsColor(Qt::red) m_highColor(Qt::green),
, m_peakColor(255, 200, 200, 255) m_peakColor(255, 200, 200, 255)
{ {
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
setMinimumWidth(30); this->setMinimumWidth(30);
connect(m_redrawTimer, &QTimer::timeout, this, &CLevelMeter::ps_redrawTimerExpired); connect(m_redrawTimer, &QTimer::timeout, this, &CLevelMeter::redrawTimerExpired);
m_redrawTimer->start(RedrawInterval); m_redrawTimer->start(RedrawInterval);
m_redrawTimer->setObjectName("CLevelMeter"); m_redrawTimer->setObjectName("CLevelMeter");
} }
@@ -40,52 +40,33 @@ namespace BlackGui
void CLevelMeter::reset() void CLevelMeter::reset()
{ {
m_rmsLevel = 0.0; m_level = 0.0;
m_peakLevel = 0.0; m_peakLevel = 0.0;
update(); this->update();
} }
void CLevelMeter::levelChanged(double rmsLevel, double peakLevel, int numSamples) void CLevelMeter::levelChanged(double level)
{ {
// Smooth the RMS signal m_level = level;
const double smooth = pow(double(0.9), static_cast<double>(numSamples) / 256); // TODO: remove this magic number if (level > m_peakLevel)
m_rmsLevel = (m_rmsLevel * smooth) + (rmsLevel * (1.0 - smooth));
if (peakLevel > m_decayedPeakLevel)
{ {
m_peakLevel = peakLevel; m_peakLevel = level;
m_decayedPeakLevel = peakLevel;
m_peakLevelChanged.start(); m_peakLevelChanged.start();
} }
if (peakLevel > m_peakHoldLevel)
{
m_peakHoldLevel = peakLevel;
m_peakHoldLevelChanged.start();
}
update();
} }
void CLevelMeter::ps_redrawTimerExpired() void CLevelMeter::redrawTimerExpired()
{ {
// Decay the peak signal // decay
const int elapsedMs = m_peakLevelChanged.elapsed(); if (m_peakLevelChanged.elapsed() > PeakHoldLevelDuration)
const double decayAmount = m_peakDecayRate * elapsedMs;
if (decayAmount < m_peakLevel)
{ {
m_decayedPeakLevel = m_peakLevel - decayAmount; m_peakLevel -= DecayValue;
if (m_peakLevel < m_level || m_peakLevel < 0)
{
m_peakLevel = 0.0;
}
} }
else this->update();
{
m_decayedPeakLevel = 0.0;
}
// Check whether to clear the peak hold level
if (m_peakHoldLevelChanged.elapsed() > PeakHoldLevelDuration)
m_peakHoldLevel = 0.0;
update();
} }
void CLevelMeter::paintEvent(QPaintEvent *event) void CLevelMeter::paintEvent(QPaintEvent *event)
@@ -93,20 +74,23 @@ namespace BlackGui
Q_UNUSED(event) Q_UNUSED(event)
QPainter painter(this); QPainter painter(this);
painter.fillRect(rect(), Qt::black); QRect bar = this->contentsRect();
painter.fillRect(bar, Qt::transparent);
const int w = bar.width();
const int left = rect().left();
const int level = qRound(m_level * w);
QRect bar = rect(); bar.setLeft(left);
bar.setRight(level);
painter.fillRect(bar, m_peakLevel >= High ? m_highColor : m_lowColor);
bar.setTop(rect().top() + (1.0 - m_peakHoldLevel) * rect().height()); if (m_peakLevel > m_level)
bar.setBottom(bar.top() + 5); {
painter.fillRect(bar, m_rmsColor); const int peak = qRound(m_peakLevel * w);
bar.setBottom(rect().bottom()); bar.setLeft(level);
bar.setRight(peak);
bar.setTop(rect().top() + (1.0 - m_decayedPeakLevel) * rect().height()); painter.fillRect(bar, m_peakColor);
painter.fillRect(bar, m_peakColor); }
bar.setTop(rect().top() + (1.0 - m_rmsLevel) * rect().height());
painter.fillRect(bar, m_rmsColor);
} }
} // namespace } // namespace

View File

@@ -18,70 +18,70 @@
#include <QColor> #include <QColor>
#include <QObject> #include <QObject>
#include <QTime> #include <QTime>
#include <QWidget> #include <QFrame>
class QPaintEvent; class QPaintEvent;
class QTimer; class QTimer;
namespace BlackGui namespace BlackGui
{ {
//! Widget which displays a vertical audio level meter, indicating the //! Widget which displays a audio level meter, indicating the
//! RMS and peak levels of the window of audio samples most recently analyzed //! level and peak levels of the window of audio samples most recently analyzed
//! by the Engine. class BLACKGUI_EXPORT CLevelMeter : public QFrame
class BLACKGUI_EXPORT CLevelMeter : public QWidget
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor lowColor READ getLowColor WRITE setLowColor)
Q_PROPERTY(QColor highColor READ getHighColor WRITE setHighColor)
Q_PROPERTY(QColor peakColor READ getPeakColor WRITE setPeakColor)
public: public:
//! Constructor //! Constructor
CLevelMeter(QWidget *parent = nullptr); CLevelMeter(QWidget *parent = nullptr);
//! Destructor //! Destructor
virtual ~CLevelMeter(); virtual ~CLevelMeter() override;
//! \copydoc QWidget::paintEvent //! \copydoc QWidget::paintEvent
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
public slots:
//! Clean up //! Clean up
void reset(); void reset();
//! Values //! Values
void levelChanged(double rmsLevel, double peakLevel, int numSamples); void levelChanged(double level);
private slots: //! Color properties @{
void ps_redrawTimerExpired(); const QColor &getLowColor() const { return m_lowColor; }
const QColor &getHighColor() const { return m_highColor; }
const QColor &getPeakColor() const { return m_peakColor; }
void setLowColor(const QColor &color) { m_lowColor = color; }
void setHighColor(const QColor &color) { m_highColor = color; }
void setPeakColor(const QColor &color) { m_peakColor = color; }
//! @}
private: private:
const int RedrawInterval = 100; // ms //! Timer expired
const double PeakDecayRate = 0.001; void redrawTimerExpired();
const int PeakHoldLevelDuration = 2000; // ms
//! Height of RMS level bar, range 0.0 - 1.0. const int RedrawInterval = 100; // ms
double m_rmsLevel = 0.0; const int PeakHoldLevelDuration = 1000; // ms
//! Range 0.0 - 1.0.
double m_level = 0.0;
//! Most recent peak level, range 0.0 - 1.0. //! Most recent peak level, range 0.0 - 1.0.
double m_peakLevel = 0.0; double m_peakLevel = 0.0;
//! Height of peak level bar.
//! This is calculated by decaying m_peakLevel depending on the elapsed time since m_peakLevelChanged, and the value of m_decayRate.
double m_decayedPeakLevel = 0.0;
//! Time at which m_peakLevel was last changed. //! Time at which m_peakLevel was last changed.
QTime m_peakLevelChanged; QTime m_peakLevelChanged;
//! Rate at which peak level bar decays. Expressed in level units / millisecond. static constexpr double High = 0.60;
double m_peakDecayRate; static constexpr double DecayValue = 0.10;
//! High watermark of peak level. Range 0.0 - 1.0.
double m_peakHoldLevel = 0.0;
//! Time at which m_peakHoldLevel was last changed.
QTime m_peakHoldLevelChanged;
QTimer *m_redrawTimer = nullptr; QTimer *m_redrawTimer = nullptr;
QColor m_rmsColor; QColor m_lowColor;
QColor m_highColor;
QColor m_peakColor; QColor m_peakColor;
}; };
} } // ns
#endif // guard #endif // guard