Skip to content

Commit

Permalink
engine: implement proper 16bit fading support
Browse files Browse the repository at this point in the history
  • Loading branch information
mcallegari committed Jan 8, 2024
1 parent aa9da43 commit e43706e
Show file tree
Hide file tree
Showing 9 changed files with 350 additions and 235 deletions.
139 changes: 91 additions & 48 deletions engine/src/fadechannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <QDebug>
#include <cmath>

#include "qlcfixturemode.h"
#include "fadechannel.h"
#include "qlcchannel.h"
#include "universe.h"
Expand All @@ -29,8 +30,9 @@ FadeChannel::FadeChannel()
: m_flags(0)
, m_fixture(Fixture::invalidId())
, m_universe(Universe::invalid())
, m_channel(QLCChannel::invalid())
, m_primaryChannel(QLCChannel::invalid())
, m_address(QLCChannel::invalid())
, m_channelRef(NULL)
, m_start(0)
, m_target(0)
, m_current(0)
Expand All @@ -44,8 +46,10 @@ FadeChannel::FadeChannel(const FadeChannel& ch)
: m_flags(ch.m_flags)
, m_fixture(ch.m_fixture)
, m_universe(ch.m_universe)
, m_channel(ch.m_channel)
, m_primaryChannel(ch.m_primaryChannel)
, m_channels(ch.m_channels)
, m_address(ch.m_address)
, m_channelRef(ch.m_channelRef)
, m_start(ch.m_start)
, m_target(ch.m_target)
, m_current(ch.m_current)
Expand All @@ -59,14 +63,15 @@ FadeChannel::FadeChannel(const FadeChannel& ch)
FadeChannel::FadeChannel(const Doc *doc, quint32 fxi, quint32 channel)
: m_flags(0)
, m_fixture(fxi)
, m_channel(channel)
, m_channelRef(NULL)
, m_start(0)
, m_target(0)
, m_current(0)
, m_ready(false)
, m_fadeTime(0)
, m_elapsed(0)
{
m_channels.append(channel);
autoDetect(doc);
}

Expand All @@ -81,7 +86,9 @@ FadeChannel &FadeChannel::operator=(const FadeChannel &fc)
m_flags = fc.m_flags;
m_fixture = fc.m_fixture;
m_universe = fc.m_universe;
m_channel = fc.m_channel;
m_primaryChannel = fc.m_primaryChannel;
m_channels = fc.m_channels;
m_channelRef = fc.m_channelRef;
m_address = fc.m_address;
m_start = fc.m_start;
m_target = fc.m_target;
Expand All @@ -96,7 +103,7 @@ FadeChannel &FadeChannel::operator=(const FadeChannel &fc)

bool FadeChannel::operator==(const FadeChannel& ch) const
{
return (m_fixture == ch.m_fixture && m_channel == ch.m_channel);
return (m_fixture == ch.m_fixture && channel() == ch.channel());
}

int FadeChannel::flags() const
Expand Down Expand Up @@ -143,54 +150,48 @@ void FadeChannel::autoDetect(const Doc *doc)
}
else
{
QLCFixtureMode *mode = fixture->fixtureMode();
m_universe = fixture->universe();
m_address = fixture->address();

// if the fixture was invalid at the beginning of this method
// it means channel was an absolute address, so, fix it
if (fixtureWasInvalid)
m_channel -= fixture->address();
m_channels[0] -= fixture->address();

const QLCChannel *channel = fixture->channel(m_channel);
quint32 chIndex = channel();
m_primaryChannel = mode ? mode->primaryChannel(chIndex) : QLCChannel::invalid();
m_channelRef = fixture->channel(chIndex);

// non existing channel within fixture
if (channel == NULL)
if (m_channelRef == NULL)
{
addFlag(FadeChannel::HTP | FadeChannel::Intensity | FadeChannel::CanFade);
return;
}

// autodetect the channel type
if (fixture->channelCanFade(m_channel))
if (fixture->channelCanFade(chIndex))
addFlag(FadeChannel::CanFade);

if (channel != NULL && channel->group() == QLCChannel::Intensity)
if (m_channelRef != NULL && m_channelRef->group() == QLCChannel::Intensity)
addFlag(FadeChannel::HTP | FadeChannel::Intensity);
else
addFlag(FadeChannel::LTP);

if (fixture->forcedHTPChannels().contains(int(m_channel)))
if (fixture->forcedHTPChannels().contains(int(chIndex)))
{
removeFlag(FadeChannel::LTP);
addFlag(FadeChannel::HTP);
}
else if (fixture->forcedLTPChannels().contains(int(m_channel)))
else if (fixture->forcedLTPChannels().contains(int(chIndex)))
{
removeFlag(FadeChannel::HTP);
addFlag(FadeChannel::LTP);
}

if (channel != NULL && channel->controlByte() == QLCChannel::LSB)
addFlag(FadeChannel::Fine);
}
}

void FadeChannel::setFixture(const Doc *doc, quint32 id)
{
m_fixture = id;
autoDetect(doc);
}

quint32 FadeChannel::fixture() const
{
return m_fixture;
Expand All @@ -203,15 +204,33 @@ quint32 FadeChannel::universe() const
return m_universe;
}

void FadeChannel::setChannel(const Doc *doc, quint32 num)
void FadeChannel::addChannel(quint32 num)
{
m_channel = num;
autoDetect(doc);
m_channels.append(num);
qDebug() << "[FadeChannel] ADD channel" << num << "count:" << m_channels.count();

// on secondary channel, shift values 8bits up
if (m_channels.count() > 1)
{
m_start = m_start << 8;
m_target = m_target << 8;
m_current = m_current << 8;
}
}

int FadeChannel::channelCount()
{
return m_channels.count();
}

quint32 FadeChannel::channel() const
{
return m_channel;
return m_channels.isEmpty() ? QLCChannel::invalid() : m_channels.first();
}

quint32 FadeChannel::primaryChannel() const
{
return m_primaryChannel;
}

quint32 FadeChannel::address() const
Expand All @@ -224,42 +243,68 @@ quint32 FadeChannel::address() const

quint32 FadeChannel::addressInUniverse() const
{
return address() % UNIVERSE_SIZE;
quint32 addr = address();
if (addr == QLCChannel::invalid())
return QLCChannel::invalid();

return addr % UNIVERSE_SIZE;
}

void FadeChannel::setStart(uchar value)
/************************************************************************
* Values
************************************************************************/

void FadeChannel::setStart(uchar value, int index)
{
m_start = value;
if (m_channels.count() == 1)
m_start = value;
else
((uchar *)&m_start)[index] = value;
}

uchar FadeChannel::start() const
uchar FadeChannel::start(int index) const
{
return uchar(m_start);
if (index >= m_channels.count())
return uchar(m_start);

return uchar(m_start >> (8 * (m_channels.count() - 1 - index)));
}

void FadeChannel::setTarget(uchar value)
void FadeChannel::setTarget(uchar value, int index)
{
m_target = value;
if (m_channels.count() == 1)
m_target = value;
else
((uchar *)&m_target)[index] = value;
}

uchar FadeChannel::target() const
uchar FadeChannel::target(int index) const
{
return uchar(m_target);
if (index >= m_channels.count())
return uchar(m_target);

return uchar(m_target >> (8 * (m_channels.count() - 1 - index)));
}

void FadeChannel::setCurrent(uchar value)
void FadeChannel::setCurrent(uchar value, int index)
{
m_current = value;
if (m_channels.count() == 1)
m_current = value;
else
((uchar *)&m_current)[index] = value;
}

uchar FadeChannel::current() const
uchar FadeChannel::current(int index) const
{
return uchar(m_current);
if (index >= m_channels.count())
return uchar(m_current);

return uchar(m_current >> (8 * (m_channels.count() - 1 - index)));
}

uchar FadeChannel::current(qreal intensity) const
uchar FadeChannel::current(qreal intensity, int index) const
{
return uchar(floor((qreal(m_current) * intensity) + 0.5));
return uchar(floor((qreal(current(index)) * intensity) + 0.5));
}

