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

mcallegari / qlcplus / 13763878004

10 Mar 2025 11:47AM UTC coverage: 31.887%. Remained the same
13763878004

push

github

mcallegari
4.14.1 release to date

14701 of 46103 relevant lines covered (31.89%)

26418.09 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;
×
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
{
47
    Q_ASSERT(m_doc != NULL);
48
    Q_ASSERT(showID != Show::invalidId());
49

50
    m_show = qobject_cast<Show*>(m_doc->function(showID));
×
51
    if (m_show == NULL)
×
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);
×
81
        }
82

83
        // Initialize the intensity map
84
        m_intensityMap[track->id()] = 1.0;
×
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
91
    qDebug() << "Ordered list of ShowFunctions (time):";
92
    foreach (ShowFunction *sfunc, m_timeFunctions)
×
93
        qDebug() << "[Show] Function ID:" << sfunc->functionID() << "start time:" << sfunc->startTime() << "duration:" << sfunc->duration(m_doc);
94

95
    qDebug() << "Ordered list of ShowFunctions (beats):";
96
    foreach (ShowFunction *sfunc, m_beatFunctions)
×
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
{
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();
×
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
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;
×
163
                qDebug() << "Beat synced";
164
            }
165
            else
166
                m_elapsedBeats += 1000;
×
167
        }
168

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

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

179
        ShowFunction *sf = m_timeFunctions.at(m_currentTimeFunctionIndex);
×
180
        quint32 funcStartTime = sf->startTime();
×
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;
×
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);
×
199
                    break;
200
                }
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
208
            startFunctionsDone = true;
209
    }
210

211
    startFunctionsDone = false;
212

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

219
        ShowFunction *sf = m_beatFunctions.at(m_currentBeatFunctionIndex);
×
220
        quint32 funcStartTime = sf->startTime();
×
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;
×
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);
×
239
                    break;
240
                }
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
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)
×
291
        return;
292

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
        }
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

© 2025 Coveralls, Inc