Qt Reference Documentation

# levelmeter.cpp Example File

demos/spectrum/app/levelmeter.cpp

     /****************************************************************************
     **
     ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
     ** All rights reserved.
     ** Contact: Nokia Corporation (qt-info@nokia.com)
     **
     ** This file is part of the examples of the Qt Toolkit.
     **
     ** $QT_BEGIN_LICENSE:BSD$
     ** You may use this file under the terms of the BSD license as follows:
     **
     ** "Redistribution and use in source and binary forms, with or without
     ** modification, are permitted provided that the following conditions are
     ** met:
     **   * Redistributions of source code must retain the above copyright
     **     notice, this list of conditions and the following disclaimer.
     **   * Redistributions in binary form must reproduce the above copyright
     **     notice, this list of conditions and the following disclaimer in
     **     the documentation and/or other materials provided with the
     **     distribution.
     **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
     **     the names of its contributors may be used to endorse or promote
     **     products derived from this software without specific prior written
     **     permission.
     **
     ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
     ** $QT_END_LICENSE$
     **
     ****************************************************************************/

     #include "levelmeter.h"

     #include <math.h>

     #include <QPainter>
     #include <QTimer>
     #include <QDebug>

     // Constants
     const int RedrawInterval = 100; // ms
     const qreal PeakDecayRate = 0.001;
     const int PeakHoldLevelDuration = 2000; // ms

     LevelMeter::LevelMeter(QWidget *parent)
         :   QWidget(parent)
         ,   m_rmsLevel(0.0)
         ,   m_peakLevel(0.0)
         ,   m_decayedPeakLevel(0.0)
         ,   m_peakDecayRate(PeakDecayRate)
         ,   m_peakHoldLevel(0.0)
         ,   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, SIGNAL(timeout()), this, SLOT(redrawTimerExpired()));
         m_redrawTimer->start(RedrawInterval);
     }

     LevelMeter::~LevelMeter()
     {

     }

     void LevelMeter::reset()
     {
         m_rmsLevel = 0.0;
         m_peakLevel = 0.0;
         update();
     }

     void LevelMeter::levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples)
     {
         // Smooth the RMS signal
         const qreal smooth = pow(qreal(0.9), static_cast<qreal>(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 LevelMeter::redrawTimerExpired()
     {
         // Decay the peak signal
         const int elapsedMs = m_peakLevelChanged.elapsed();
         const qreal 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 LevelMeter::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);
     }