• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 26643984380

29 May 2026 02:45PM UTC coverage: 34.968% (-0.07%) from 35.037%
26643984380

Pull #2036

github

web-flow
Merge dd2197bec into f9fbc19ef
Pull Request #2036: engine/audio: configurable spectrum grid for Audio Triggers

17 of 188 new or added lines in 5 files covered. (9.04%)

13 existing lines in 4 files now uncovered.

18309 of 52359 relevant lines covered (34.97%)

41042.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.73
/engine/src/rgbaudio.cpp
1
/*
2
  Q Light Controller Plus
3
  rgbaudio.cpp
4

5
  Copyright (c) Massimo Callegari
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QXmlStreamReader>
21
#include <QXmlStreamWriter>
22
#include <QDebug>
23

24
#include "rgbaudio.h"
25
#include "audiocapture.h"
26
#include "doc.h"
27

28
RGBAudio::RGBAudio(Doc * doc)
48✔
29
    : RGBAlgorithm(doc)
30
    , m_audioInput(NULL)
48✔
31
    , m_bandsNumber(-1)
48✔
32
    , m_maxMagnitude(0)
48✔
33
{
34
}
48✔
35

36
RGBAudio::RGBAudio(const RGBAudio& a, QObject *parent)
×
37
    : QObject(parent)
38
    , RGBAlgorithm(a.doc())
39
    , m_audioInput(NULL)
×
40
    , m_bandsNumber(-1)
×
41
    , m_maxMagnitude(0)
×
42
{
43
}
×
44

45
RGBAudio::~RGBAudio()
48✔
46
{
47
    QSharedPointer<AudioCapture> capture(doc()->audioInputCapture());
48✔
48
    if (capture.data() == m_audioInput && m_bandsNumber > 0)
48✔
49
    {
50
        m_audioInput->unregisterBandsNumber(m_bandsNumber);
×
51
    }
52
}
48✔
53

54
RGBAlgorithm* RGBAudio::clone() const
×
55
{
56
    RGBAudio* audio = new RGBAudio(*this);
×
57
    return static_cast<RGBAlgorithm*> (audio);
×
58
}
59

60
void RGBAudio::setAudioCapture(AudioCapture* cap)
×
61
{
62
    qDebug() << Q_FUNC_INFO << "Audio capture set";
×
63

64
    m_audioInput = cap;
×
NEW
65
    connect(m_audioInput, SIGNAL(dataProcessed(double*,int,double,quint32,int,double)),
×
66
            this, SLOT(slotAudioBarsChanged(double*,int,double,quint32,int,double)));
67
    m_bandsNumber = -1;
×
68
}
×
69

70
void RGBAudio::slotAudioBarsChanged(double *spectrumBands, int size,
×
71
                                    double maxMagnitude, quint32 power, int spectrumGridMode,
72
                                    double spectrumLowBandGamma)
73
{
74
    Q_UNUSED(spectrumGridMode)
75
    Q_UNUSED(spectrumLowBandGamma)
76
    if (size != m_bandsNumber)
×
77
        return;
×
78

79
    QMutexLocker locker(&m_mutex);
×
80

81
    m_spectrumValues.clear();
×
82
    for (int i = 0; i < m_bandsNumber; i++)
×
83
        m_spectrumValues.append(spectrumBands[i]);
×
84
    m_maxMagnitude = maxMagnitude;
×
85
    m_volumePower = power;
×
86
}
×
87

88
void RGBAudio::calculateColors(int barsHeight)
×
89
{
90
    if (barsHeight > 0)
×
91
    {
92
        QColor startColor = getColor(0);
×
93
        QColor endColor = getColor(1);
×
94
        m_barColors.clear();
×
95
        if (endColor == QColor()
×
96
            || barsHeight == 1) // to avoid division by 0 below
×
97
        {
98
            for (int i = 0; i < barsHeight; i++)
×
99
                m_barColors.append(startColor.rgb());
×
100
        }
101
        else
102
        {
103
            int crDelta = (endColor.red() - startColor.red()) / (barsHeight - 1);
×
104
            int cgDelta = (endColor.green() - startColor.green()) / (barsHeight - 1);
×
105
            int cbDelta = (endColor.blue() - startColor.blue()) / (barsHeight - 1);
×
106
            QColor pixelColor = startColor;
×
107

108
            for (int i = 0; i < barsHeight; i++)
×
109
            {
110
                m_barColors.append(pixelColor.rgb());
×
111
                pixelColor = QColor(pixelColor.red() + crDelta,
×
112
                                    pixelColor.green() + cgDelta,
×
113
                                    pixelColor.blue() + cbDelta);
×
114
            }
115
        }
116
    }
117
}
×
118

119
/****************************************************************************
120
 * RGBAlgorithm
121
 ****************************************************************************/
122

123
int RGBAudio::rgbMapStepCount(const QSize& size)
×
124
{
125
    Q_UNUSED(size);
126
    return 1;
×
127
}
128

