From 496d63cf116b3b896b23f7c7946e67f481c0c712 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 15 Feb 2015 17:18:06 +0100 Subject: [PATCH] refs #387, preparation for level meter * not yet connected with audio --- .../components/audiovolumecomponent.ui | 27 +++-- src/blackgui/levelmeter.cpp | 111 ++++++++++++++++++ src/blackgui/levelmeter.h | 85 ++++++++++++++ 3 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 src/blackgui/levelmeter.cpp create mode 100644 src/blackgui/levelmeter.h diff --git a/src/blackgui/components/audiovolumecomponent.ui b/src/blackgui/components/audiovolumecomponent.ui index 5df13a97e..2705ba128 100644 --- a/src/blackgui/components/audiovolumecomponent.ui +++ b/src/blackgui/components/audiovolumecomponent.ui @@ -162,7 +162,7 @@ - + 0 0 @@ -179,17 +179,14 @@ - - - Qt::Horizontal + + + + 0 + 0 + - - - 40 - 20 - - - + @@ -218,6 +215,14 @@ + + + BlackGui::CLevelMeter + QWidget +
blackgui/levelmeter.h
+ 1 +
+
diff --git a/src/blackgui/levelmeter.cpp b/src/blackgui/levelmeter.cpp new file mode 100644 index 000000000..85c2ed36a --- /dev/null +++ b/src/blackgui/levelmeter.cpp @@ -0,0 +1,111 @@ +/* Copyright (C) 2013 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + * + * Class based on qt example: Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + */ + +#include "levelmeter.h" + +#include + +#include +#include +#include + + +namespace BlackGui +{ + CLevelMeter::CLevelMeter(QWidget *parent) + : QWidget(parent) + , m_peakDecayRate(PeakDecayRate) + , m_redrawTimer(new QTimer(this)) + , m_rmsColor(Qt::red) + , m_peakColor(255, 200, 200, 255) + { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + setMinimumWidth(30); + + connect(m_redrawTimer, &QTimer::timeout, this, &CLevelMeter::ps_redrawTimerExpired); + m_redrawTimer->start(RedrawInterval); + } + + CLevelMeter::~CLevelMeter() + { } + + void CLevelMeter::reset() + { + m_rmsLevel = 0.0; + m_peakLevel = 0.0; + update(); + } + + void CLevelMeter::levelChanged(double rmsLevel, double peakLevel, int numSamples) + { + // Smooth the RMS signal + const double smooth = pow(double(0.9), static_cast(numSamples) / 256); // TODO: remove this magic number + m_rmsLevel = (m_rmsLevel * smooth) + (rmsLevel * (1.0 - smooth)); + + if (peakLevel > m_decayedPeakLevel) + { + m_peakLevel = peakLevel; + m_decayedPeakLevel = peakLevel; + m_peakLevelChanged.start(); + } + + if (peakLevel > m_peakHoldLevel) + { + m_peakHoldLevel = peakLevel; + m_peakHoldLevelChanged.start(); + } + + update(); + } + + void CLevelMeter::ps_redrawTimerExpired() + { + // Decay the peak signal + const int elapsedMs = m_peakLevelChanged.elapsed(); + const double decayAmount = m_peakDecayRate * elapsedMs; + if (decayAmount < m_peakLevel) + { + m_decayedPeakLevel = m_peakLevel - decayAmount; + } + else + { + 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) + { + Q_UNUSED(event) + + QPainter painter(this); + painter.fillRect(rect(), Qt::black); + + QRect bar = rect(); + + bar.setTop(rect().top() + (1.0 - m_peakHoldLevel) * rect().height()); + bar.setBottom(bar.top() + 5); + painter.fillRect(bar, m_rmsColor); + bar.setBottom(rect().bottom()); + + bar.setTop(rect().top() + (1.0 - m_decayedPeakLevel) * rect().height()); + painter.fillRect(bar, m_peakColor); + + bar.setTop(rect().top() + (1.0 - m_rmsLevel) * rect().height()); + painter.fillRect(bar, m_rmsColor); + } + +} // namespace diff --git a/src/blackgui/levelmeter.h b/src/blackgui/levelmeter.h new file mode 100644 index 000000000..499cfc98a --- /dev/null +++ b/src/blackgui/levelmeter.h @@ -0,0 +1,85 @@ +/* Copyright (C) 2013 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + * + * Class based on qt example: Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + */ + +//! \file + +#ifndef BLACKGUI_LEVELMETER_H +#define BLACKGUI_LEVELMETER_H + +#include +#include + +namespace BlackGui +{ + + /** + * Widget which displays a vertical audio level meter, indicating the + * RMS and peak levels of the window of audio samples most recently analyzed + * by the Engine. + */ + class CLevelMeter : public QWidget + { + Q_OBJECT + public: + //! Constructor + CLevelMeter(QWidget *parent = 0); + + //! Destructor + ~CLevelMeter(); + + //! \copydoc QWidget::paintEvent + void paintEvent(QPaintEvent *event) override; + + public slots: + + //! Clean up + void reset(); + + //! Values + void levelChanged(double rmsLevel, double peakLevel, int numSamples); + + private slots: + void ps_redrawTimerExpired(); + + private: + const int RedrawInterval = 100; // ms + const double PeakDecayRate = 0.001; + const int PeakHoldLevelDuration = 2000; // ms + + //! Height of RMS level bar, range 0.0 - 1.0. + double m_rmsLevel = 0.0; + + //! Most recent peak level, range 0.0 - 1.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. + QTime m_peakLevelChanged; + + //! Rate at which peak level bar decays. Expressed in level units / millisecond. + double m_peakDecayRate; + + //! 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; + QColor m_rmsColor; + QColor m_peakColor; + }; +} + +#endif // guard