mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Fix Effects and refactor Smoothing (#1442)
This commit is contained in:
parent
62829d9bf8
commit
f32db90c12
@ -211,6 +211,7 @@
|
|||||||
"dashboard_newsbox_readmore": "Read more",
|
"dashboard_newsbox_readmore": "Read more",
|
||||||
"dashboard_newsbox_visitblog": "Visit Hyperion-Blog",
|
"dashboard_newsbox_visitblog": "Visit Hyperion-Blog",
|
||||||
"edt_append_degree": "°",
|
"edt_append_degree": "°",
|
||||||
|
"edt_append_frames": "frames",
|
||||||
"edt_append_hz": "Hz",
|
"edt_append_hz": "Hz",
|
||||||
"edt_append_leds": "LEDs",
|
"edt_append_leds": "LEDs",
|
||||||
"edt_append_ms": "ms",
|
"edt_append_ms": "ms",
|
||||||
@ -424,8 +425,8 @@
|
|||||||
"edt_conf_smooth_time_ms_title": "Time",
|
"edt_conf_smooth_time_ms_title": "Time",
|
||||||
"edt_conf_smooth_type_expl": "Type of smoothing.",
|
"edt_conf_smooth_type_expl": "Type of smoothing.",
|
||||||
"edt_conf_smooth_type_title": "Type",
|
"edt_conf_smooth_type_title": "Type",
|
||||||
"edt_conf_smooth_updateDelay_expl": "Delay the output in case your ambient light is faster than your TV.",
|
"edt_conf_smooth_updateDelay_expl": "Delay the output by n updates in case your ambient light is faster than your TV.",
|
||||||
"edt_conf_smooth_updateDelay_title": "Update delay",
|
"edt_conf_smooth_updateDelay_title": "Output delay",
|
||||||
"edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.",
|
"edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.",
|
||||||
"edt_conf_smooth_updateFrequency_title": "Update frequency",
|
"edt_conf_smooth_updateFrequency_title": "Update frequency",
|
||||||
"edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)",
|
"edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)",
|
||||||
|
@ -154,6 +154,7 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
// Start test
|
// Start test
|
||||||
$('#btn_start_test').off().on('click', function () {
|
$('#btn_start_test').off().on('click', function () {
|
||||||
|
$('#btn_start_test').prop('disabled', true);
|
||||||
triggerTestEffect();
|
triggerTestEffect();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -161,6 +162,7 @@ $(document).ready(function () {
|
|||||||
$('#btn_stop_test').off().on('click', function () {
|
$('#btn_stop_test').off().on('click', function () {
|
||||||
requestPriorityClear();
|
requestPriorityClear();
|
||||||
testrun = false;
|
testrun = false;
|
||||||
|
$('#btn_start_test').prop('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Continuous test
|
// Continuous test
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
#include <effectengine/EffectSchema.h>
|
#include <effectengine/EffectSchema.h>
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
|
|
||||||
|
#include <hyperion/LinearColorSmoothing.h>
|
||||||
|
|
||||||
// pre-declaration
|
// pre-declaration
|
||||||
class Effect;
|
class Effect;
|
||||||
class EffectFileHandler;
|
class EffectFileHandler;
|
||||||
@ -79,7 +81,7 @@ public slots:
|
|||||||
, int timeout = PriorityMuxer::ENDLESS
|
, int timeout = PriorityMuxer::ENDLESS
|
||||||
, const QString &pythonScript = ""
|
, const QString &pythonScript = ""
|
||||||
, const QString &origin = "System"
|
, const QString &origin = "System"
|
||||||
, unsigned smoothCfg=0
|
, unsigned smoothCfg=SmoothingConfigID::SYSTEM
|
||||||
, const QString &imageData = ""
|
, const QString &imageData = ""
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -105,7 +107,7 @@ private:
|
|||||||
, int priority
|
, int priority
|
||||||
, int timeout = PriorityMuxer::ENDLESS
|
, int timeout = PriorityMuxer::ENDLESS
|
||||||
, const QString &origin="System"
|
, const QString &origin="System"
|
||||||
, unsigned smoothCfg=0
|
, unsigned smoothCfg=SmoothingConfigID::SYSTEM
|
||||||
, const QString &imageData = ""
|
, const QString &imageData = ""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef LINEARCOLORSMOOTHING_H
|
||||||
|
#define LINEARCOLORSMOOTHING_H
|
||||||
|
|
||||||
// STL includes
|
// STL includes
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -10,6 +11,7 @@
|
|||||||
// hyperion includes
|
// hyperion includes
|
||||||
#include <leddevice/LedDevice.h>
|
#include <leddevice/LedDevice.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
#include <utils/settings.h>
|
#include <utils/settings.h>
|
||||||
@ -21,13 +23,12 @@ class QTimer;
|
|||||||
class Logger;
|
class Logger;
|
||||||
class Hyperion;
|
class Hyperion;
|
||||||
|
|
||||||
/// The type of smoothing to perform
|
enum SmoothingConfigID
|
||||||
enum SmoothingType {
|
{
|
||||||
/// "Linear" smoothing algorithm
|
SYSTEM = 0,
|
||||||
Linear,
|
PAUSE = 1,
|
||||||
|
EFFECT_DYNAMIC = 2,
|
||||||
/// Decay based smoothing algorithm
|
EFFECT_SPECIFIC = 3
|
||||||
Decay,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Linear Smoothing class
|
/// Linear Smoothing class
|
||||||
@ -80,6 +81,7 @@ public:
|
|||||||
/// @param hyperion The hyperion parent instance
|
/// @param hyperion The hyperion parent instance
|
||||||
///
|
///
|
||||||
LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion);
|
LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion);
|
||||||
|
~LinearColorSmoothing() override;
|
||||||
|
|
||||||
/// LED values as input for the smoothing filter
|
/// LED values as input for the smoothing filter
|
||||||
///
|
///
|
||||||
@ -114,16 +116,16 @@ public:
|
|||||||
///
|
///
|
||||||
/// @return The index of the configuration, which can be passed to selectConfig()
|
/// @return The index of the configuration, which can be passed to selectConfig()
|
||||||
///
|
///
|
||||||
unsigned updateConfig(unsigned cfgID, int settlingTime_ms, double ledUpdateFrequency_hz = 25.0, unsigned updateDelay = 0);
|
unsigned updateConfig(int cfgID, int settlingTime_ms, double ledUpdateFrequency_hz = 25.0, unsigned updateDelay = 0);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief select a smoothing configuration given by cfg index from addConfig()
|
/// @brief select a smoothing configuration given by cfg index from addConfig()
|
||||||
/// @param cfg The index to use
|
/// @param cfgID The index to use
|
||||||
/// @param force Overwrite in any case the current values (used for cfg 0 settings update)
|
/// @param force Overwrite in any case the current values (used for cfg 0 settings update)
|
||||||
///
|
///
|
||||||
/// @return On success return else false (and falls back to cfg 0)
|
/// @return On success return else false (and falls back to cfg 0)
|
||||||
///
|
///
|
||||||
bool selectConfig(unsigned cfg, bool force = false);
|
bool selectConfig(int cfgID, bool force = false);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
@ -160,12 +162,17 @@ private:
|
|||||||
///
|
///
|
||||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||||
|
|
||||||
|
QString getConfig(int cfgID);
|
||||||
|
|
||||||
/// Logger instance
|
/// Logger instance
|
||||||
Logger *_log;
|
Logger *_log;
|
||||||
|
|
||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
Hyperion *_hyperion;
|
Hyperion *_hyperion;
|
||||||
|
|
||||||
|
/// priority muxer instance
|
||||||
|
PriorityMuxer* _prioMuxer;
|
||||||
|
|
||||||
/// The interval at which to update the leds (msec)
|
/// The interval at which to update the leds (msec)
|
||||||
int _updateInterval;
|
int _updateInterval;
|
||||||
|
|
||||||
@ -210,14 +217,12 @@ private:
|
|||||||
REMEMBERED_FRAME ( const REMEMBERED_FRAME & ) = default;
|
REMEMBERED_FRAME ( const REMEMBERED_FRAME & ) = default;
|
||||||
REMEMBERED_FRAME & operator= ( const REMEMBERED_FRAME & ) = default;
|
REMEMBERED_FRAME & operator= ( const REMEMBERED_FRAME & ) = default;
|
||||||
|
|
||||||
REMEMBERED_FRAME(const int64_t time, const std::vector<ColorRgb> colors)
|
REMEMBERED_FRAME(int64_t time, const std::vector<ColorRgb> colors)
|
||||||
: time(time)
|
: time(time)
|
||||||
, colors(colors)
|
, colors(colors)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The type of smoothing to perform
|
|
||||||
SmoothingType _smoothingType;
|
|
||||||
|
|
||||||
/// The queue of temporarily remembered frames
|
/// The queue of temporarily remembered frames
|
||||||
std::deque<REMEMBERED_FRAME> _frameQueue;
|
std::deque<REMEMBERED_FRAME> _frameQueue;
|
||||||
@ -246,41 +251,53 @@ private:
|
|||||||
/// Value of 1.0 / settlingTime; inverse of the window size used for weighting of frames.
|
/// Value of 1.0 / settlingTime; inverse of the window size used for weighting of frames.
|
||||||
floatT _invWindow;
|
floatT _invWindow;
|
||||||
|
|
||||||
struct SMOOTHING_CFG
|
enum class SmoothingType { Linear = 0, Decay = 1 };
|
||||||
{
|
|
||||||
/// The type of smoothing to perform
|
|
||||||
SmoothingType smoothingType;
|
|
||||||
|
|
||||||
|
class SmoothingCfg
|
||||||
|
{
|
||||||
|
public:
|
||||||
/// Whether to pause output
|
/// Whether to pause output
|
||||||
bool pause;
|
bool _pause;
|
||||||
|
|
||||||
/// The time of the smoothing window.
|
/// The time of the smoothing window.
|
||||||
int64_t settlingTime;
|
int64_t _settlingTime;
|
||||||
|
|
||||||
/// The interval time in milliseconds of the timer used for scheduling LED update operations. A value of 0 indicates sub-millisecond timing.
|
/// The interval time in milliseconds of the timer used for scheduling LED update operations. A value of 0 indicates sub-millisecond timing.
|
||||||
int updateInterval;
|
int _updateInterval;
|
||||||
|
|
||||||
// The rate at which color frames should be written to LED device.
|
/// The type of smoothing to perform
|
||||||
double outputRate;
|
SmoothingType _type;
|
||||||
|
|
||||||
|
/// The rate at which color frames should be written to LED device.
|
||||||
|
double _outputRate;
|
||||||
|
|
||||||
/// The rate at which interpolation of LED frames should be performed.
|
/// The rate at which interpolation of LED frames should be performed.
|
||||||
double interpolationRate;
|
double _interpolationRate;
|
||||||
|
|
||||||
/// The number of frames the output is delayed
|
/// The number of frames the output is delayed
|
||||||
unsigned outputDelay;
|
unsigned _outputDelay;
|
||||||
|
|
||||||
/// Whether to apply temporal dithering to diffuse rounding errors when downsampling to 8-bit RGB colors. Improves color accuracy.
|
/// Whether to apply temporal dithering to diffuse rounding errors when downsampling to 8-bit RGB colors. Improves color accuracy.
|
||||||
bool dithering;
|
bool _dithering;
|
||||||
|
|
||||||
/// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate.
|
/// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate.
|
||||||
double decay;
|
double _decay;
|
||||||
};
|
|
||||||
/// smooth configuration list
|
|
||||||
QVector<SMOOTHING_CFG> _cfgList;
|
|
||||||
|
|
||||||
unsigned _currentConfigId;
|
SmoothingCfg();
|
||||||
|
SmoothingCfg(bool pause, int64_t settlingTime, int updateInterval, SmoothingType type = SmoothingType::Linear, double outputRate = 0, double interpolationRate = 0, unsigned outputDelay = 0, bool dithering = false, double decay = 1);
|
||||||
|
|
||||||
|
static QString EnumToString(SmoothingType type);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// smoothing configurations
|
||||||
|
QVector<SmoothingCfg> _cfgList;
|
||||||
|
|
||||||
|
int _currentConfigId;
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
|
|
||||||
|
/// The type of smoothing to perform
|
||||||
|
SmoothingType _smoothingType;
|
||||||
|
|
||||||
/// Pushes the colors into the frame queue and cleans outdated frames from memory.
|
/// Pushes the colors into the frame queue and cleans outdated frames from memory.
|
||||||
///
|
///
|
||||||
/// @param ledColors The next colors to queue
|
/// @param ledColors The next colors to queue
|
||||||
@ -292,7 +309,7 @@ private:
|
|||||||
/// (Re-)Initializes the color-component vectors with given number of values.
|
/// (Re-)Initializes the color-component vectors with given number of values.
|
||||||
///
|
///
|
||||||
/// @param ledCount The number of colors.
|
/// @param ledCount The number of colors.
|
||||||
void intitializeComponentVectors(const size_t ledCount);
|
void intitializeComponentVectors(size_t ledCount);
|
||||||
|
|
||||||
/// The number of led component-values that must be held per color; i.e. size of the color vectors reds / greens / blues
|
/// The number of led component-values that must be held per color; i.e. size of the color vectors reds / greens / blues
|
||||||
size_t _ledCount = 0;
|
size_t _ledCount = 0;
|
||||||
@ -330,10 +347,10 @@ private:
|
|||||||
///
|
///
|
||||||
/// When downsampling the average color values to the 8-bit RGB resolution of the LED device, rounding errors are minimized
|
/// When downsampling the average color values to the 8-bit RGB resolution of the LED device, rounding errors are minimized
|
||||||
/// by temporal dithering algorithm (error diffusion of residual errors).
|
/// by temporal dithering algorithm (error diffusion of residual errors).
|
||||||
void performDecay(const int64_t now);
|
void performDecay(int64_t now);
|
||||||
|
|
||||||
/// Performs a linear smoothing effect
|
/// Performs a linear smoothing effect
|
||||||
void performLinear(const int64_t now);
|
void performLinear(int64_t now);
|
||||||
|
|
||||||
/// Aggregates the RGB components of the LED colors using the given weight and updates weighted accordingly
|
/// Aggregates the RGB components of the LED colors using the given weight and updates weighted accordingly
|
||||||
///
|
///
|
||||||
@ -343,7 +360,7 @@ private:
|
|||||||
static inline void aggregateComponents(const std::vector<ColorRgb>& colors, std::vector<uint64_t>& weighted, const floatT weight);
|
static inline void aggregateComponents(const std::vector<ColorRgb>& colors, std::vector<uint64_t>& weighted, const floatT weight);
|
||||||
|
|
||||||
/// Gets the current time in microseconds from high precision system clock.
|
/// Gets the current time in microseconds from high precision system clock.
|
||||||
inline int64_t micros() const;
|
static inline int64_t micros() ;
|
||||||
|
|
||||||
/// The time, when the rendering statistics were logged previously
|
/// The time, when the rendering statistics were logged previously
|
||||||
int64_t _renderedStatTime;
|
int64_t _renderedStatTime;
|
||||||
@ -368,3 +385,5 @@ private:
|
|||||||
/// @returns The frame weight.
|
/// @returns The frame weight.
|
||||||
std::function<floatT(int64_t, int64_t, int64_t)> _weightFrame;
|
std::function<floatT(int64_t, int64_t, int64_t)> _weightFrame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // LINEARCOLORSMOOTHING_H
|
@ -112,14 +112,17 @@ void EffectEngine::handleUpdatedEffectList()
|
|||||||
{
|
{
|
||||||
_availableEffects.clear();
|
_availableEffects.clear();
|
||||||
|
|
||||||
unsigned id = 2;
|
//Add smoothing config entry to support dynamic effects done in configurator
|
||||||
|
_hyperion->updateSmoothingConfig(SmoothingConfigID::EFFECT_DYNAMIC);
|
||||||
|
|
||||||
|
unsigned specificId = SmoothingConfigID::EFFECT_SPECIFIC;
|
||||||
for (auto def : _effectFileHandler->getEffects())
|
for (auto def : _effectFileHandler->getEffects())
|
||||||
{
|
{
|
||||||
// add smoothing configs to Hyperion
|
// add smoothing configurations to Hyperion
|
||||||
if (def.args["smoothing-custom-settings"].toBool())
|
if (def.args["smoothing-custom-settings"].toBool())
|
||||||
{
|
{
|
||||||
def.smoothCfg = _hyperion->updateSmoothingConfig(
|
def.smoothCfg = _hyperion->updateSmoothingConfig(
|
||||||
id,
|
++specificId,
|
||||||
def.args["smoothing-time_ms"].toInt(),
|
def.args["smoothing-time_ms"].toInt(),
|
||||||
def.args["smoothing-updateFrequency"].toDouble(),
|
def.args["smoothing-updateFrequency"].toDouble(),
|
||||||
0 );
|
0 );
|
||||||
@ -127,7 +130,7 @@ void EffectEngine::handleUpdatedEffectList()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
def.smoothCfg = _hyperion->updateSmoothingConfig(id);
|
def.smoothCfg = SmoothingConfigID::SYSTEM;
|
||||||
//Debug( _log, "Default Settings: Update effect %s, script %s, file %s, smoothCfg [%u]", QSTRING_CSTR(def.name), QSTRING_CSTR(def.script), QSTRING_CSTR(def.file), def.smoothCfg);
|
//Debug( _log, "Default Settings: Update effect %s, script %s, file %s, smoothCfg [%u]", QSTRING_CSTR(def.name), QSTRING_CSTR(def.script), QSTRING_CSTR(def.file), def.smoothCfg);
|
||||||
}
|
}
|
||||||
_availableEffects.push_back(def);
|
_availableEffects.push_back(def);
|
||||||
@ -137,11 +140,30 @@ void EffectEngine::handleUpdatedEffectList()
|
|||||||
|
|
||||||
int EffectEngine::runEffect(const QString &effectName, int priority, int timeout, const QString &origin)
|
int EffectEngine::runEffect(const QString &effectName, int priority, int timeout, const QString &origin)
|
||||||
{
|
{
|
||||||
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
|
unsigned smoothCfg = SmoothingConfigID::SYSTEM;
|
||||||
|
for (const auto &def : _availableEffects)
|
||||||
|
{
|
||||||
|
if (def.name == effectName)
|
||||||
|
{
|
||||||
|
smoothCfg = def.smoothCfg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin, smoothCfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg, const QString &imageData)
|
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg, const QString &imageData)
|
||||||
{
|
{
|
||||||
|
//In case smoothing information is provided dynamically use temp smoothing config item (2)
|
||||||
|
if (smoothCfg == SmoothingConfigID::SYSTEM && args["smoothing-custom-settings"].toBool())
|
||||||
|
{
|
||||||
|
smoothCfg = _hyperion->updateSmoothingConfig(
|
||||||
|
SmoothingConfigID::EFFECT_DYNAMIC,
|
||||||
|
args["smoothing-time_ms"].toInt(),
|
||||||
|
args["smoothing-updateFrequency"].toDouble(),
|
||||||
|
0 );
|
||||||
|
}
|
||||||
|
|
||||||
if (pythonScript.isEmpty())
|
if (pythonScript.isEmpty())
|
||||||
{
|
{
|
||||||
const EffectDefinition *effectDefinition = nullptr;
|
const EffectDefinition *effectDefinition = nullptr;
|
||||||
@ -181,7 +203,7 @@ int EffectEngine::runEffectScript(const QString &script, const QString &name, co
|
|||||||
_activeEffects.push_back(effect);
|
_activeEffects.push_back(effect);
|
||||||
|
|
||||||
// start the effect
|
// start the effect
|
||||||
Debug(_log, "Start the effect: name [%s], smoothCfg [%u]", QSTRING_CSTR(name), smoothCfg);
|
Debug(_log, "Start the effect: name [%s]", QSTRING_CSTR(name));
|
||||||
_hyperion->registerInput(priority, hyperion::COMP_EFFECT, origin, name ,smoothCfg);
|
_hyperion->registerInput(priority, hyperion::COMP_EFFECT, origin, name ,smoothCfg);
|
||||||
effect->start();
|
effect->start();
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include <leddevice/LedDeviceWrapper.h>
|
#include <leddevice/LedDeviceWrapper.h>
|
||||||
|
|
||||||
#include <hyperion/MultiColorAdjustment.h>
|
#include <hyperion/MultiColorAdjustment.h>
|
||||||
#include "LinearColorSmoothing.h"
|
#include <hyperion/LinearColorSmoothing.h>
|
||||||
|
|
||||||
#if defined(ENABLE_EFFECTENGINE)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
// effect engine includes
|
// effect engine includes
|
||||||
@ -303,10 +303,6 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
|
|||||||
|
|
||||||
// TODO: Check, if framegrabber frequency is lower than latchtime..., if yes, stop
|
// TODO: Check, if framegrabber frequency is lower than latchtime..., if yes, stop
|
||||||
}
|
}
|
||||||
else if(type == settings::SMOOTHING)
|
|
||||||
{
|
|
||||||
_deviceSmooth->handleSettingsUpdate( type, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update once to push single color sets / adjustments/ ledlayout resizes and update ledBuffer color
|
// update once to push single color sets / adjustments/ ledlayout resizes and update ledBuffer color
|
||||||
update();
|
update();
|
||||||
@ -707,8 +703,6 @@ void Hyperion::update()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_deviceSmooth->selectConfig(priorityInfo.smooth_cfg);
|
|
||||||
|
|
||||||
// feed smoothing in pause mode to maintain a smooth transition back to smooth mode
|
// feed smoothing in pause mode to maintain a smooth transition back to smooth mode
|
||||||
if (_deviceSmooth->enabled() || _deviceSmooth->pause())
|
if (_deviceSmooth->enabled() || _deviceSmooth->pause())
|
||||||
{
|
{
|
||||||
|
@ -2,16 +2,13 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "LinearColorSmoothing.h"
|
#include <hyperion/LinearColorSmoothing.h>
|
||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
/// The number of microseconds per millisecond = 1000.
|
|
||||||
const int64_t MS_PER_MICRO = 1000;
|
|
||||||
|
|
||||||
#if defined(COMPILER_GCC)
|
#if defined(COMPILER_GCC)
|
||||||
#define ALWAYS_INLINE inline __attribute__((__always_inline__))
|
#define ALWAYS_INLINE inline __attribute__((__always_inline__))
|
||||||
#elif defined(COMPILER_MSVC)
|
#elif defined(COMPILER_MSVC)
|
||||||
@ -25,6 +22,14 @@ ALWAYS_INLINE long clampRounded(const floatT x) {
|
|||||||
return std::min(255L, std::max(0L, std::lroundf(x)));
|
return std::min(255L, std::max(0L, std::lroundf(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const bool verbose = false;
|
||||||
|
|
||||||
|
/// The number of microseconds per millisecond = 1000.
|
||||||
|
const int64_t MS_PER_MICRO = 1000;
|
||||||
|
|
||||||
/// The number of bits that are used for shifting the fixed point values
|
/// The number of bits that are used for shifting the fixed point values
|
||||||
const int FPShift = (sizeof(uint64_t)*8 - (12 + 9));
|
const int FPShift = (sizeof(uint64_t)*8 - (12 + 9));
|
||||||
|
|
||||||
@ -35,97 +40,113 @@ const int SmallShiftBis = sizeof(uint8_t)*8;
|
|||||||
const int FPShiftSmall = (sizeof(uint64_t)*8 - (12 + 9 + SmallShiftBis));
|
const int FPShiftSmall = (sizeof(uint64_t)*8 - (12 + 9 + SmallShiftBis));
|
||||||
|
|
||||||
const char* SETTINGS_KEY_SMOOTHING_TYPE = "type";
|
const char* SETTINGS_KEY_SMOOTHING_TYPE = "type";
|
||||||
|
|
||||||
|
const char* SETTINGS_KEY_SETTLING_TIME = "time_ms";
|
||||||
|
const char* SETTINGS_KEY_UPDATE_FREQUENCY = "updateFrequency";
|
||||||
|
const char* SETTINGS_KEY_OUTPUT_DELAY = "updateDelay";
|
||||||
|
|
||||||
|
const char* SETTINGS_KEY_DECAY = "decay";
|
||||||
const char* SETTINGS_KEY_INTERPOLATION_RATE = "interpolationRate";
|
const char* SETTINGS_KEY_INTERPOLATION_RATE = "interpolationRate";
|
||||||
const char* SETTINGS_KEY_OUTPUT_RATE = "outputRate";
|
const char* SETTINGS_KEY_OUTPUT_RATE = "outputRate";
|
||||||
const char* SETTINGS_KEY_DITHERING = "dithering";
|
const char* SETTINGS_KEY_DITHERING = "dithering";
|
||||||
const char* SETTINGS_KEY_DECAY = "decay";
|
|
||||||
|
const int64_t DEFAULT_SETTLINGTIME = 200; // in ms
|
||||||
|
const int DEFAULT_UPDATEFREQUENCY = 25; // in Hz
|
||||||
|
|
||||||
|
constexpr std::chrono::milliseconds DEFAULT_UPDATEINTERVALL{MS_PER_MICRO/ DEFAULT_UPDATEFREQUENCY};
|
||||||
|
const unsigned DEFAULT_OUTPUTDEPLAY = 0; // in frames
|
||||||
|
}
|
||||||
|
|
||||||
using namespace hyperion;
|
using namespace hyperion;
|
||||||
|
|
||||||
const int64_t DEFAUL_SETTLINGTIME = 200; // settlingtime in ms
|
|
||||||
const int DEFAUL_UPDATEFREQUENCY = 25; // updatefrequncy in hz
|
|
||||||
|
|
||||||
constexpr std::chrono::milliseconds DEFAUL_UPDATEINTERVALL{1000/ DEFAUL_UPDATEFREQUENCY};
|
|
||||||
const unsigned DEFAUL_OUTPUTDEPLAY = 0; // outputdelay in ms
|
|
||||||
|
|
||||||
LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion)
|
LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion)
|
||||||
: QObject(hyperion)
|
: QObject(hyperion)
|
||||||
, _log(nullptr)
|
, _log(nullptr)
|
||||||
, _hyperion(hyperion)
|
, _hyperion(hyperion)
|
||||||
, _updateInterval(DEFAUL_UPDATEINTERVALL.count())
|
, _prioMuxer(_hyperion->getMuxerInstance())
|
||||||
, _settlingTime(DEFAUL_SETTLINGTIME)
|
, _updateInterval(DEFAULT_UPDATEINTERVALL.count())
|
||||||
, _timer(new QTimer(this))
|
, _settlingTime(DEFAULT_SETTLINGTIME)
|
||||||
, _outputDelay(DEFAUL_OUTPUTDEPLAY)
|
, _timer(nullptr)
|
||||||
, _smoothingType(SmoothingType::Linear)
|
, _outputDelay(DEFAULT_OUTPUTDEPLAY)
|
||||||
, _pause(false)
|
, _pause(false)
|
||||||
, _currentConfigId(0)
|
, _currentConfigId(SmoothingConfigID::SYSTEM)
|
||||||
, _enabled(false)
|
, _enabled(false)
|
||||||
|
, _smoothingType(SmoothingType::Linear)
|
||||||
, tempValues(std::vector<uint64_t>(0, 0L))
|
, tempValues(std::vector<uint64_t>(0, 0L))
|
||||||
{
|
{
|
||||||
QString subComponent = hyperion->property("instance").toString();
|
QString subComponent = hyperion->property("instance").toString();
|
||||||
_log= Logger::getInstance("SMOOTHING", subComponent);
|
_log= Logger::getInstance("SMOOTHING", subComponent);
|
||||||
|
|
||||||
// init cfg 0 (default)
|
// timer
|
||||||
addConfig(DEFAUL_SETTLINGTIME, DEFAUL_UPDATEFREQUENCY, DEFAUL_OUTPUTDEPLAY);
|
_timer = new QTimer(this);
|
||||||
|
_timer->setTimerType(Qt::PreciseTimer);
|
||||||
|
|
||||||
|
// init cfg (default)
|
||||||
|
updateConfig(SmoothingConfigID::SYSTEM, DEFAULT_SETTLINGTIME, DEFAULT_UPDATEFREQUENCY, DEFAULT_OUTPUTDEPLAY);
|
||||||
handleSettingsUpdate(settings::SMOOTHING, config);
|
handleSettingsUpdate(settings::SMOOTHING, config);
|
||||||
selectConfig(0, true);
|
|
||||||
|
|
||||||
// add pause on cfg 1
|
// add pause on cfg 1
|
||||||
SMOOTHING_CFG cfg = {SmoothingType::Linear, false, 0, 0, 0, 0, 0, false, 1};
|
SmoothingCfg cfg {true, 0, 0};
|
||||||
_cfgList.append(cfg);
|
_cfgList.append(cfg);
|
||||||
|
|
||||||
// listen for comp changes
|
// listen for comp changes
|
||||||
connect(_hyperion, &Hyperion::compStateChangeRequest, this, &LinearColorSmoothing::componentStateChange);
|
connect(_hyperion, &Hyperion::compStateChangeRequest, this, &LinearColorSmoothing::componentStateChange);
|
||||||
// timer
|
|
||||||
connect(_timer, &QTimer::timeout, this, &LinearColorSmoothing::updateLeds);
|
connect(_timer, &QTimer::timeout, this, &LinearColorSmoothing::updateLeds);
|
||||||
|
|
||||||
//Debug(_log, "LinearColorSmoothing sizeof floatT == %d", (sizeof(floatT)));
|
connect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, [=] (int priority){
|
||||||
|
const PriorityMuxer::InputInfo priorityInfo = _prioMuxer->getInputInfo(priority);
|
||||||
|
int smooth_cfg = priorityInfo.smooth_cfg;
|
||||||
|
if (smooth_cfg != _currentConfigId || smooth_cfg == SmoothingConfigID::EFFECT_DYNAMIC)
|
||||||
|
{
|
||||||
|
this->selectConfig(smooth_cfg, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearColorSmoothing::~LinearColorSmoothing()
|
||||||
|
{
|
||||||
|
delete _timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJsonDocument &config)
|
void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJsonDocument &config)
|
||||||
{
|
{
|
||||||
if (type == settings::SMOOTHING)
|
if (type == settings::type::SMOOTHING)
|
||||||
{
|
{
|
||||||
// std::cout << "LinearColorSmoothing::handleSettingsUpdate" << std::endl;
|
|
||||||
// std::cout << config.toJson().toStdString() << std::endl;
|
|
||||||
|
|
||||||
QJsonObject obj = config.object();
|
QJsonObject obj = config.object();
|
||||||
if (enabled() != obj["enable"].toBool(true))
|
if (enabled() != obj["enable"].toBool(true))
|
||||||
{
|
{
|
||||||
setEnable(obj["enable"].toBool(true));
|
setEnable(obj["enable"].toBool(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
SMOOTHING_CFG cfg = {SmoothingType::Linear,true, 0, 0, 0, 0, 0, false, 1};
|
SmoothingCfg cfg(false,
|
||||||
|
static_cast<int64_t>(obj[SETTINGS_KEY_SETTLING_TIME].toInt(DEFAULT_SETTLINGTIME)),
|
||||||
|
static_cast<int64_t>(MS_PER_MICRO / obj[SETTINGS_KEY_UPDATE_FREQUENCY].toDouble(DEFAULT_UPDATEFREQUENCY))
|
||||||
|
);
|
||||||
|
|
||||||
const QString typeString = obj[SETTINGS_KEY_SMOOTHING_TYPE].toString();
|
const QString typeString = obj[SETTINGS_KEY_SMOOTHING_TYPE].toString();
|
||||||
|
|
||||||
if(typeString == "linear") {
|
if(typeString == SETTINGS_KEY_DECAY) {
|
||||||
cfg.smoothingType = SmoothingType::Linear;
|
cfg._type = SmoothingType::Decay;
|
||||||
} else if(typeString == "decay") {
|
}
|
||||||
cfg.smoothingType = SmoothingType::Decay;
|
else {
|
||||||
|
cfg._type = SmoothingType::Linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.pause = false;
|
cfg._pause = false;
|
||||||
cfg.settlingTime = static_cast<int64_t>(obj["time_ms"].toInt(DEFAUL_SETTLINGTIME));
|
cfg._outputDelay = static_cast<unsigned>(obj[SETTINGS_KEY_OUTPUT_DELAY].toInt(DEFAULT_OUTPUTDEPLAY));
|
||||||
cfg.updateInterval = static_cast<int>(1000.0 / obj["updateFrequency"].toDouble(DEFAUL_UPDATEFREQUENCY));
|
|
||||||
cfg.outputRate = obj[SETTINGS_KEY_OUTPUT_RATE].toDouble(DEFAUL_UPDATEFREQUENCY);
|
|
||||||
cfg.interpolationRate = obj[SETTINGS_KEY_INTERPOLATION_RATE].toDouble(DEFAUL_UPDATEFREQUENCY);
|
|
||||||
cfg.outputDelay = static_cast<unsigned>(obj["updateDelay"].toInt(DEFAUL_OUTPUTDEPLAY));
|
|
||||||
cfg.dithering = obj[SETTINGS_KEY_DITHERING].toBool(false);
|
|
||||||
cfg.decay = obj[SETTINGS_KEY_DECAY].toDouble(1.0);
|
|
||||||
|
|
||||||
//Debug( _log, "smoothing cfg_id %d: pause: %d bool, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _currentConfigId, cfg.pause, cfg.settlingTime, cfg.updateInterval, unsigned(1000.0/cfg.updateInterval), cfg.outputDelay );
|
cfg._outputRate = obj[SETTINGS_KEY_OUTPUT_RATE].toDouble(DEFAULT_UPDATEFREQUENCY);
|
||||||
_cfgList[0] = cfg;
|
cfg._interpolationRate = obj[SETTINGS_KEY_INTERPOLATION_RATE].toDouble(DEFAULT_UPDATEFREQUENCY);
|
||||||
|
cfg._dithering = obj[SETTINGS_KEY_DITHERING].toBool(false);
|
||||||
|
cfg._decay = obj[SETTINGS_KEY_DECAY].toDouble(1.0);
|
||||||
|
|
||||||
|
_cfgList[SmoothingConfigID::SYSTEM] = cfg;
|
||||||
|
DebugIf(_enabled,_log,"%s", QSTRING_CSTR(getConfig(SmoothingConfigID::SYSTEM)));
|
||||||
|
|
||||||
// if current id is 0, we need to apply the settings (forced)
|
// if current id is 0, we need to apply the settings (forced)
|
||||||
if (_currentConfigId == 0)
|
if (_currentConfigId == SmoothingConfigID::SYSTEM)
|
||||||
{
|
{
|
||||||
//Debug( _log, "_currentConfigId == 0");
|
selectConfig(SmoothingConfigID::SYSTEM, true);
|
||||||
selectConfig(0, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Debug( _log, "_currentConfigId != 0");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,8 +166,7 @@ int LinearColorSmoothing::write(const std::vector<ColorRgb> &ledValues)
|
|||||||
_previousValues = ledValues;
|
_previousValues = ledValues;
|
||||||
_previousInterpolationTime = micros();
|
_previousInterpolationTime = micros();
|
||||||
|
|
||||||
//Debug( _log, "Start Smoothing timer: settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
|
_timer->start(_updateInterval);
|
||||||
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -202,7 +222,7 @@ void LinearColorSmoothing::writeFrame()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ALWAYS_INLINE int64_t LinearColorSmoothing::micros() const
|
ALWAYS_INLINE int64_t LinearColorSmoothing::micros()
|
||||||
{
|
{
|
||||||
const auto now = std::chrono::high_resolution_clock::now();
|
const auto now = std::chrono::high_resolution_clock::now();
|
||||||
return (std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch())).count();
|
return (std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch())).count();
|
||||||
@ -215,7 +235,7 @@ void LinearColorSmoothing::assembleAndDitherFrame()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of leds present in each frame
|
// The number of LEDs present in each frame
|
||||||
const size_t N = _targetValues.size();
|
const size_t N = _targetValues.size();
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
@ -250,7 +270,7 @@ void LinearColorSmoothing::assembleFrame()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of leds present in each frame
|
// The number of LEDs present in each frame
|
||||||
const size_t N = _targetValues.size();
|
const size_t N = _targetValues.size();
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
@ -438,7 +458,6 @@ void LinearColorSmoothing::updateLeds()
|
|||||||
const int64_t now = micros();
|
const int64_t now = micros();
|
||||||
const int64_t deltaTime = _targetTime - now;
|
const int64_t deltaTime = _targetTime - now;
|
||||||
|
|
||||||
//Debug(_log, "elapsed Time [%d], _targetTime [%d] - now [%d], deltaTime [%d]", now -_previousWriteTime, _targetTime, now, deltaTime);
|
|
||||||
if (deltaTime < 0)
|
if (deltaTime < 0)
|
||||||
{
|
{
|
||||||
writeDirect();
|
writeDirect();
|
||||||
@ -447,12 +466,11 @@ void LinearColorSmoothing::updateLeds()
|
|||||||
|
|
||||||
switch (_smoothingType)
|
switch (_smoothingType)
|
||||||
{
|
{
|
||||||
case Decay:
|
case SmoothingType::Decay:
|
||||||
performDecay(now);
|
performDecay(now);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Linear:
|
case SmoothingType::Linear:
|
||||||
// Linear interpolation is default
|
|
||||||
default:
|
default:
|
||||||
performLinear(now);
|
performLinear(now);
|
||||||
break;
|
break;
|
||||||
@ -461,8 +479,6 @@ void LinearColorSmoothing::updateLeds()
|
|||||||
|
|
||||||
void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors)
|
void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors)
|
||||||
{
|
{
|
||||||
//Debug(_log, "rememberFrame - before _frameQueue.size() [%d]", _frameQueue.size());
|
|
||||||
|
|
||||||
const int64_t now = micros();
|
const int64_t now = micros();
|
||||||
|
|
||||||
// Maintain the queue by removing outdated frames
|
// Maintain the queue by removing outdated frames
|
||||||
@ -478,15 +494,12 @@ void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors)
|
|||||||
|
|
||||||
if (p > 0)
|
if (p > 0)
|
||||||
{
|
{
|
||||||
//Debug(_log, "rememberFrame - erasing %d frames", p);
|
|
||||||
_frameQueue.erase(_frameQueue.begin(), _frameQueue.begin() + p);
|
_frameQueue.erase(_frameQueue.begin(), _frameQueue.begin() + p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the latest frame at back of the queue
|
// Append the latest frame at back of the queue
|
||||||
const REMEMBERED_FRAME frame = REMEMBERED_FRAME(now, ledColors);
|
const REMEMBERED_FRAME frame = REMEMBERED_FRAME(now, ledColors);
|
||||||
_frameQueue.push_back(frame);
|
_frameQueue.push_back(frame);
|
||||||
|
|
||||||
//Debug(_log, "rememberFrame - after _frameQueue.size() [%d]", _frameQueue.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -532,7 +545,8 @@ void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> &ledColors)
|
|||||||
|
|
||||||
void LinearColorSmoothing::clearQueuedColors()
|
void LinearColorSmoothing::clearQueuedColors()
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
_timer->stop();
|
||||||
|
//QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
||||||
_previousValues.clear();
|
_previousValues.clear();
|
||||||
|
|
||||||
_targetValues.clear();
|
_targetValues.clear();
|
||||||
@ -566,71 +580,65 @@ void LinearColorSmoothing::setPause(bool pause)
|
|||||||
|
|
||||||
unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
||||||
{
|
{
|
||||||
SMOOTHING_CFG cfg = {
|
SmoothingCfg cfg {
|
||||||
SmoothingType::Linear,
|
|
||||||
false,
|
false,
|
||||||
settlingTime_ms,
|
settlingTime_ms,
|
||||||
static_cast<int>(1000.0 / ledUpdateFrequency_hz),
|
static_cast<int>(MS_PER_MICRO / ledUpdateFrequency_hz),
|
||||||
|
SmoothingType::Linear,
|
||||||
ledUpdateFrequency_hz,
|
ledUpdateFrequency_hz,
|
||||||
ledUpdateFrequency_hz,
|
ledUpdateFrequency_hz,
|
||||||
updateDelay,
|
updateDelay
|
||||||
false,
|
|
||||||
1
|
|
||||||
};
|
};
|
||||||
_cfgList.append(cfg);
|
_cfgList.append(cfg);
|
||||||
|
|
||||||
//Debug( _log, "smoothing cfg %d: pause: %d bool, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _cfgList.count()-1, cfg.pause, cfg.settlingTime, cfg.updateInterval, unsigned(1000.0/cfg.updateInterval), cfg.outputDelay );
|
DebugIf(verbose && _enabled, _log,"%s", QSTRING_CSTR(getConfig(_cfgList.count()-1)));
|
||||||
|
|
||||||
return _cfgList.count() - 1;
|
return _cfgList.count() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned LinearColorSmoothing::updateConfig(unsigned cfgID, int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
unsigned LinearColorSmoothing::updateConfig(int cfgID, int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
||||||
{
|
{
|
||||||
unsigned updatedCfgID = cfgID;
|
int updatedCfgID = cfgID;
|
||||||
if (cfgID < static_cast<unsigned>(_cfgList.count()))
|
if (cfgID < _cfgList.count())
|
||||||
{
|
{
|
||||||
SMOOTHING_CFG cfg = {
|
SmoothingCfg cfg {
|
||||||
SmoothingType::Linear,
|
|
||||||
false,
|
false,
|
||||||
settlingTime_ms,
|
settlingTime_ms,
|
||||||
static_cast<int>(1000.0 / ledUpdateFrequency_hz),
|
static_cast<int>(MS_PER_MICRO / ledUpdateFrequency_hz),
|
||||||
|
SmoothingType::Linear,
|
||||||
ledUpdateFrequency_hz,
|
ledUpdateFrequency_hz,
|
||||||
ledUpdateFrequency_hz,
|
ledUpdateFrequency_hz,
|
||||||
updateDelay,
|
updateDelay
|
||||||
false,
|
};
|
||||||
1};
|
|
||||||
_cfgList[updatedCfgID] = cfg;
|
_cfgList[updatedCfgID] = cfg;
|
||||||
|
DebugIf(verbose && _enabled, _log,"%s", QSTRING_CSTR(getConfig(updatedCfgID)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
updatedCfgID = addConfig(settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
|
updatedCfgID = addConfig(settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
|
||||||
}
|
}
|
||||||
// Debug( _log, "smoothing updatedCfgID %u: settlingTime: %d ms, "
|
|
||||||
// "interval: %d ms (%u Hz), updateDelay: %u frames", cfgID, _settlingTime, int64_t(1000.0/ledUpdateFrequency_hz), unsigned(ledUpdateFrequency_hz), updateDelay );
|
|
||||||
return updatedCfgID;
|
return updatedCfgID;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force)
|
bool LinearColorSmoothing::selectConfig(int cfgID, bool force)
|
||||||
{
|
{
|
||||||
if (_currentConfigId == cfg && !force)
|
if (_currentConfigId == cfgID && !force)
|
||||||
{
|
{
|
||||||
//Debug( _log, "selectConfig SAME as before, not FORCED - _currentConfigId [%u], force [%d]", cfg, force);
|
|
||||||
//Debug( _log, "current smoothing cfg: %d, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _currentConfigId, _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Debug( _log, "selectConfig FORCED - _currentConfigId [%u], force [%d]", cfg, force);
|
if (cfgID < _cfgList.count() )
|
||||||
if (cfg < static_cast<uint>(_cfgList.count()) )
|
|
||||||
{
|
{
|
||||||
_smoothingType = _cfgList[cfg].smoothingType;
|
_smoothingType = _cfgList[cfgID]._type;
|
||||||
_settlingTime = _cfgList[cfg].settlingTime;
|
_settlingTime = _cfgList[cfgID]._settlingTime;
|
||||||
_outputDelay = _cfgList[cfg].outputDelay;
|
_outputDelay = _cfgList[cfgID]._outputDelay;
|
||||||
_pause = _cfgList[cfg].pause;
|
_pause = _cfgList[cfgID]._pause;
|
||||||
_outputRate = _cfgList[cfg].outputRate;
|
_outputRate = _cfgList[cfgID]._outputRate;
|
||||||
_outputIntervalMicros = int64_t(1000000.0 / _outputRate); // 1s = 1e6 µs
|
_outputIntervalMicros = int64_t(1000000.0 / _outputRate); // 1s = 1e6 µs
|
||||||
_interpolationRate = _cfgList[cfg].interpolationRate;
|
_interpolationRate = _cfgList[cfgID]._interpolationRate;
|
||||||
_interpolationIntervalMicros = int64_t(1000000.0 / _interpolationRate);
|
_interpolationIntervalMicros = int64_t(1000000.0 / _interpolationRate);
|
||||||
_dithering = _cfgList[cfg].dithering;
|
_dithering = _cfgList[cfgID]._dithering;
|
||||||
_decay = _cfgList[cfg].decay;
|
_decay = _cfgList[cfgID]._decay;
|
||||||
_invWindow = 1.0F / (MS_PER_MICRO * _settlingTime);
|
_invWindow = 1.0F / (MS_PER_MICRO * _settlingTime);
|
||||||
|
|
||||||
// Set _weightFrame based on the given decay
|
// Set _weightFrame based on the given decay
|
||||||
@ -661,33 +669,95 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force)
|
|||||||
_interpolationCounter = 0;
|
_interpolationCounter = 0;
|
||||||
_interpolationStatCounter = 0;
|
_interpolationStatCounter = 0;
|
||||||
|
|
||||||
if (_cfgList[cfg].updateInterval != _updateInterval)
|
if (_cfgList[cfgID]._updateInterval != _updateInterval)
|
||||||
{
|
{
|
||||||
|
|
||||||
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
_timer->stop();
|
||||||
_updateInterval = _cfgList[cfg].updateInterval;
|
_updateInterval = _cfgList[cfgID]._updateInterval;
|
||||||
if (this->enabled())
|
if (this->enabled())
|
||||||
{
|
{
|
||||||
//Debug( _log, "_cfgList[cfg].updateInterval != _updateInterval - Restart timer - _updateInterval [%d]", _updateInterval);
|
_timer->start(_updateInterval);
|
||||||
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Debug( _log, "Smoothing disabled, do NOT restart timer");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_currentConfigId = cfg;
|
_currentConfigId = cfgID;
|
||||||
// Debug( _log, "current smoothing cfg: %d, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _currentConfigId, _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
|
DebugIf(_enabled, _log,"%s", QSTRING_CSTR(getConfig(_currentConfigId)));
|
||||||
// DebugIf( enabled() && !_pause, _log, "set smoothing cfg: %u settlingTime: %d ms, interval: %d ms, updateDelay: %u frames", _currentConfigId, _settlingTime, _updateInterval, _outputDelay );
|
|
||||||
// DebugIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId );
|
|
||||||
|
|
||||||
const float thalf = (1.0-std::pow(1.0/2, 1.0/_decay))*_settlingTime;
|
|
||||||
Debug( _log, "cfg [%d]: Type: %s - Time: %d ms, outputRate %f Hz, interpolationRate: %f Hz, timer: %d ms, Dithering: %d, Decay: %f -> HalfTime: %f ms", cfg, _smoothingType == SmoothingType::Decay ? "decay" : "linear", _settlingTime, _outputRate, _interpolationRate, _updateInterval, _dithering ? 1 : 0, _decay, thalf);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset to default
|
// reset to default
|
||||||
_currentConfigId = 0;
|
_currentConfigId = SmoothingConfigID::SYSTEM;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString LinearColorSmoothing::getConfig(int cfgID)
|
||||||
|
{
|
||||||
|
QString configText;
|
||||||
|
|
||||||
|
if (cfgID < _cfgList.count())
|
||||||
|
{
|
||||||
|
SmoothingCfg cfg = _cfgList[cfgID];
|
||||||
|
|
||||||
|
configText = QString ("[%1] - type: %2, pause: %3, settlingTime: %4ms, interval: %5ms (%6Hz), delay: %7 frames")
|
||||||
|
.arg(cfgID)
|
||||||
|
.arg(SmoothingCfg::EnumToString(cfg._type),(cfg._pause) ? "true" : "false")
|
||||||
|
.arg(cfg._settlingTime)
|
||||||
|
.arg(cfg._updateInterval)
|
||||||
|
.arg(int(MS_PER_MICRO/cfg._updateInterval))
|
||||||
|
.arg(cfg._outputDelay);
|
||||||
|
|
||||||
|
switch (cfg._type) {
|
||||||
|
case SmoothingType::Linear:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SmoothingType::Decay:
|
||||||
|
{
|
||||||
|
const double thalf = (1.0-std::pow(1.0/2, 1.0/_decay))*_settlingTime;
|
||||||
|
configText += QString (", outputRate %1Hz, interpolationRate: %2Hz, dithering: %3, decay: %4 -> halftime: %5ms")
|
||||||
|
.arg(cfg._outputRate,0,'f',2)
|
||||||
|
.arg(cfg._interpolationRate,0,'f',2)
|
||||||
|
.arg((cfg._dithering) ? "true" : "false")
|
||||||
|
.arg(cfg._decay,0,'f',2)
|
||||||
|
.arg(thalf,0,'f',2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configText;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearColorSmoothing::SmoothingCfg::SmoothingCfg() :
|
||||||
|
_pause(false),
|
||||||
|
_settlingTime(DEFAULT_SETTLINGTIME),
|
||||||
|
_updateInterval(DEFAULT_UPDATEFREQUENCY),
|
||||||
|
_type(SmoothingType::Linear)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearColorSmoothing::SmoothingCfg::SmoothingCfg(bool pause, int64_t settlingTime, int updateInterval, SmoothingType type, double outputRate, double interpolationRate, unsigned outputDelay, bool dithering, double decay) :
|
||||||
|
_pause(pause),
|
||||||
|
_settlingTime(settlingTime),
|
||||||
|
_updateInterval(updateInterval),
|
||||||
|
_type(type),
|
||||||
|
_outputRate(outputRate),
|
||||||
|
_interpolationRate(interpolationRate),
|
||||||
|
_outputDelay(outputDelay),
|
||||||
|
_dithering(dithering),
|
||||||
|
_decay(decay)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString LinearColorSmoothing::SmoothingCfg::EnumToString(SmoothingType type)
|
||||||
|
{
|
||||||
|
if (type == SmoothingType::Linear) {
|
||||||
|
return QString("Linear");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == SmoothingType::Decay)
|
||||||
|
{
|
||||||
|
return QString("Decay");
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString("Unknown");
|
||||||
|
}
|
||||||
|
@ -44,6 +44,7 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
|||||||
_lowestPriorityInfo.componentId = hyperion::COMP_COLOR;
|
_lowestPriorityInfo.componentId = hyperion::COMP_COLOR;
|
||||||
_lowestPriorityInfo.origin = "System";
|
_lowestPriorityInfo.origin = "System";
|
||||||
_lowestPriorityInfo.owner = "";
|
_lowestPriorityInfo.owner = "";
|
||||||
|
_lowestPriorityInfo.smooth_cfg = 0;
|
||||||
|
|
||||||
_activeInputs[PriorityMuxer::LOWEST_PRIORITY] = _lowestPriorityInfo;
|
_activeInputs[PriorityMuxer::LOWEST_PRIORITY] = _lowestPriorityInfo;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
"minimum": 0,
|
"minimum": 0,
|
||||||
"maximum": 2048,
|
"maximum": 2048,
|
||||||
"default": 0,
|
"default": 0,
|
||||||
"append": "edt_append_ms",
|
"append": "edt_append_frames",
|
||||||
"propertyOrder": 9
|
"propertyOrder": 9
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user