129
void RGBAudio::rgbMapSetColors(const QVector<uint> &colors)
×
130
{
131
    Q_UNUSED(colors);
132
}
×
133

134
QVector<uint> RGBAudio::rgbMapGetColors()
×
135
{
136
    return QVector<uint>();
×
137
}
138

139
void RGBAudio::rgbMap(const QSize& size, uint rgb, int step, RGBMap &map)
×
140
{
141
    Q_UNUSED(step);
142

143
    QMutexLocker locker(&m_mutex);
×
144

145
    QSharedPointer<AudioCapture> capture = doc()->audioInputCapture();
×
146
    if (capture.data() != m_audioInput)
×
147
        setAudioCapture(capture.data());
×
148

149
    map.resize(size.height());
×
150
    for (int y = 0; y < size.height(); y++)
×
151
    {
152
        map[y].resize(size.width());
×
153
        map[y].fill(0);
×
154
    }
155

156
    // on the first round, just set the proper number of
157
    // spectrum bands to receive
158
    if (m_bandsNumber == -1)
×
159
    {
160
        m_bandsNumber = size.width();
×
161
        qDebug() << "[RGBAudio] set" << m_bandsNumber << "bars";
×
162
        m_audioInput->registerBandsNumber(m_bandsNumber);
×
163
        return;
×
164
    }
165
    if (m_barColors.count() == 0)
×
166
        calculateColors(size.height());
×
167

168
    double volHeight = (m_volumePower * size.height()) / 0x7FFF;
×
169
    for (int x = 0; x < m_spectrumValues.count(); x++)
×
170
    {
171
        int barHeight;
172
        if (m_maxMagnitude == 0)
×
173
            barHeight = 0;
×
174
        else
175
        {
176
            barHeight = (volHeight * m_spectrumValues[x]) / m_maxMagnitude;
×
177
            if (barHeight > size.height())
×
178
                barHeight = size.height();
×
179
        }
180
        for (int y = size.height() - barHeight; y < size.height(); y++)
×
181
        {
182
            if (m_barColors.count() == 0)
×
183
                map[y][x] = rgb;
×
184
            else
185
                map[y][x] = m_barColors.at(y);
×
186
        }
187
    }
188
}
×
189

190
void RGBAudio::postRun()
×
191
{
192
    QMutexLocker locker(&m_mutex);
×
193

194
    QSharedPointer<AudioCapture> capture = doc()->audioInputCapture();
×
195
    if (capture.data() == m_audioInput)
×
196
    {
NEW
197
        disconnect(m_audioInput, SIGNAL(dataProcessed(double*,int,double,quint32,int,double)),
×
198
                   this, SLOT(slotAudioBarsChanged(double*,int,double,quint32,int,double)));
199
        if (m_bandsNumber > 0)
×
200
            m_audioInput->unregisterBandsNumber(m_bandsNumber);
×
201
    }
202
    m_audioInput = NULL;
×
203
    m_bandsNumber = -1;
×
204
}
×
205

206
QString RGBAudio::name() const
47✔
207
{
208
    return QString("Audio Spectrum");
47✔
209
}
210

211
QString RGBAudio::author() const
×
212
{
213
    return QString("Massimo Callegari");
×
214
}
215

216
int RGBAudio::apiVersion() const
×
217
{
218
    return 1;
×
219
}
220

221
void RGBAudio::setColors(QVector<QColor> colors)
×
222
{
223
    RGBAlgorithm::setColors(colors);
×
224

225
    // invalidate bars colors so the next time a rendering is
226
    // required, it will be filled with the right values
227
    m_barColors.clear();
×
228
}
×
229

230
RGBAlgorithm::Type RGBAudio::type() const
×
231
{
232
    return RGBAlgorithm::Audio;
×
233
}
234

235
int RGBAudio::acceptColors() const
×
236
{
237
    return 2; // start and end colors accepted
×
238
}
239

240
bool RGBAudio::loadXML(QXmlStreamReader &root)
×
241
{
242
    if (root.name() != KXMLQLCRGBAlgorithm)
×
243
    {
244
        qWarning() << Q_FUNC_INFO << "RGB Algorithm node not found";
×
245
        return false;
×
246
    }
247

248
    if (root.attributes().value(KXMLQLCRGBAlgorithmType).toString() != KXMLQLCRGBAudio)
×
249
    {
250
        qWarning() << Q_FUNC_INFO << "RGB Algorithm is not Audio";
×
251
        return false;
×
252
    }
253

254
    root.skipCurrentElement();
×
255

256
    return true;
×
257
}
258

259
bool RGBAudio::saveXML(QXmlStreamWriter *doc) const
×
260
{
261
    Q_ASSERT(doc != NULL);
×
262

263
    doc->writeStartElement(KXMLQLCRGBAlgorithm);
×
264
    doc->writeAttribute(KXMLQLCRGBAlgorithmType, KXMLQLCRGBAudio);
×
265
    doc->writeEndElement();
×
266

267
    return true;
×
268
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc