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

mcallegari / qlcplus / 7252848206

18 Dec 2023 07:26PM UTC coverage: 32.067% (+0.001%) from 32.066%
7252848206

push

github

mcallegari
Code style review #1427

199 of 628 new or added lines in 101 files covered. (31.69%)

8 existing lines in 2 files now uncovered.

15169 of 47304 relevant lines covered (32.07%)

23733.74 hits per line

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

70.72
/engine/src/chaserrunner.cpp
1
/*
2
  Q Light Controller Plus
3
  chaserrunner.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7
                Jano Svitok
8

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

13
      http://www.apache.org/licenses/LICENSE-2.0.txt
14

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

22
#include <QElapsedTimer>
23
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
24
#include <QRandomGenerator>
25
#endif
26
#include <QDebug>
27

28
#include "chaserrunner.h"
29
#include "mastertimer.h"
30
#include "chaserstep.h"
31
#include "qlcmacros.h"
32
#include "chaser.h"
33
#include "scene.h"
34
#include "doc.h"
35

36
ChaserRunner::ChaserRunner(const Doc *doc, const Chaser *chaser, quint32 startTime)
30✔
37
    : QObject(NULL)
38
    , m_doc(doc)
39
    , m_chaser(chaser)
40
    , m_updateOverrideSpeeds(false)
41
    , m_startOffset(0)
42
    , m_lastRunStepIdx(-1)
43
    , m_lastFunctionID(Function::invalidId())
60✔
44
    , m_roundTime(new QElapsedTimer())
30✔
45
    , m_order()
60✔
46
{
47
    Q_ASSERT(chaser != NULL);
30✔
48

49
    m_pendingAction.m_action = ChaserNoAction;
30✔
50
    m_pendingAction.m_masterIntensity = 1.0;
30✔
51
    m_pendingAction.m_stepIntensity = 1.0;
30✔
52
    m_pendingAction.m_fadeMode = Chaser::FromFunction;
30✔
53
    m_pendingAction.m_stepIndex = -1;
30✔
54

55
    if (m_chaser->type() == Function::SequenceType && startTime > 0)
30✔
56
    {
57
        qDebug() << "[ChaserRunner] startTime:" << startTime;
×
58
        int idx = 0;
×
59
        quint32 stepsTime = 0;
×
NEW
60
        foreach (ChaserStep step, chaser->steps())
×
61
        {
62
            uint duration = m_chaser->durationMode() == Chaser::Common ? m_chaser->duration() : step.duration;
×
63

64
            if (startTime < stepsTime + duration)
×
65
            {
66
                m_pendingAction.m_action = ChaserSetStepIndex;
×
67
                m_pendingAction.m_stepIndex = idx;
×
68
                m_startOffset = startTime - stepsTime;
×
69
                qDebug() << "[ChaserRunner] Starting from step:" << idx;
×
70
                break;
×
71
            }
72
            idx++;
×
73
            stepsTime += duration;
×
74
        }
75
    }
76

77
    m_direction = m_chaser->direction();
30✔
78
    connect(chaser, SIGNAL(changed(quint32)), this, SLOT(slotChaserChanged()));
30✔
79
    m_roundTime->restart();
30✔
80

81
    fillOrder();
30✔
82
}
30✔
83

84
ChaserRunner::~ChaserRunner()
40✔
85
{
86
    clearRunningList();
30✔
87
    delete m_roundTime;
30✔
88
}
40✔
89

90
/****************************************************************************
91
 * Speed
92
 ****************************************************************************/
93

94
void ChaserRunner::slotChaserChanged()
38✔
95
{
96
    // Handle (possible) speed change on the next write() pass
97
    m_updateOverrideSpeeds = true;
38✔
98
    QList<ChaserRunnerStep*> delList;
76✔
99
    foreach (ChaserRunnerStep *step, m_runnerSteps)
54✔
100
    {
101
        if (!m_chaser->steps().contains(ChaserStep(step->m_function->id())))
8✔
102
        {
103
            // Disappearing function: remove step
104
            delList.append(step);
5✔
105
        }
106
        else
107
        {
108
            // Recalculate the speed of each running step
109
            step->m_fadeIn = stepFadeIn(step->m_index);
3✔
110
            step->m_fadeOut = stepFadeOut(step->m_index);
3✔
111
            step->m_duration = stepDuration(step->m_index);
3✔
112
        }
113
    }
114
    foreach (ChaserRunnerStep *step, delList)
48✔
115
    {
116
        step->m_function->stop(functionParent());
5✔
117
        m_runnerSteps.removeAll(step);
5✔
118
        delete step;
5✔
119
    }
120
}
38✔
121

122
uint ChaserRunner::stepFadeIn(int stepIdx) const
129✔
123
{
124
    uint speed = 0;
129✔
125
    if (m_chaser->overrideFadeInSpeed() != Function::defaultSpeed())
129✔
126
    {
127
        // Override speed is used when another function has started the chaser,
128
        // i.e. chaser inside a chaser that wants to impose its own fade in speed
129
        // to its members.
130
        speed = m_chaser->overrideFadeInSpeed();
10✔
131
    }
132
    else
133
    {
134
        switch (m_chaser->fadeInMode())
119✔
135
        {
136
            case Chaser::Common:
3✔
137
                // All steps' fade in speed is dictated by the chaser
138
                speed = m_chaser->fadeInSpeed();
3✔
139
            break;
3✔
140
            case Chaser::PerStep:
4✔
141
                // Each step specifies its own fade in speed
142
                if (stepIdx >= 0 && stepIdx < m_chaser->stepsCount())
4✔
143
                    speed = m_chaser->steps().at(stepIdx).fadeIn;
3✔
144
                else
145
                    speed = Function::defaultSpeed();
1✔
146
            break;
4✔
147
            default:
112✔
148
            case Chaser::Default:
149
                // Don't touch members' fade in speed at all
150
                speed = Function::defaultSpeed();
112✔
151
            break;
112✔
152
        }
153
    }
154

155
    return speed;
129✔
156
}
157

158
uint ChaserRunner::stepFadeOut(int stepIdx) const
162✔
159
{
160
    uint speed = 0;
162✔
161
    if (m_chaser->overrideFadeOutSpeed() != Function::defaultSpeed())
162✔
162
    {
163
        // Override speed is used when another function has started the chaser,
164
        // i.e. chaser inside a chaser that wants to impose its own fade out speed
165
        // to its members.
166
        speed = m_chaser->overrideFadeOutSpeed();
10✔
167
    }
168
    else
169
    {
170
        switch (m_chaser->fadeOutMode())
152✔
171
        {
172
            case Chaser::Common:
3✔
173
                // All steps' fade out speed is dictated by the chaser
174
                speed = m_chaser->fadeOutSpeed();
3✔
175
            break;
3✔
176
            case Chaser::PerStep:
4✔
177
                // Each step specifies its own fade out speed
178
                if (stepIdx >= 0 && stepIdx < m_chaser->stepsCount())
4✔
179
                    speed = m_chaser->steps().at(stepIdx).fadeOut;
3✔
180
                else
181
                    speed = Function::defaultSpeed();
1✔
182
            break;
4✔
183
            default:
145✔
184
            case Chaser::Default:
185
                // Don't touch members' fade out speed at all
186
                speed = Function::defaultSpeed();
145✔
187
            break;
145✔
188
        }
189
    }
190

191
    return speed;
162✔
192
}
193

194
uint ChaserRunner::stepDuration(int stepIdx) const
137✔
195
{
196
    uint speed = 0;
137✔
197
    if (m_chaser->overrideDuration() != Function::defaultSpeed())
137✔
198
    {
199
        // Override speed is used when another function has started the chaser,
200
        // i.e. chaser inside a chaser that wants to impose its own duration
201
        // to its members.
202
        speed = m_chaser->overrideDuration();
10✔
203
    }
204
    else
205
    {
206
        switch (m_chaser->durationMode())
127✔
207
        {
208
            default:
123✔
209
            case Chaser::Default:
210
            case Chaser::Common:
211
                // All steps' duration is dictated by the chaser
212
                speed = m_chaser->duration();
123✔
213
            break;
123✔
214
            case Chaser::PerStep:
4✔
215
                // Each step specifies its own duration
216
                if (stepIdx >= 0 && stepIdx < m_chaser->stepsCount())
4✔
217
                    speed = m_chaser->steps().at(stepIdx).duration;
3✔
218
                else
219
                    speed = m_chaser->duration();
1✔
220
            break;
4✔
221
        }
222
    }
223

224
    return speed;
137✔
225
}
226

