- Qt 5.5
- Qt Multimedia
- Spectrum Example
- levelmeter.cpp Example File
- Qt 5.5.1 Reference Documentation

# levelmeter.cpp Example File

spectrum/app/levelmeter.cpp

    /****************************************************************************
    **
    ** Copyright (C) 2015 The Qt Company Ltd.
    ** Contact: http://www.qt.io/licensing/
    **
    ** 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 The Qt Company Ltd 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);
    }