void CueStack::insertStartValue(FadeChannel& fc, const QList<Universe *> ua) { qDebug() << Q_FUNC_INFO; const QHash <FadeChannel,FadeChannel>& channels(m_fader->channels()); if (channels.contains(fc) == true) { // GenericFader contains the channel so grab its current // value as the new starting value to get a smoother fade FadeChannel existing = channels[fc]; fc.setStart(existing.current()); fc.setCurrent(fc.start()); } else { // GenericFader didn't have the channel. Grab the starting value from UniverseArray. quint32 uni = fc.universe(); if (uni != Universe::invalid() && uni < (quint32)ua.count()) { if (fc.group(doc()) != QLCChannel::Intensity) fc.setStart(ua[uni]->preGMValues()[fc.address()]); else fc.setStart(0); // HTP channels must start at zero } fc.setCurrent(fc.start()); } }
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 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 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 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 GenericFader_Test::addRemove() { GenericFader fader(m_doc); FadeChannel fc; fc.setFixture(0); fc.setChannel(0); FadeChannel wrong; fc.setFixture(0); QCOMPARE(fader.m_channels.count(), 0); QVERIFY(fader.m_channels.contains(fc) == false); fader.add(fc); QVERIFY(fader.m_channels.contains(fc) == true); QCOMPARE(fader.m_channels.count(), 1); fader.remove(wrong); QVERIFY(fader.m_channels.contains(fc) == true); QCOMPARE(fader.m_channels.count(), 1); fader.remove(fc); QVERIFY(fader.m_channels.contains(fc) == false); QCOMPARE(fader.m_channels.count(), 0); fc.setChannel(0); fader.add(fc); QVERIFY(fader.m_channels.contains(fc) == true); fc.setChannel(1); fader.add(fc); QVERIFY(fader.m_channels.contains(fc) == true); fc.setChannel(2); fader.add(fc); QVERIFY(fader.m_channels.contains(fc) == true); QCOMPARE(fader.m_channels.count(), 3); fader.removeAll(); QCOMPARE(fader.m_channels.count(), 0); fc.setFixture(0); fc.setChannel(0); fc.setTarget(127); fader.add(fc); QCOMPARE(fader.m_channels.size(), 1); QCOMPARE(fader.m_channels[fc].target(), uchar(127)); fc.setTarget(63); fader.add(fc); QCOMPARE(fader.m_channels.size(), 1); QCOMPARE(fader.m_channels[fc].target(), uchar(63)); fc.setCurrent(63); fader.add(fc); QCOMPARE(fader.m_channels.size(), 1); QCOMPARE(fader.m_channels[fc].target(), uchar(63)); }
void FadeChannel_Test::current() { FadeChannel fch; QCOMPARE(fch.current(), uchar(0)); for (uint i = 0; i <= 255; i++) { fch.setCurrent(i); QCOMPARE(fch.current(), uchar(i)); QCOMPARE(fch.current(0.4), uchar(floor((qreal(i) * 0.4) + 0.5))); } }
void CueStack_Test::insertStartValue() { QList<Universe*> ua; ua.append(new Universe(0, new GrandMaster())); ua.at(0)->setChannelCapability(0, QLCChannel::Pan); CueStack cs(m_doc); cs.preRun(); FadeChannel fc; fc.setChannel(0); fc.setStart(0); fc.setTarget(255); fc.setCurrent(127); cs.m_fader->add(fc); fc.setTarget(64); cs.insertStartValue(fc, ua); QCOMPARE(fc.start(), uchar(127)); QCOMPARE(fc.current(), uchar(127)); cs.m_fader->remove(fc); // HTP channel in universes ua[0]->write(0, 192); cs.insertStartValue(fc, ua); QCOMPARE(fc.start(), uchar(0)); QCOMPARE(fc.current(), uchar(0)); QLCFixtureDef* def = m_doc->fixtureDefCache()->fixtureDef("Futurelight", "DJScan250"); QVERIFY(def != NULL); QLCFixtureMode* mode = def->modes().first(); QVERIFY(mode != NULL); Fixture* fxi = new Fixture(m_doc); fxi->setFixtureDefinition(def, mode); fxi->setName("Test Scanner"); fxi->setAddress(0); fxi->setUniverse(0); m_doc->addFixture(fxi); // LTP channel (Pan) in universes ua[0]->write(0, 192); cs.insertStartValue(fc, ua); QCOMPARE(fc.start(), uchar(192)); QCOMPARE(fc.current(), uchar(192)); MasterTimer mt(m_doc); cs.postRun(&mt); }
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); }
QMap <quint32,FadeChannel> ChaserRunner::createFadeChannels(const UniverseArray* universes, QMap <quint32,FadeChannel>& zeroChannels) const { QMap <quint32,FadeChannel> map; if (m_currentStep >= m_steps.size() || m_currentStep < 0) return map; Scene* scene = qobject_cast<Scene*> (m_steps.at(m_currentStep)); Q_ASSERT(scene != NULL); // Put all current channels to a map of channels that will be faded to zero. // If the same channels are added to the new channel map, they are removed // from this zero map. zeroChannels = m_channelMap; QListIterator <SceneValue> it(scene->values()); while (it.hasNext() == true) { SceneValue value(it.next()); Fixture* fxi = m_doc->fixture(value.fxi); if (fxi == NULL || fxi->channel(value.channel) == NULL) continue; FadeChannel channel; channel.setAddress(fxi->universeAddress() + value.channel); channel.setGroup(fxi->channel(value.channel)->group()); channel.setTarget(value.value); // Get starting value from universes. For HTP channels it's always 0. channel.setStart(uchar(universes->preGMValues()[channel.address()])); // Transfer last step's current value to current step's starting value. if (m_channelMap.contains(channel.address()) == true) channel.setStart(m_channelMap[channel.address()].current()); channel.setCurrent(channel.start()); // Append the channel to the channel map map[channel.address()] = channel; // Remove the channel from a map of to-be-zeroed channels since now it // has a new value to fade to. zeroChannels.remove(channel.address()); } // All channels that were present in the previous step but are not present // in the current step will go through this zeroing process. QMutableMapIterator <quint32,FadeChannel> zit(zeroChannels); while (zit.hasNext() == true) { zit.next(); FadeChannel& channel(zit.value()); if (channel.current() == 0 || channel.group() != QLCChannel::Intensity) { // Remove all non-HTP channels and such HTP channels that are // already at zero. There's nothing to do for them. zit.remove(); } else { // This HTP channel was present in the previous step, but is absent // in the current. It's nicer that we fade it back to zero, rather // than just let it drop straight to zero. channel.setStart(channel.current()); channel.setTarget(0); } } return map; }
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); } }