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

mcallegari / qlcplus / 8961243534

05 May 2024 09:23PM UTC coverage: 32.068% (+4.0%) from 28.094%
8961243534

push

github

mcallegari
Merge branch 'master' into qmltoqt6

902 of 2557 new or added lines in 140 files covered. (35.28%)

166 existing lines in 76 files now uncovered.

15395 of 48008 relevant lines covered (32.07%)

22949.67 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
{
UNCOV
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

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

NEW
74
            if (f->tempoType() == Function::Time)
×
NEW
75
                m_timeFunctions.append(sfunc);
×
76
            else
NEW
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

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

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

NEW
95
    qDebug() << "Ordered list of ShowFunctions (beats):";
×
NEW
96
    foreach (ShowFunction *sfunc, m_beatFunctions)
×
NEW
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;
×
NEW
125
    m_elapsedBeats = 0;
×
NEW
126
    m_currentTimeFunctionIndex = 0;
×
NEW
127
    m_currentBeatFunctionIndex = 0;
×
128

UNCOV
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

NEW
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
NEW
151
    bool startFunctionsDone = false;
×
152

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

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

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

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

NEW
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)));
×
NEW
205
            m_currentTimeFunctionIndex++;
×
206
        }
207
        else
NEW
208
            startFunctionsDone = true;
×
209
    }
210

NEW
211
    startFunctionsDone = false;
×
212

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

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

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

NEW
243
            f->start(m_doc->masterTimer(), functionParent(), functionTimeOffset);
×
NEW
244
            m_runningQueue.append(QPair<Function *, quint32>(f, sf->startTime() + sf->duration(m_doc)));
×
NEW
245
            m_currentBeatFunctionIndex++;
×
246
        }
247
        else
NEW
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
NEW
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;
×
NEW
259
        quint32 currTime = func->tempoType() == Function::Time ? m_elapsedTime : m_elapsedBeats;
×
260

261
        // if we passed the function stop time
NEW
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