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

mcallegari / qlcplus / 14809507932

03 May 2025 09:13AM UTC coverage: 31.879% (+0.03%) from 31.845%
14809507932

push

github

web-flow
Merge pull request #1745 from mcallegari/qmluiqt6

Port QML UI to Qt6

2 of 9 new or added lines in 3 files covered. (22.22%)

3720 existing lines in 174 files now uncovered.

16422 of 51513 relevant lines covered (31.88%)

19079.9 hits per line

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

0.0
/engine/src/showrunner.cpp
1
/*
2
  Q Light Controller
3
  showrunner.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 <QMutex>
21
#include <QDebug>
22

23
#include "showrunner.h"
24
#include "function.h"
25
#include "track.h"
26
#include "show.h"
27

28
#define TIMER_INTERVAL 50
29

30
static bool compareShowFunctions(const ShowFunction *sf1, const ShowFunction *sf2)
×
31
{
32
    if (sf1->startTime() < sf2->startTime())
×
33
        return true;
×
UNCOV
34
    return false;
×
35
}
36

37
ShowRunner::ShowRunner(const Doc* doc, quint32 showID, quint32 startTime)
×
38
    : QObject(NULL)
39
    , m_doc(doc)
×
40
    , m_currentTimeFunctionIndex(0)
×
41
    , m_elapsedTime(startTime)
×
42
    , m_currentBeatFunctionIndex(0)
×
43
    , m_elapsedBeats(0)
×
44
    , beatSynced(false)
×
45
    , m_totalRunTime(0)
×
46
{
UNCOV
47
    Q_ASSERT(m_doc != NULL);
×
UNCOV
48
    Q_ASSERT(showID != Show::invalidId());
×
49

50
    m_show = qobject_cast<Show*>(m_doc->function(showID));
×
51
    if (m_show == NULL)
×
UNCOV
52
        return;
×
53

54
    foreach (Track *track, m_show->tracks())
×
55
    {
56
        // some sanity checks
57
        if (track == NULL ||
×
58
            track->id() == Track::invalidId())
×
59
                continue;
×
60

61
        if (track->isMute())
×
62
            continue;
×
63

64
        // get all the functions of the track and append them to the runner queue
65
        foreach (ShowFunction *sfunc, track->showFunctions())
×
66
        {
67
            if (sfunc->startTime() + sfunc->duration(m_doc) <= startTime)
×
68
                continue;
×
69

70
            Function *f = m_doc->function(sfunc->functionID());
×
71
            if (f == NULL)
×
72
                continue;
×
73

74
            if (f->tempoType() == Function::Time)
×
75
                m_timeFunctions.append(sfunc);
×
76
            else
77
                m_beatFunctions.append(sfunc);
×
78

79
            if (sfunc->startTime() + sfunc->duration(m_doc) > m_totalRunTime)
×
80
                m_totalRunTime = sfunc->startTime() + sfunc->duration(m_doc);
×
UNCOV
81
        }
×
82

83
        // Initialize the intensity map
84
        m_intensityMap[track->id()] = 1.0;
×
UNCOV
85
    }
×
86

87
    std::sort(m_timeFunctions.begin(), m_timeFunctions.end(), compareShowFunctions);
×
88
    std::sort(m_beatFunctions.begin(), m_beatFunctions.end(), compareShowFunctions);
×
89

90
#if 1
UNCOV
91
    qDebug() << "Ordered list of ShowFunctions (time):";
×
92
    foreach (ShowFunction *sfunc, m_timeFunctions)
×
UNCOV
93
        qDebug() << "[Show] Function ID:" << sfunc->functionID() << "start time:" << sfunc->startTime() << "duration:" << sfunc->duration(m_doc);
×
94

UNCOV
95
    qDebug() << "Ordered list of ShowFunctions (beats):";
×
96
    foreach (ShowFunction *sfunc, m_beatFunctions)
×
UNCOV
97
        qDebug() << "[Show] Function ID:" << sfunc->functionID() << "start time:" << sfunc->startTime() << "duration:" << sfunc->duration(m_doc);
×
98
#endif
99
    m_runningQueue.clear();
×
100

101
    qDebug() << "ShowRunner created";
×
102
}
×
103

104
ShowRunner::~ShowRunner()
×
105
{
106
}
×
107

108
void ShowRunner::start()
×
109
{
UNCOV
110
    qDebug() << "ShowRunner started";
×
111
}
×
112

113
void ShowRunner::setPause(bool enable)
×
114
{
115
    for (int i = 0; i < m_runningQueue.count(); i++)
×
116
    {
117
        Function *f = m_runningQueue.at(i).first;
×
118
        f->setPause(enable);
×
119
    }
120
}
×
121

122
void ShowRunner::stop()
×
123
{
124
    m_elapsedTime = 0;
×
125
    m_elapsedBeats = 0;
×
126
    m_currentTimeFunctionIndex = 0;
×
127
    m_currentBeatFunctionIndex = 0;
×
128

129
    for (int i = 0; i < m_runningQueue.count(); i++)
×
130
    {
131
        Function *f = m_runningQueue.at(i).first;
×
132
        f->stop(functionParent());
×
133
    }
134

135
    m_runningQueue.clear();
×
UNCOV
136
    qDebug() << "ShowRunner stopped";
×
137
}
×
138

139
FunctionParent ShowRunner::functionParent() const
×
140
{
141
    return FunctionParent(FunctionParent::Function, m_show->id());
×
142
}
143

144
void ShowRunner::write(MasterTimer *timer)
×
145
{
146
    //qDebug() << Q_FUNC_INFO << "elapsed:" << m_elapsedTime << ", total:" << m_totalRunTime;
147

148
    // Phase 1. Check all the Functions that need to be started
149
    // m_timeFunctions is ordered by startup time, so when we found an entry
150
    // with start time greater than m_elapsed, this phase is over
UNCOV
151
    bool startFunctionsDone = false;
×
152

153
    // check synchronization to beats (if show is beat-based)
154
    if (m_show->tempoType() == Function::Beats)
×
155
    {
156
        //qDebug() << Q_FUNC_INFO << "isBeat:" << timer->isBeat() << ", elapsed beats:" << m_elapsedBeats;
157

158
        if (timer->isBeat())
×
159
        {
160
            if (beatSynced == false)
×
161
            {
162
                beatSynced = true;
×
UNCOV
163
                qDebug() << "Beat synced";
×
164
            }
165
            else
166
                m_elapsedBeats += 1000;
×
167
        }
168

169
        if (beatSynced == false)
×
UNCOV
170
            return;
×
171
    }
172

173
    // check if there are time-based functions to start
UNCOV
174
    while (startFunctionsDone == false)
×
175
    {
176
        if (m_currentTimeFunctionIndex == m_timeFunctions.count())
×
UNCOV
177
            break;
×
178

179
        ShowFunction *sf = m_timeFunctions.at(m_currentTimeFunctionIndex);
×
180
        quint32 funcStartTime = sf->startTime();
×
UNCOV
181
        quint32 functionTimeOffset = 0;
×
182
        Function *f = m_doc->function(sf->functionID());
×
183

184
        // this should happen only when a Show is not started from 0
185
        if (m_elapsedTime > funcStartTime)
×
186
        {
187
            functionTimeOffset = m_elapsedTime - funcStartTime;
×
UNCOV
188
            funcStartTime = m_elapsedTime;
×
189
        }
190
        if (m_elapsedTime >= funcStartTime)
×
191
        {
192
            foreach (Track *track, m_show->tracks())
×
193
            {
194
                if (track->showFunctions().contains(sf))
×
195
                {
196
                    int intOverrideId = f->requestAttributeOverride(Function::Intensity, m_intensityMap[track->id()]);
×
197
                    //f->adjustAttribute(m_intensityMap[track->id()], Function::Intensity);
198
                    sf->setIntensityOverrideId(intOverrideId);
×
UNCOV
199
                    break;
×
200
                }
UNCOV
201
            }
×
202

203
            f->start(m_doc->masterTimer(), functionParent(), functionTimeOffset);
×
204
            m_runningQueue.append(QPair<Function *, quint32>(f, sf->startTime() + sf->duration(m_doc)));
×
205
            m_currentTimeFunctionIndex++;
×
206
        }
207
        else
UNCOV
208
            startFunctionsDone = true;
×
209
    }
210

UNCOV
211
    startFunctionsDone = false;
×
212

213
    // check if there are beat-based functions to start
UNCOV
214
    while (startFunctionsDone == false)
×
215
    {
216
        if (m_currentBeatFunctionIndex == m_beatFunctions.count())
×
UNCOV
217
            break;
×
218

219
        ShowFunction *sf = m_beatFunctions.at(m_currentBeatFunctionIndex);
×
220
        quint32 funcStartTime = sf->startTime();
×
UNCOV
221
        quint32 functionTimeOffset = 0;
×
222
        Function *f = m_doc->function(sf->functionID());
×
223

224
        // this should happen only when a Show is not started from 0
225
        if (m_elapsedBeats > funcStartTime)
×
226
        {
227
            functionTimeOffset = m_elapsedBeats - funcStartTime;
×
UNCOV
228
            funcStartTime = m_elapsedBeats;
×
229
        }
230
        if (m_elapsedBeats >= funcStartTime)
×
231
        {
232
            foreach (Track *track, m_show->tracks())
×
233
            {
234
                if (track->showFunctions().contains(sf))
×
235
                {
236
                    int intOverrideId = f->requestAttributeOverride(Function::Intensity, m_intensityMap[track->id()]);
×
237
                    //f->adjustAttribute(m_intensityMap[track->id()], Function::Intensity);
238
                    sf->setIntensityOverrideId(intOverrideId);
×
UNCOV
239
                    break;
×
240
                }
UNCOV
241
            }
×
242

243
            f->start(m_doc->masterTimer(), functionParent(), functionTimeOffset);
×
244
            m_runningQueue.append(QPair<Function *, quint32>(f, sf->startTime() + sf->duration(m_doc)));
×
245
            m_currentBeatFunctionIndex++;
×
246
        }
247
        else
UNCOV
248
            startFunctionsDone = true;
×
249
    }
250

251
    // Phase 2. Check if we need to stop some running Functions
252
    // It is done in reverse order for two reasons:
253
    // 1- m_runningQueue is not ordered by stop time
254
    // 2- to avoid messing up with indices when an entry is removed
255
    for (int i = m_runningQueue.count() - 1; i >= 0; i--)
×
256
    {
257
        Function *func = m_runningQueue.at(i).first;
×
258
        quint32 stopTime = m_runningQueue.at(i).second;
×
259
        quint32 currTime = func->tempoType() == Function::Time ? m_elapsedTime : m_elapsedBeats;
×
260

261
        // if we passed the function stop time
262
        if (currTime >= stopTime)
×
263
        {
264
            // stop the function
265
            func->stop(functionParent());
×
266
            // remove it from the running queue
267
            m_runningQueue.removeAt(i);
×
268
        }
269
    }
270

271
    // Phase 3. Check if this is the end of the Show
272
    if (m_elapsedTime >= m_totalRunTime)
×
273
    {
274
        if (m_show != NULL)
×
275
            m_show->stop(functionParent());
×
276
        emit showFinished();
×
277
        return;
×
278
    }
279

280
    m_elapsedTime += MasterTimer::tick();
×
281
    emit timeChanged(m_elapsedTime);
×
282
}
283

284
/************************************************************************
285
 * Intensity
286
 ************************************************************************/
287

288
void ShowRunner::adjustIntensity(qreal fraction, Track *track)
×
289
{
290
    if (track == NULL)
×
UNCOV
291
        return;
×
292

UNCOV
293
    qDebug() << Q_FUNC_INFO << "Track ID: " << track->id() << ", val:" << fraction;
×
294
    m_intensityMap[track->id()] = fraction;
×
295

296
    foreach (ShowFunction *sf, track->showFunctions())
×
297
    {
298
        Function *f = m_doc->function(sf->functionID());
×
299
        if (f == NULL)
×
300
            continue;
×
301

302
        for (int i = 0; i < m_runningQueue.count(); i++)
×
303
        {
304
            Function *rf = m_runningQueue.at(i).first;
×
305
            if (f == rf)
×
306
                f->adjustAttribute(fraction, sf->intensityOverrideId());
×
307
        }
UNCOV
308
    }
×
309
}
310

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