227
/****************************************************************************
228
 * Step control
229
 ****************************************************************************/
230

231
void ChaserRunner::setAction(ChaserAction &action)
38✔
232
{
233
    // apply the actions that can be applied immediately
234
    switch (action.m_action)
38✔
235
    {
236
        case ChaserNoAction:
6✔
237
            m_pendingAction.m_masterIntensity = action.m_masterIntensity;
6✔
238
            m_pendingAction.m_stepIntensity = action.m_stepIntensity;
6✔
239
        break;
6✔
240

241
        case ChaserStopStep:
×
242
        {
243
            bool stopped = false;
×
244

NEW
245
            foreach (ChaserRunnerStep *step, m_runnerSteps)
×
246
            {
247
                if (action.m_stepIndex == step->m_index)
×
248
                {
249
                    qDebug() << "[ChaserRunner] Stopping step idx:" << action.m_stepIndex << "(running:" << m_runnerSteps.count() << ")";
×
250
                    m_lastFunctionID = step->m_function->type() == Function::SceneType ? step->m_function->id() : Function::invalidId();
×
251
                    step->m_function->stop(functionParent());
×
252
                    m_runnerSteps.removeOne(step);
×
253
                    delete step;
×
254
                    stopped = true;
×
255
                }
256
            }
257

258
            if (stopped && m_runnerSteps.size() == 1)
×
259
            {
260
                ChaserRunnerStep *lastStep = m_runnerSteps.at(0);
×
261
                m_lastRunStepIdx = lastStep->m_index;
×
262
                emit currentStepChanged(m_lastRunStepIdx);
×
263
            }
264
        }
265
        break;
×
266

267
        // copy to pending action. Will be processed at the next write call
268
        default:
32✔
269
            m_pendingAction.m_stepIndex = action.m_stepIndex;
32✔
270
            m_pendingAction.m_masterIntensity = action.m_masterIntensity;
32✔
271
            m_pendingAction.m_stepIntensity = action.m_stepIntensity;
32✔
272
            m_pendingAction.m_fadeMode = action.m_fadeMode;
32✔
273
            m_pendingAction.m_action = action.m_action;
32✔
274
        break;
32✔
275
    }
276
}
38✔
277

278
void ChaserRunner::tap()
2✔
279
{
280
    if (uint(m_roundTime->elapsed()) >= (stepDuration(m_lastRunStepIdx) / 4))
2✔
281
        m_pendingAction.m_action = ChaserNextStep;
2✔
282
}
2✔
283

284
int ChaserRunner::currentStepIndex() const
65✔
285
{
286
    return m_lastRunStepIdx;
65✔
287
}
288

289
int ChaserRunner::runningStepsNumber() const
×
290
{
291
    return m_runnerSteps.count();
×
292
}
293

294
ChaserRunnerStep *ChaserRunner::currentRunningStep() const
×
295
{
296
    if (m_runnerSteps.count() > 0)
×
297
        return m_runnerSteps.at(0);
×
298
    return NULL;
×
299
}
300

