void EFXFixture::start(MasterTimer* timer, QList<Universe *> universes) { Q_UNUSED(universes); Q_UNUSED(timer); if (fadeIntensity() > 0 && m_started == false) { Fixture* fxi = doc()->fixture(head().fxi); Q_ASSERT(fxi != NULL); if (fxi->masterIntensityChannel(head().head) != QLCChannel::invalid()) { FadeChannel fc; fc.setFixture(doc(), head().fxi); fc.setChannel(fxi->masterIntensityChannel(head().head)); if (m_parent->overrideFadeInSpeed() != Function::defaultSpeed()) fc.setFadeTime(m_parent->overrideFadeInSpeed()); else fc.setFadeTime(m_parent->fadeInSpeed()); fc.setStart(0); fc.setCurrent(fc.start()); // Don't use intensity() multiplier because EFX's GenericFader takes care of that fc.setTarget(fadeIntensity()); // Fade channel up with EFX's own GenericFader to allow manual intensity control m_parent->m_fader->add(fc); } } m_started = true; }
void EFXFixture::stop(MasterTimer* timer, QList<Universe *> universes) { Q_UNUSED(universes); if (fadeIntensity() > 0 && m_started == true) { Fixture* fxi = doc()->fixture(head().fxi); Q_ASSERT(fxi != NULL); if (fxi->masterIntensityChannel(head().head) != QLCChannel::invalid()) { FadeChannel fc; fc.setFixture(doc(), head().fxi); fc.setChannel(fxi->masterIntensityChannel(head().head)); if (m_parent->overrideFadeOutSpeed() != Function::defaultSpeed()) fc.setFadeTime(m_parent->overrideFadeOutSpeed()); else fc.setFadeTime(m_parent->fadeOutSpeed()); fc.setStart(uchar(floor((float(fadeIntensity()) * intensity()) + 0.5))); fc.setCurrent(fc.start()); fc.setTarget(0); // Give zero-fading to MasterTimer because EFX will stop after this call timer->faderAdd(fc); // Remove the previously up-faded channel from EFX's internal fader to allow // MasterTimer's fader take HTP precedence. m_parent->m_fader->remove(fc); } } m_started = false; }
void RGBMatrix::insertStartValues(FadeChannel& fc) const { Q_ASSERT(m_fader != NULL); // To create a nice and smooth fade, get the starting value from // m_fader's existing FadeChannel (if any). Otherwise just assume // we're starting from zero. if (m_fader->channels().contains(fc) == true) { FadeChannel old = m_fader->channels()[fc]; fc.setCurrent(old.current()); fc.setStart(old.current()); } else { fc.setCurrent(0); fc.setStart(0); } // The channel is not ready yet fc.setReady(false); // Fade in speed is used for all non-zero targets if (fc.target() == 0) fc.setFadeTime(fadeOutSpeed()); else fc.setFadeTime(fadeInSpeed()); }
void RGBMatrix::insertStartValues(FadeChannel& fc, uint fadeTime) const { Q_ASSERT(m_fader != NULL); // To create a nice and smooth fade, get the starting value from // m_fader's existing FadeChannel (if any). Otherwise just assume // we're starting from zero. QHash <FadeChannel,FadeChannel>::const_iterator oldChannelIterator = m_fader->channels().find(fc); if (oldChannelIterator != m_fader->channels().end()) { FadeChannel old = oldChannelIterator.value(); fc.setCurrent(old.current()); fc.setStart(old.current()); } else { fc.setCurrent(0); fc.setStart(0); } // The channel is not ready yet fc.setReady(false); // Fade in speed is used for all non-zero targets if (fc.target() == 0) fc.setFadeTime(fadeOutSpeed()); else { fc.setFadeTime(fadeTime); } }
void CueStack::switchCue(int from, int to, const QList<Universe *> ua) { qDebug() << Q_FUNC_INFO; Cue newCue; Cue oldCue; m_mutex.lock(); if (to >= 0 && to < m_cues.size()) newCue = m_cues[to]; if (from >= 0 && from < m_cues.size()) oldCue = m_cues[from]; m_mutex.unlock(); // Fade out the HTP channels of the previous cue QHashIterator <uint,uchar> oldit(oldCue.values()); while (oldit.hasNext() == true) { oldit.next(); FadeChannel fc; fc.setFixture(doc(), Fixture::invalidId()); fc.setChannel(oldit.key()); if (fc.group(doc()) == QLCChannel::Intensity) { fc.setElapsed(0); fc.setReady(false); fc.setTarget(0); fc.setFadeTime(oldCue.fadeOutSpeed()); insertStartValue(fc, ua); m_fader->add(fc); } } // Fade in all channels of the new cue QHashIterator <uint,uchar> newit(newCue.values()); while (newit.hasNext() == true) { newit.next(); FadeChannel fc; fc.setFixture(doc(), Fixture::invalidId()); fc.setChannel(newit.key()); fc.setTarget(newit.value()); fc.setElapsed(0); fc.setReady(false); fc.setFadeTime(newCue.fadeInSpeed()); insertStartValue(fc, ua); m_fader->add(fc); } }
void RGBMatrix::postRun(MasterTimer* timer, QList<Universe *> universes) { if (m_fader != NULL) { QHashIterator <FadeChannel,FadeChannel> it(m_fader->channels()); while (it.hasNext() == true) { it.next(); FadeChannel fc = it.value(); // fade out only intensity channels if (fc.group(doc()) != QLCChannel::Intensity) continue; bool canFade = true; Fixture *fixture = doc()->fixture(fc.fixture()); if (fixture != NULL) canFade = fixture->channelCanFade(fc.channel()); fc.setStart(fc.current(getAttributeValue(Intensity))); fc.setCurrent(fc.current(getAttributeValue(Intensity))); fc.setElapsed(0); fc.setReady(false); if (canFade == false) { fc.setFadeTime(0); fc.setTarget(fc.current(getAttributeValue(Intensity))); } else { if (overrideFadeOutSpeed() == defaultSpeed()) fc.setFadeTime(fadeOutSpeed()); else fc.setFadeTime(overrideFadeOutSpeed()); fc.setTarget(0); } timer->faderAdd(fc); } delete m_fader; m_fader = NULL; } { QMutexLocker algorithmLocker(&m_algorithmMutex); if (m_algorithm != NULL) m_algorithm->postRun(); } Function::postRun(timer, universes); }
void CueStack::postRun(MasterTimer* timer) { qDebug() << Q_FUNC_INFO; Q_ASSERT(timer != NULL); Q_ASSERT(m_fader != NULL); // Bounce all intensity channels to MasterTimer's fader for zeroing QHashIterator <FadeChannel,FadeChannel> it(m_fader->channels()); while (it.hasNext() == true) { it.next(); FadeChannel fc = it.value(); if (fc.group(doc()) == QLCChannel::Intensity) { fc.setStart(fc.current(intensity())); fc.setTarget(0); fc.setElapsed(0); fc.setReady(false); fc.setFadeTime(fadeOutSpeed()); timer->fader()->add(fc); } } m_currentIndex = -1; delete m_fader; m_fader = NULL; emit currentCueChanged(m_currentIndex); emit stopped(); }
void FadeChannel_Test::fadeTime() { FadeChannel ch; QVERIFY(ch.fadeTime() == 0); ch.setFadeTime(50); QVERIFY(ch.fadeTime() == 50); }
void GenericFader_Test::writeLoop() { UniverseArray ua(512); GenericFader fader(m_doc); FadeChannel fc; fc.setFixture(0); fc.setChannel(5); fc.setStart(0); fc.setTarget(250); fc.setFadeTime(1000); fader.add(fc); QCOMPARE(ua.preGMValues()[15], (char) 0); int expected = 0; for (int i = MasterTimer::tick(); i <= 1000; i += MasterTimer::tick()) { ua.zeroIntensityChannels(); fader.write(&ua); int actual = uchar(ua.preGMValues()[15]); expected += 5; QCOMPARE(actual, expected); } }
void GenericFader_Test::writeZeroFade() { UniverseArray ua(512); GenericFader fader(m_doc); FadeChannel fc; fc.setFixture(0); fc.setChannel(5); fc.setStart(0); fc.setTarget(255); fc.setFadeTime(0); fader.add(fc); QCOMPARE(ua.preGMValues()[15], (char) 0); fader.write(&ua); QCOMPARE(ua.preGMValues()[15], (char) 255); }
void GenericFader_Test::adjustIntensity() { UniverseArray ua(512); GenericFader fader(m_doc); FadeChannel fc; // HTP channel fc.setFixture(0); fc.setChannel(5); fc.setStart(0); fc.setTarget(250); fc.setFadeTime(1000); fader.add(fc); // LTP channel fc.setChannel(0); fader.add(fc); qreal intensity = 0.5; fader.adjustIntensity(intensity); QCOMPARE(fader.intensity(), intensity); int expected = 0; for (int i = MasterTimer::tick(); i <= 1000; i += MasterTimer::tick()) { ua.zeroIntensityChannels(); fader.write(&ua); expected += 5; // GenericFader should apply intensity only to HTP channels int actual = uchar(ua.preGMValues()[15]); int expectedWithIntensity = floor((qreal(expected) * intensity) + 0.5); QVERIFY(actual == expectedWithIntensity); // No intensity adjustment on LTP channels actual = uchar(ua.preGMValues()[10]); QVERIFY(actual == expected); } }
void FadeChannel_Test::nextStep() { FadeChannel fc; fc.setStart(0); fc.setTarget(250); fc.setFadeTime(1000); for (int i = 5; i < 250; i += 5) { int value = fc.nextStep(MasterTimer::tick()); QCOMPARE(value, i); } fc.setCurrent(0); fc.setReady(false); fc.setFadeTime(0); fc.setElapsed(0); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(250)); fc.setCurrent(0); fc.setReady(false); fc.setFadeTime(MasterTimer::tick() / 5); fc.setElapsed(0); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(250)); fc.setCurrent(0); fc.setReady(false); fc.setFadeTime(1 * MasterTimer::tick()); fc.setElapsed(0); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(250)); fc.setCurrent(0); fc.setReady(false); fc.setFadeTime(2 * MasterTimer::tick()); fc.setElapsed(0); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(125)); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(250)); fc.setCurrent(0); fc.setReady(false); fc.setFadeTime(5 * MasterTimer::tick()); fc.setElapsed(0); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(50)); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(100)); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(150)); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(200)); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(250)); // Maximum elapsed() reached fc.setCurrent(0); fc.setTarget(255); fc.setReady(false); fc.setElapsed(UINT_MAX); fc.setFadeTime(5 * MasterTimer::tick()); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), UINT_MAX); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), UINT_MAX); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), UINT_MAX); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), UINT_MAX); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), UINT_MAX); // Channel marked as ready fc.setReady(true); fc.setElapsed(0); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), MasterTimer::tick() * 1); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), MasterTimer::tick() * 2); QCOMPARE(fc.nextStep(MasterTimer::tick()), uchar(255)); QCOMPARE(fc.elapsed(), MasterTimer::tick() * 3); }
QString Script::handleSetFixture(const QList<QStringList>& tokens, QList<Universe *> universes) { qDebug() << Q_FUNC_INFO; if (tokens.size() > 4) return QString("Too many arguments"); bool ok = false; quint32 id = 0; quint32 ch = 0; uchar value = 0; double time = 0; id = tokens[0][1].toUInt(&ok); if (ok == false) return QString("Invalid fixture (ID: %1)").arg(tokens[0][1]); for (int i = 1; i < tokens.size(); i++) { QStringList list = tokens[i]; list[0] = list[0].toLower().trimmed(); if (list.size() == 2) { ok = false; if (list[0] == "val" || list[0] == "value") value = uchar(list[1].toUInt(&ok)); else if (list[0] == "ch" || list[0] == "channel") ch = list[1].toUInt(&ok); else if (list[0] == "time") time = list[1].toDouble(&ok); else return QString("Unrecognized keyword: %1").arg(list[0]); if (ok == false) return QString("Invalid value (%1) for keyword: %2").arg(list[1]).arg(list[0]); } } Doc* doc = qobject_cast<Doc*> (parent()); Q_ASSERT(doc != NULL); Fixture* fxi = doc->fixture(id); if (fxi != NULL) { if (ch < fxi->channels()) { int address = fxi->address() + ch; if (address < 512) { GenericFader* gf = fader(); Q_ASSERT(gf != NULL); FadeChannel fc; fc.setFixture(doc, fxi->id()); fc.setChannel(ch); fc.setTarget(value); fc.setFadeTime(time); // If the script has used the channel previously, it might still be in // the bowels of GenericFader so get the starting value from there. // Otherwise get it from universes (HTP channels are always 0 then). quint32 uni = fc.universe(); if (gf->channels().contains(fc) == true) fc.setStart(gf->channels()[fc].current()); else fc.setStart(universes[uni]->preGMValue(address)); fc.setCurrent(fc.start()); gf->add(fc); return QString(); } else { return QString("Invalid address: %1").arg(address); } } else { return QString("Fixture (%1) has no channel number %2").arg(fxi->name()).arg(ch); } } else { return QString("No such fixture (ID: %1)").arg(id); } }