void FadeChannel::setReady(bool rdy)
Expand Down Expand Up @@ -301,6 +346,7 @@ uchar FadeChannel::nextStep(uint ms)
{
if (elapsed() < UINT_MAX)
setElapsed(elapsed() + ms);

return calculateCurrent(fadeTime(), elapsed());
}

Expand All @@ -319,14 +365,11 @@ uchar FadeChannel::calculateCurrent(uint fadeTime, uint elapsedTime)
}
else
{
// 16 bit fading works as long as MSB and LSB channels
// are targeting the same value. E.g. Red and Red Fine both at 158
float val = (float(m_target - m_start) * (float(elapsedTime) / float(fadeTime))) + float(m_start);
long rval = lrintf(val * 256);
if (m_flags & Fine)
m_current = rval & 0xff;
else
m_current = rval / 256;
bool rampUp = m_target > m_start ? true : false;
m_current = rampUp ? m_target - m_start : m_start - m_target;
m_current = m_current * (qreal(elapsedTime) / qreal(fadeTime));
m_current = rampUp ? m_start + m_current : m_start - m_current;
//qDebug() << "channel" << channel() << "start" << m_start << "target" << m_target << "current" << m_current << "fade" << fadeTime << "elapsed" << elapsedTime ;
}

return uchar(m_current);
Expand Down
74 changes: 41 additions & 33 deletions engine/src/fadechannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,59 +81,72 @@ class FadeChannel
void addFlag(int flag);
void removeFlag(int flag);

protected:
void autoDetect(const Doc *doc);

private:
/** Bitmask including the channel type
* and, if needed, more flags */
int m_flags;

/************************************************************************
* Values
************************************************************************/
public:
/** Set the Fixture that is being controlled. */
void setFixture(const Doc *doc, quint32 id);

/** Get the Fixture that is being controlled. */
quint32 fixture() const;

/** Get the universe of the Fixture that is being controlled. */
quint32 universe() const;

/** Set channel within the Fixture. */
void setChannel(const Doc* doc, quint32 num);
/** Add another channel to be handled by this fader */
void addChannel(quint32 num);

/** Get channel within the Fixture. */
/** Get the number of channels handled by this fader */
int channelCount();

/** Get the first (or master) channel handled by this fader */
quint32 channel() const;

/** Get (if present) the index of the primary channel this fader relate to */
quint32 primaryChannel() const;

/** Get the absolute address for this channel. */
quint32 address() const;

/** Get the absolute address in its universe for this channel. */
quint32 addressInUniverse() const;

protected:
void autoDetect(const Doc *doc);

private:
/** Bitmask representing all the channel specificities
* such as fading, overriding, flashing, etc. */
int m_flags;

quint32 m_fixture;
quint32 m_universe;
quint32 m_primaryChannel;
QVector<quint32> m_channels;
quint32 m_address;

/** Cache channel reference for faster lookup */
const QLCChannel *m_channelRef;

/************************************************************************
* Values
************************************************************************/
public:

/** Set starting value. */
void setStart(uchar value);
void setStart(uchar value, int index = 0);

/** Get starting value. */
uchar start() const;
uchar start(int index = 0) const;

/** Set target value. */
void setTarget(uchar value);
void setTarget(uchar value, int index = 0);

/** Get target value. */
uchar target() const;
uchar target(int index = 0) const;

/** Set the current value. */
void setCurrent(uchar value);
void setCurrent(uchar value, int index = 0);

/** Get the current value. */
uchar current() const;
uchar current(int index = 0) const;

/** Get the current value, modified by $intensity. */
uchar current(qreal intensity) const;
uchar current(qreal intensity, int index = 0) const;

/** Mark this channel as ready (useful for writing LTP values only once). */
void setReady(bool rdy);
Expand Down Expand Up @@ -177,14 +190,9 @@ class FadeChannel
uchar calculateCurrent(uint fadeTime, uint elapsedTime);

private:
quint32 m_fixture;
quint32 m_universe;
quint32 m_channel;
quint32 m_address;

int m_start;
int m_target;
int m_current;
quint32 m_start;
quint32 m_target;
quint32 m_current;
bool m_ready;

uint m_fadeTime;
Expand Down

0 comments on commit e43706e

Please sign in to comment.