301
int ChaserRunner::computeNextStep(int currentStep) const
19✔
302
{
303
    int nextStep = currentStep;
19✔
304

305
    if (m_chaser->runOrder() == Function::Random)
19✔
306
    {
307
        nextStep = m_order.indexOf(nextStep);
×
308
        if (nextStep == -1)
×
309
        {
310
            qDebug() << "[ChaserRunner] steps order not found";
×
311
            nextStep = currentStep;
×
312
        }
313
    }
314

315
    // Next step
316
    if (m_direction == Function::Forward)
19✔
317
    {
318
        nextStep++;
19✔
319
    }
320
    else
321
    {
322
        nextStep--;
×
323
    }
324

325
    if (nextStep < m_chaser->stepsCount() && nextStep >= 0)
19✔
326
    {
327
        if (m_chaser->runOrder() == Function::Random)
16✔
328
        {
329
            nextStep = randomStepIndex(nextStep);
×
330
        }
331
        return nextStep; // In the middle of steps. No need to go any further.
16✔
332
    }
333

334
    if (m_chaser->runOrder() == Function::SingleShot)
3✔
335
    {
336
        return -1; // Forward or Backward SingleShot has been completed.
×
337
    }
338
    else if (m_chaser->runOrder() == Function::Loop)
3✔
339
    {
340
        if (m_direction == Function::Forward)
3✔
341
        {
342
            if (nextStep >= m_chaser->stepsCount())
3✔
343
                nextStep = 0;
3✔
344
            else
345
                nextStep = m_chaser->stepsCount() - 1; // Used by CueList with manual prev
×
346
        }
347
        else // Backward
348
        {
349
            if (nextStep < 0)
×
350
                nextStep = m_chaser->stepsCount() - 1;
×
351
            else
352
                nextStep = 0;
×
353
        }
354
    }
355
    else if (m_chaser->runOrder() == Function::Random)
×
356
    {
357
        nextStep = randomStepIndex(nextStep);
×
358
    }
359
    else // Ping Pong
360
    {
361
        // Change direction, but don't run the first/last step twice.
362
        if (m_direction == Function::Forward)
×
363
        {
364
            nextStep = m_chaser->stepsCount() - 2;
×
365
        }
366
        else // Backwards
367
        {
368
            nextStep = 1;
×
369
        }
370

371
        // Make sure we don't go beyond limits.
372
        nextStep = CLAMP(nextStep, 0, m_chaser->stepsCount() - 1);
×
373
    }
374

375
    return nextStep;
3✔
376
}
377

378
void ChaserRunner::shuffle(QVector<int> & data)
30✔
379
{
380
   int n = data.size();
30✔
381
   for (int i = n - 1; i > 0; --i)
85✔
382
   {
383
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
384
      qSwap(data[i], data[qrand() % (i + 1)]);
385
#else
386
      qSwap(data[i], data[QRandomGenerator::global()->generate() % (i + 1)]);
55✔
387
#endif
388
   }
389
}
30✔
390

391
int ChaserRunner::randomStepIndex(int step) const
×
392
{
393
   if (m_chaser->runOrder() == Function::Random && step >= 0 && step < m_order.size())
×
394
       return m_order[step];
×
395

396
   return step;
×
397
}
398

399
void ChaserRunner::fillOrder()
30✔
400
{
401
    fillOrder(m_chaser->stepsCount());
30✔
402
}
30✔
403

404
void ChaserRunner::fillOrder(int size)
30✔
405
{
406
   m_order.resize(size);
30✔
407
   for (int i = 0; i < size; ++i)
111✔
408
       m_order[i] = i;
81✔
409

410
   shuffle(m_order);
30✔
411
}
30✔
412

413
/****************************************************************************
414
 * Intensity
415
 ****************************************************************************/
416

417
void ChaserRunner::adjustStepIntensity(qreal fraction, int requestedStepIndex, int fadeControl)
7✔
418
{
419
    fraction = CLAMP(fraction, qreal(0.0), qreal(1.0));
7✔
420

421
    //qDebug() << "Adjust intensity" << fraction << "step:" << requestedStepIndex << "fade:" << fadeControl;
422

423
    int stepIndex = requestedStepIndex;
7✔
424
    if (stepIndex == -1)
7✔
425
    {
426
        stepIndex = m_lastRunStepIdx;
7✔
427
        // store the intensity to be applied at the next step startup
428
        m_pendingAction.m_masterIntensity = fraction;
7✔
429
    }
430

431
    foreach (ChaserRunnerStep *step, m_runnerSteps)
7✔
432
    {
433
        if (stepIndex == step->m_index && step->m_function != NULL)
2✔
434
        {
435
            if (requestedStepIndex == -1 && step->m_function->type() == Function::SceneType)
2✔
436
            {
437
                Scene *scene = qobject_cast<Scene *>(step->m_function);
2✔
438
                scene->adjustAttribute(fraction, step->m_pIntensityOverrideId);
2✔
439
            }
440
            else
441
            {
442
                step->m_function->adjustAttribute(fraction, step->m_intensityOverrideId);
×
443
            }
444
            return;
2✔
445
        }
446
    }
447

448
    // No need to start a new step if it is not wanted
449
    if (requestedStepIndex == -1)
5✔
450
        return;
5✔
451

452
    // Don't start a step with an intensity of zero
453
    if (fraction == qreal(0.0))
×
454
        return;
×
455

456
    // not found ? It means we need to start a new step and crossfade kicks in !
457
    startNewStep(stepIndex, m_doc->masterTimer(), m_pendingAction.m_masterIntensity, fraction, fadeControl);
×
458
}
459

