1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "levelmeter.h"
52
53#include <math.h>
54
55#include <QPainter>
56#include <QTimer>
57#include <QDebug>
58
59
60// Constants
61const int RedrawInterval = 100; // ms
62const qreal PeakDecayRate = 0.001;
63const int PeakHoldLevelDuration = 2000; // ms
64
65
66LevelMeter::LevelMeter(QWidget *parent)
67 : QWidget(parent)
68 , m_rmsLevel(0.0)
69 , m_peakLevel(0.0)
70 , m_decayedPeakLevel(0.0)
71 , m_peakDecayRate(PeakDecayRate)
72 , m_peakHoldLevel(0.0)
73 , m_redrawTimer(new QTimer(this))
74 , m_rmsColor(Qt::red)
75 , m_peakColor(255, 200, 200, 255)
76{
77 setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Preferred);
78 setMinimumWidth(30);
79
80 connect(sender: m_redrawTimer, signal: &QTimer::timeout,
81 receiver: this, slot: &LevelMeter::redrawTimerExpired);
82 m_redrawTimer->start(msec: RedrawInterval);
83}
84
85LevelMeter::~LevelMeter()
86{
87
88}
89
90void LevelMeter::reset()
91{
92 m_rmsLevel = 0.0;
93 m_peakLevel = 0.0;
94 update();
95}
96
97void LevelMeter::levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples)
98{
99 // Smooth the RMS signal
100 const qreal smooth = pow(x: qreal(0.9), y: static_cast<qreal>(numSamples) / 256); // TODO: remove this magic number
101 m_rmsLevel = (m_rmsLevel * smooth) + (rmsLevel * (1.0 - smooth));
102
103 if (peakLevel > m_decayedPeakLevel) {
104 m_peakLevel = peakLevel;
105 m_decayedPeakLevel = peakLevel;
106 m_peakLevelChanged.start();
107 }
108
109 if (peakLevel > m_peakHoldLevel) {
110 m_peakHoldLevel = peakLevel;
111 m_peakHoldLevelChanged.start();
112 }
113
114 update();
115}
116
117void LevelMeter::redrawTimerExpired()
118{
119 // Decay the peak signal
120 const int elapsedMs = m_peakLevelChanged.elapsed();
121 const qreal decayAmount = m_peakDecayRate * elapsedMs;
122 if (decayAmount < m_peakLevel)
123 m_decayedPeakLevel = m_peakLevel - decayAmount;
124 else
125 m_decayedPeakLevel = 0.0;
126
127 // Check whether to clear the peak hold level
128 if (m_peakHoldLevelChanged.elapsed() > PeakHoldLevelDuration)
129 m_peakHoldLevel = 0.0;
130
131 update();
132}
133
134void LevelMeter::paintEvent(QPaintEvent *event)
135{
136 Q_UNUSED(event)
137
138 QPainter painter(this);
139 painter.fillRect(r: rect(), c: Qt::black);
140
141 QRect bar = rect();
142
143 bar.setTop(rect().top() + (1.0 - m_peakHoldLevel) * rect().height());
144 bar.setBottom(bar.top() + 5);
145 painter.fillRect(bar, color: m_rmsColor);
146 bar.setBottom(rect().bottom());
147
148 bar.setTop(rect().top() + (1.0 - m_decayedPeakLevel) * rect().height());
149 painter.fillRect(bar, color: m_peakColor);
150
151 bar.setTop(rect().top() + (1.0 - m_rmsLevel) * rect().height());
152 painter.fillRect(bar, color: m_rmsColor);
153}
154

source code of qtmultimedia/examples/multimedia/spectrum/app/levelmeter.cpp