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

mcallegari / qlcplus / 7025156636

28 Nov 2023 10:11PM UTC coverage: 31.979% (-0.02%) from 32.001%
7025156636

push

github

mcallegari
qmlui: start to handle real beat-based Show

15114 of 47262 relevant lines covered (31.98%)

23507.96 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() << "ID:" << sfunc->functionID() << "st:" << sfunc->startTime() << "dur:" << sfunc->duration(m_doc);
×
94

95
    qDebug() << "Ordered list of ShowFunctions (beats):";
×
96
    foreach (ShowFunction *sfunc, m_beatFunctions)
×
97
        qDebug() << "ID:" << sfunc->functionID() << "st:" << sfunc->startTime() << "dur:" << 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
        if (timer->isBeat() && beatSynced == false)
×
157
            beatSynced = true;
×
158

159
        if (beatSynced == false)
×
160
            return;
×
161
    }
162

163
    // check if there are time-based functions to start
164
    while (startFunctionsDone == false)
×
165
    {
166
        if (m_currentTimeFunctionIndex == m_timeFunctions.count())
×
167
            break;
×
168

169
        ShowFunction *sf = m_timeFunctions.at(m_currentTimeFunctionIndex);
×
170
        quint32 funcStartTime = sf->startTime();
×
171
        quint32 functionTimeOffset = 0;
×
172
        Function *f = m_doc->function(sf->functionID());
×
173

174
        // this should happen only when a Show is not started from 0
175
        if (m_elapsedTime > funcStartTime)
×
176
        {
177
            functionTimeOffset = m_elapsedTime - funcStartTime;
×
178
            funcStartTime = m_elapsedTime;
×
179
        }
180
        if (m_elapsedTime >= funcStartTime)
×
181
        {
182
            foreach (Track *track, m_show->tracks())
×
183
            {
184
                if (track->showFunctions().contains(sf))
×
185
                {
186
                    int intOverrideId = f->requestAttributeOverride(Function::Intensity, m_intensityMap[track->id()]);
×
187
                    //f->adjustAttribute(m_intensityMap[track->id()], Function::Intensity);
188
                    sf->setIntensityOverrideId(intOverrideId);
×
189
                    break;
×
190
                }
191
            }
192

193
            f->start(m_doc->masterTimer(), functionParent(), functionTimeOffset);
×
194
            m_runningQueue.append(QPair<Function *, quint32>(f, sf->startTime() + sf->duration(m_doc)));
×
195
            m_currentTimeFunctionIndex++;
×
196
        }
197
        else
198
            startFunctionsDone = true;
×
199
    }
200

201
    startFunctionsDone = false;
×
202

203
    // check if there are beat-based functions to start
204
    while (startFunctionsDone == false)
×
205
    {
206
        if (m_currentBeatFunctionIndex == m_beatFunctions.count())
×
207
            break;
×
208

209
        ShowFunction *sf = m_beatFunctions.at(m_currentBeatFunctionIndex);
×
210
        quint32 funcStartTime = sf->startTime();
×
211
        quint32 functionTimeOffset = 0;
×
212
        Function *f = m_doc->function(sf->functionID());
×
213

214
        // this should happen only when a Show is not started from 0
215
        if (m_elapsedTime > funcStartTime)
×
216
        {
217
            functionTimeOffset = m_elapsedTime - funcStartTime;
×
218
            funcStartTime = m_elapsedTime;
×
219
        }
220
        if (m_elapsedTime >= funcStartTime)
×
221
        {
222
            foreach (Track *track, m_show->tracks())
×
223
            {
224
                if (track->showFunctions().contains(sf))
×
225
                {
226
                    int intOverrideId = f->requestAttributeOverride(Function::Intensity, m_intensityMap[track->id()]);
×
227
                    //f->adjustAttribute(m_intensityMap[track->id()], Function::Intensity);
228
                    sf->setIntensityOverrideId(intOverrideId);
×
229
                    break;
×
230
                }
231
            }
232

233
            f->start(m_doc->masterTimer(), functionParent(), functionTimeOffset);
×
234
            m_runningQueue.append(QPair<Function *, quint32>(f, sf->startTime() + sf->duration(m_doc)));
×
235
            m_currentBeatFunctionIndex++;
×
236
        }
237
        else
238
            startFunctionsDone = true;
×
239
    }
240

241
    // Phase 2. Check if we need to stop some running Functions
242
    // It is done in reverse order for two reasons:
243
    // 1- m_runningQueue is not ordered by stop time
244
    // 2- to avoid messing up with indices when an entry is removed
245
    for(int i = m_runningQueue.count() - 1; i >= 0; i--)
×
246
    {
247
        Function *func = m_runningQueue.at(i).first;
×
248
        quint32 stopTime = m_runningQueue.at(i).second;
×
249

250
        // if we passed the function stop time
251
        if (m_elapsedTime >= stopTime)
×
252
        {
253
            // stop the function
254
            func->stop(functionParent());
×
255
            // remove it from the running queue
256
            m_runningQueue.removeAt(i);
×
257
        }
258
    }
259

260
    // Phase 3. Check if this is the end of the Show
261
    if (m_elapsedTime >= m_totalRunTime)
×
262
    {
263
        if (m_show != NULL)
×
264
            m_show->stop(functionParent());
×
265
        emit showFinished();
×
266
        return;
×
267
    }
268

269
    m_elapsedTime += MasterTimer::tick();
×
270
    emit timeChanged(m_elapsedTime);
×
271
}
272

273
/************************************************************************
274
 * Intensity
275
 ************************************************************************/
276

277
void ShowRunner::adjustIntensity(qreal fraction, Track *track)
×
278
{
279
    if (track == NULL)
×
280
        return;
×
281

282
    qDebug() << Q_FUNC_INFO << "Track ID: " << track->id() << ", val:" << fraction;
×
283
    m_intensityMap[track->id()] = fraction;
×
284

285
    foreach (ShowFunction *sf, track->showFunctions())
×
286
    {
287
        Function *f = m_doc->function(sf->functionID());
×
288
        if (f == NULL)
×
289
            continue;
×
290

291
        for (int i = 0; i < m_runningQueue.count(); i++)
×
292
        {
293
            Function *rf = m_runningQueue.at(i).first;
×
294
            if (f == rf)
×
295
                f->adjustAttribute(fraction, sf->intensityOverrideId());
×
296
        }
297
    }
298
}
299

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