460
/****************************************************************************
461
 * Running
462
 ****************************************************************************/
463

464
void ChaserRunner::clearRunningList()
63✔
465
{
466
    // empty the running queue
467
    foreach (ChaserRunnerStep *step, m_runnerSteps)
129✔
468
    {
469
        if (step->m_function)
33✔
470
        {
471
            // restore the original Function fade out time
472
            step->m_function->setOverrideFadeOutSpeed(stepFadeOut(step->m_index));
33✔
473
            step->m_function->stop(functionParent(), m_chaser->type() == Function::SequenceType);
33✔
474
            m_lastFunctionID = step->m_function->type() == Function::SceneType ? step->m_function->id() : Function::invalidId();
33✔
475
        }
476
        delete step;
33✔
477
    }
478
    m_runnerSteps.clear();
63✔
479
}
63✔
480

481
void ChaserRunner::startNewStep(int index, MasterTimer *timer, qreal mIntensity, qreal sIntensity,
112✔
482
                                int fadeControl, quint32 elapsed)
483
{
484
    if (m_chaser == NULL || m_chaser->stepsCount() == 0)
112✔
485
        return;
×
486

487
    if (index < 0 || index >= m_chaser->stepsCount())
112✔
488
        index = 0; // fallback to the first step
×
489

490
    ChaserStep step(m_chaser->steps().at(index));
112✔
491
    Function *func = m_doc->function(step.fid);
112✔
492
    if (func == NULL)
112✔
493
        return;
×
494

495
    ChaserRunnerStep *newStep = new ChaserRunnerStep();
112✔
496
    newStep->m_index = index;
112✔
497

498
    // check if blending between Scenes is needed
499
    if (m_lastFunctionID != Function::invalidId() &&
203✔
500
        func->type() == Function::SceneType)
91✔
501
    {
502
        Scene *scene = qobject_cast<Scene *>(func);
91✔
503
        scene->setBlendFunctionID(m_lastFunctionID);
91✔
504
    }
505

506
    // this happens only during crossfades
507
    if (m_runnerSteps.count())
112✔
508
    {
509
        ChaserRunnerStep *lastStep = m_runnerSteps.last();
×
510
        if (lastStep->m_function &&
×
511
            lastStep->m_function->type() == Function::SceneType &&
×
512
            func->type() == Function::SceneType)
×
513
        {
514
            Scene *lastScene = qobject_cast<Scene *>(lastStep->m_function);
×
515
            lastScene->setBlendFunctionID(Function::invalidId());
×
516
            Scene *scene = qobject_cast<Scene *>(func);
×
517
            scene->setBlendFunctionID(lastStep->m_function->id());
×
518
        }
519
    }
520

521
    switch (fadeControl)
112✔
522
    {
523
        case Chaser::FromFunction:
106✔
524
            newStep->m_fadeIn = stepFadeIn(index);
106✔
525
            newStep->m_fadeOut = stepFadeOut(index);
106✔
526
        break;
106✔
527
        case Chaser::Blended:
×
528
            newStep->m_fadeIn = stepFadeIn(index);
×
529
            newStep->m_fadeOut = stepFadeOut(index);
×
530
        break;
×
531
        case Chaser::Crossfade:
×
532
            newStep->m_fadeIn = 0;
×
533
            newStep->m_fadeOut = 0;
×
534
        break;
×
535
        case Chaser::BlendedCrossfade:
×
536
            newStep->m_fadeIn = 0;
×
537
            newStep->m_fadeOut = 0;
×
538
        break;
×
539
    }
540

541
    newStep->m_duration = stepDuration(index);
112✔
542

543
    if (m_startOffset != 0)
112✔
544
        newStep->m_elapsed = m_startOffset + MasterTimer::tick();
×
545
    else
546
        newStep->m_elapsed = MasterTimer::tick() + elapsed;
112✔
547
    newStep->m_elapsedBeats = 0; //(newStep->m_elapsed / timer->beatTimeDuration()) * 1000;
112✔
548

549
    m_startOffset = 0;
112✔
550

551
    newStep->m_function = func;
112✔
552

553
    if (m_chaser->type() == Function::SequenceType)
112✔
554
    {
555
        Scene *s = qobject_cast<Scene*>(func);
×
556
        // blind == true is a workaround to reuse the same scene
557
        // without messing up the previous values
558
        for (int i = 0; i < step.values.count(); i++)
×
559
            s->setValue(step.values.at(i), true);
×
560
    }
561

562
    qDebug() << "[ChaserRunner] Starting step" << index << "fade in" << newStep->m_fadeIn
224✔
563
             << "fade out" << newStep->m_fadeOut << "intensity" << mIntensity
112✔
564
             << "fadeMode" << fadeControl;
112✔
565

566
    // Set intensity before starting the function. Otherwise the intensity
567
    // might momentarily jump too high.
568
    if (func->type() == Function::SceneType)
112✔
569
    {
570
        Scene *scene = qobject_cast<Scene *>(func);
112✔
571
        newStep->m_intensityOverrideId = func->requestAttributeOverride(Function::Intensity, sIntensity);
112✔
572
        newStep->m_pIntensityOverrideId = scene->requestAttributeOverride(Scene::ParentIntensity, mIntensity);
112✔
573
        qDebug() << "[ChaserRunner] Set step intensity:" << sIntensity << ", master:" << mIntensity;
112✔
574
    }
575
    else
576
    {
577
        newStep->m_intensityOverrideId = func->requestAttributeOverride(Function::Intensity, mIntensity * sIntensity);
×
578
    }
579

580
    // Start the fire up !
581
    func->start(timer, functionParent(), 0, newStep->m_fadeIn, newStep->m_fadeOut,
112✔
582
                func->defaultSpeed(), m_chaser->tempoType());
112✔
583
    m_runnerSteps.append(newStep);
112✔
584
    m_roundTime->restart();
112✔
585
}
586

587
int ChaserRunner::getNextStepIndex()
110✔
588
{
589
    int currentStepIndex = m_lastRunStepIdx;
110✔
590

591
    if (m_chaser->runOrder() == Function::Random)
110✔
592
    {
593
        currentStepIndex = m_order.indexOf(currentStepIndex);
×
594
        if (currentStepIndex == -1)
×
595
        {
596
            qDebug() << "[ChaserRunner] steps order not found";
×
597
            currentStepIndex = m_lastRunStepIdx;
×
598
        }
599
    }
600

601
    if (currentStepIndex == -1 &&
127✔
602
        m_chaser->direction() == Function::Backward)
17✔
603
            currentStepIndex = m_chaser->stepsCount();
6✔
604

605
    // Handle reverse Ping Pong at boundaries
606
    if (m_chaser->runOrder() == Function::PingPong &&
138✔
607
        m_pendingAction.m_action == ChaserPreviousStep)
28✔
608
    {
609
        if (currentStepIndex == 0)
×
610
            m_direction = Function::Backward;
×
611
        else if (currentStepIndex == m_chaser->stepsCount() - 1)
×
612
            m_direction = Function::Forward;
×
613
    }
614

615
    // Next step
616
    if (m_direction == Function::Forward)
110✔
617
    {
618
        // "Previous" for a forward chaser is -1
619
        if (m_pendingAction.m_action == ChaserPreviousStep)
76✔
620
            currentStepIndex--;
10✔
621
        else
622
            currentStepIndex++;
66✔
623
    }
624
    else
625
    {
626
        // "Previous" for a backward scene is +1
627
        if (m_pendingAction.m_action == ChaserPreviousStep)
34✔
628
            currentStepIndex++;
×
629
        else
630
            currentStepIndex--;
34✔
631
    }
632

633
    if (currentStepIndex < m_chaser->stepsCount() && currentStepIndex >= 0)
110✔
634
    {
635
        if (m_chaser->runOrder() == Function::Random)
80✔
636
        {
637
            currentStepIndex = randomStepIndex(currentStepIndex);
×
638
        }
639
        return currentStepIndex; // In the middle of steps. No need to go any further.
80✔
640
    }
641

642
    if (m_chaser->runOrder() == Function::SingleShot)
30✔
643
    {
644
        return -1; // Forward or Backward SingleShot has been completed.
4✔
645
    }
646
    else if (m_chaser->runOrder() == Function::Loop)
26✔
647
    {
648
        if (m_direction == Function::Forward)
18✔
649
        {
650
            if (currentStepIndex >= m_chaser->stepsCount())
16✔
651
                currentStepIndex = 0;
12✔
652
            else
653
                currentStepIndex = m_chaser->stepsCount() - 1; // Used by CueList with manual prev
4✔
654
        }
655
        else // Backward
656
        {
657
            if (currentStepIndex < 0)
2✔
658
                currentStepIndex = m_chaser->stepsCount() - 1;
2✔
659
            else
660
                currentStepIndex = 0;
×
661
        }
662
    }
663
    else if (m_chaser->runOrder() == Function::Random)
8✔
664
    {
665
        fillOrder();
×
666
        if (m_direction == Function::Forward)
×
667
        {
668
            if (currentStepIndex >= m_chaser->stepsCount())
×
669
                currentStepIndex = 0;
×
670
            else
671
                currentStepIndex = m_chaser->stepsCount() - 1; // Used by CueList with manual prev
×
672
        }
673
        else // Backward
674
        {
675
            if (currentStepIndex < 0)
×
676
                currentStepIndex = m_chaser->stepsCount() - 1;
×
677
            else
678
                currentStepIndex = 0;
×
679
        }
680
        // Don't run the same function 2 times in a row
681
        while (currentStepIndex < m_chaser->stepsCount()
×
682
                && randomStepIndex(currentStepIndex) == m_lastRunStepIdx)
×
683
            ++currentStepIndex;
×
684
        currentStepIndex = randomStepIndex(currentStepIndex);
×
685
    }
686
    else // Ping Pong
687
    {
688
        // Change direction, but don't run the first/last step twice.
689
        if (m_direction == Function::Forward)
8✔
690
        {
691
            currentStepIndex = m_chaser->stepsCount() - 2;
4✔
692
            m_direction = Function::Backward;
4✔
693
        }
694
        else // Backwards
695
        {
696
            currentStepIndex = 1;
4✔
697
            m_direction = Function::Forward;
4✔
698
        }
699

700
        // Make sure we don't go beyond limits.
701
        currentStepIndex = CLAMP(currentStepIndex, 0, m_chaser->stepsCount() - 1);
8✔
702
    }
703

704
    return currentStepIndex;
26✔
705
}
706

707
void ChaserRunner::setPause(bool enable, QList<Universe *> universes)
2✔
708
{
709
    // Nothing to do
710
    if (m_chaser->stepsCount() == 0)
2✔
711
        return;
×
712

713
    qDebug() << "[ChaserRunner] processing pause request:" << enable;
2✔
714

715
    foreach (ChaserRunnerStep *step, m_runnerSteps)
6✔
716
        step->m_function->setPause(enable);
2✔
717

718
    // there might be a Scene fading out, so request pause
719
    // to faders bound to the Scene ID running on universes
720
    Function *f = m_doc->function(m_lastFunctionID);
2✔
721
    if (f != NULL && f->type() == Function::SceneType)
2✔
722
    {
723
        foreach (Universe *universe, universes)
18✔
724
            universe->setFaderPause(m_lastFunctionID, enable);
8✔
725
    }
726
}
727

728
FunctionParent ChaserRunner::functionParent() const
224✔
729
{
730
    return FunctionParent(FunctionParent::Function, m_chaser->id());
224✔
731
}
732

733
bool ChaserRunner::write(MasterTimer *timer, QList<Universe *> universes)
356✔
734
{
735
    // Nothing to do
736
    if (m_chaser->stepsCount() == 0)
356✔
737
        return false;
1✔
738

739
    switch (m_pendingAction.m_action)
355✔
740
    {
741
        case ChaserNextStep:
19✔
742
        case ChaserPreviousStep:
743
            clearRunningList();
19✔
744
            // the actual action will be performed below, on startNewStep
745
        break;
19✔
746
        case ChaserSetStepIndex:
7✔
747
            if (m_pendingAction.m_stepIndex != -1)
7✔
748
            {
749
                clearRunningList();
6✔
750
                if (m_chaser->runOrder() == Function::Random)
6✔
751
                    m_lastRunStepIdx = randomStepIndex(m_pendingAction.m_stepIndex);
×
752
                else
753
                    m_lastRunStepIdx = m_pendingAction.m_stepIndex;
6✔
754

755
                qDebug() << "[ChaserRunner] Starting from step" << m_lastRunStepIdx << "@ offset" << m_startOffset;
6✔
756
                startNewStep(m_lastRunStepIdx, timer, m_pendingAction.m_masterIntensity,
6✔
757
                             m_pendingAction.m_stepIntensity, m_pendingAction.m_fadeMode);
758
                emit currentStepChanged(m_lastRunStepIdx);
6✔
759
            }
760
        break;
7✔
761
        case ChaserPauseRequest:
2✔
762
            setPause(m_pendingAction.m_fadeMode ? true : false, universes);
2✔
763
        break;
2✔
764
        default:
327✔
765
        break;
327✔
766
    }
767

768
    quint32 prevStepRoundElapsed = 0;
355✔
769

770
    foreach (ChaserRunnerStep *step, m_runnerSteps)
993✔
771
    {
772
        if (m_chaser->tempoType() == Function::Beats && timer->isBeat())
319✔
773
        {
774
            step->m_elapsedBeats += 1000;
×
775
            qDebug() << "[ChaserRunner] Function" << step->m_function->name() << "duration:" << step->m_duration << "beats:" << step->m_elapsedBeats;
×
776
        }
777

778
        if (step->m_duration != Function::infiniteSpeed() &&
539✔
779
            ((m_chaser->tempoType() == Function::Time && step->m_elapsed >= step->m_duration) ||
220✔
780
             (m_chaser->tempoType() == Function::Beats && step->m_elapsedBeats >= step->m_duration)))
146✔
781
        {
782
            if (step->m_duration != 0)
74✔
783
                prevStepRoundElapsed = step->m_elapsed % step->m_duration;
29✔
784

785
            m_lastFunctionID = step->m_function->type() == Function::SceneType ? step->m_function->id() : Function::invalidId();
74✔
786
            step->m_function->stop(functionParent(), m_chaser->type() == Function::SequenceType);
74✔
787
            m_runnerSteps.removeOne(step);
74✔
788
            delete step;
74✔
789
        }
790
        else
791
        {
792
            if (step->m_elapsed < UINT_MAX)
245✔
793
                step->m_elapsed += MasterTimer::tick();
245✔
794

795
            // When the speeds of the chaser change, they need to be updated to the lower
796
            // level (only current function) as well. Otherwise the new speeds would take
797
            // effect only on the next step change.
798
            if (m_updateOverrideSpeeds == true)
245✔
799
            {
800
                m_updateOverrideSpeeds = false;
×
801
                if (step->m_function != NULL)
×
802
                {
803
                    step->m_function->setOverrideFadeInSpeed(step->m_fadeIn);
×
804
                    step->m_function->setOverrideFadeOutSpeed(step->m_fadeOut);
×
805
                }
806
            }
807
        }
808
    }
809

810
    if (m_runnerSteps.isEmpty())
355✔
811
    {
812
        m_lastRunStepIdx = getNextStepIndex();
110✔
813
        if (m_lastRunStepIdx != -1)
110✔
814
        {
815
            int blend = m_pendingAction.m_action == ChaserNoAction ? Chaser::FromFunction : m_pendingAction.m_fadeMode;
106✔
816

817
            startNewStep(m_lastRunStepIdx, timer, m_pendingAction.m_masterIntensity,
106✔
818
                         m_pendingAction.m_stepIntensity, blend, prevStepRoundElapsed);
819
            emit currentStepChanged(m_lastRunStepIdx);
106✔
820
        }
821
        else
822
        {
823
            m_pendingAction.m_action = ChaserNoAction;
4✔
824
            return false;
4✔
825
        }
826
    }
827

828
    m_pendingAction.m_action = ChaserNoAction;
351✔
829
    return true;
351✔
830
}
831

832
void ChaserRunner::postRun(MasterTimer *timer, QList<Universe*> universes)
8✔
833
{
834
    Q_UNUSED(universes);
835
    Q_UNUSED(timer);
836

837
    qDebug() << Q_FUNC_INFO;
8✔
838
    clearRunningList();
8✔
839
}
8✔
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