mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Fix Effects and refactor Smoothing (#1442)
This commit is contained in:
		| @@ -211,6 +211,7 @@ | ||||
|     "dashboard_newsbox_readmore": "Read more", | ||||
|     "dashboard_newsbox_visitblog": "Visit Hyperion-Blog", | ||||
|     "edt_append_degree": "°", | ||||
|     "edt_append_frames": "frames", | ||||
|     "edt_append_hz": "Hz", | ||||
|     "edt_append_leds": "LEDs", | ||||
|     "edt_append_ms": "ms", | ||||
| @@ -424,8 +425,8 @@ | ||||
|     "edt_conf_smooth_time_ms_title": "Time", | ||||
|     "edt_conf_smooth_type_expl": "Type of smoothing.", | ||||
|     "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_title": "Update delay", | ||||
|     "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": "Output delay", | ||||
|     "edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.", | ||||
|     "edt_conf_smooth_updateFrequency_title": "Update frequency", | ||||
|     "edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)", | ||||
|   | ||||
| @@ -154,6 +154,7 @@ $(document).ready(function () { | ||||
|  | ||||
|   // Start test | ||||
|   $('#btn_start_test').off().on('click', function () { | ||||
|     $('#btn_start_test').prop('disabled', true); | ||||
|     triggerTestEffect(); | ||||
|   }); | ||||
|  | ||||
| @@ -161,6 +162,7 @@ $(document).ready(function () { | ||||
|   $('#btn_stop_test').off().on('click', function () { | ||||
|     requestPriorityClear(); | ||||
|     testrun = false; | ||||
|     $('#btn_start_test').prop('disabled', false); | ||||
|   }); | ||||
|  | ||||
|   // Continuous test | ||||
|   | ||||
| @@ -18,6 +18,8 @@ | ||||
| #include <effectengine/EffectSchema.h> | ||||
| #include <utils/Logger.h> | ||||
|  | ||||
| #include <hyperion/LinearColorSmoothing.h> | ||||
|  | ||||
| // pre-declaration | ||||
| class Effect; | ||||
| class EffectFileHandler; | ||||
| @@ -79,7 +81,7 @@ public slots: | ||||
| 				, int timeout = PriorityMuxer::ENDLESS | ||||
| 				, const QString &pythonScript = "" | ||||
| 				, const QString &origin = "System" | ||||
| 				, unsigned smoothCfg=0 | ||||
| 				, unsigned smoothCfg=SmoothingConfigID::SYSTEM | ||||
| 				, const QString &imageData = "" | ||||
| 	); | ||||
|  | ||||
| @@ -105,7 +107,7 @@ private: | ||||
| 				, int priority | ||||
| 				, int timeout = PriorityMuxer::ENDLESS | ||||
| 				, const QString &origin="System" | ||||
| 				, unsigned smoothCfg=0 | ||||
| 				, unsigned smoothCfg=SmoothingConfigID::SYSTEM | ||||
| 				, const QString &imageData = "" | ||||
| 	); | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| #pragma once | ||||
| #ifndef LINEARCOLORSMOOTHING_H | ||||
| #define LINEARCOLORSMOOTHING_H | ||||
| 
 | ||||
| // STL includes
 | ||||
| #include <vector> | ||||
| @@ -10,6 +11,7 @@ | ||||
| // hyperion includes
 | ||||
| #include <leddevice/LedDevice.h> | ||||
| #include <utils/Components.h> | ||||
| #include <hyperion/PriorityMuxer.h> | ||||
| 
 | ||||
| // settings
 | ||||
| #include <utils/settings.h> | ||||
| @@ -21,13 +23,12 @@ class QTimer; | ||||
| class Logger; | ||||
| class Hyperion; | ||||
| 
 | ||||
| /// The type of smoothing to perform
 | ||||
| enum SmoothingType { | ||||
| 	/// "Linear" smoothing algorithm
 | ||||
| 	Linear, | ||||
| 
 | ||||
| 	/// Decay based smoothing algorithm
 | ||||
| 	Decay, | ||||
| enum SmoothingConfigID | ||||
| { | ||||
| 	SYSTEM = 0, | ||||
| 	PAUSE = 1, | ||||
| 	EFFECT_DYNAMIC = 2, | ||||
| 	EFFECT_SPECIFIC = 3 | ||||
| }; | ||||
| 
 | ||||
| /// Linear Smoothing class
 | ||||
| @@ -80,6 +81,7 @@ public: | ||||
| 	/// @param hyperion  The hyperion parent instance
 | ||||
| 	///
 | ||||
| 	LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion); | ||||
| 	~LinearColorSmoothing() override; | ||||
| 
 | ||||
| 	/// 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()
 | ||||
| 	///
 | ||||
| 	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()
 | ||||
| 	/// @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)
 | ||||
| 	///
 | ||||
| 	/// @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: | ||||
| 	///
 | ||||
| @@ -160,12 +162,17 @@ private: | ||||
| 	///
 | ||||
| 	virtual int write(const std::vector<ColorRgb> &ledValues); | ||||
| 
 | ||||
| 	QString getConfig(int cfgID); | ||||
| 
 | ||||
| 	/// Logger instance
 | ||||
| 	Logger *_log; | ||||
| 
 | ||||
| 	/// Hyperion instance
 | ||||
| 	Hyperion *_hyperion; | ||||
| 
 | ||||
| 	/// priority muxer instance
 | ||||
| 	PriorityMuxer* _prioMuxer; | ||||
| 
 | ||||
| 	/// The interval at which to update the leds (msec)
 | ||||
| 	int _updateInterval; | ||||
| 
 | ||||
| @@ -210,14 +217,12 @@ private: | ||||
| 		REMEMBERED_FRAME ( 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) | ||||
| 		, colors(colors) | ||||
| 		{} | ||||
| 	}; | ||||
| 
 | ||||
| 	/// The type of smoothing to perform
 | ||||
| 	SmoothingType _smoothingType; | ||||
| 
 | ||||
| 	/// The queue of temporarily remembered frames
 | ||||
| 	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.
 | ||||
| 	floatT _invWindow; | ||||
| 
 | ||||
| 	struct SMOOTHING_CFG | ||||
| 	{ | ||||
| 		/// The type of smoothing to perform
 | ||||
| 		SmoothingType smoothingType; | ||||
| 	enum class SmoothingType { Linear = 0, Decay = 1 }; | ||||
| 
 | ||||
| 	class SmoothingCfg | ||||
| 	{ | ||||
| 	public: | ||||
| 		/// Whether to pause output
 | ||||
| 		bool pause; | ||||
| 		bool _pause; | ||||
| 
 | ||||
| 		/// 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.
 | ||||
| 		int updateInterval; | ||||
| 		int _updateInterval; | ||||
| 
 | ||||
| 		// The rate at which color frames should be written to LED device.
 | ||||
| 		double outputRate; | ||||
| 		/// The type of smoothing to perform
 | ||||
| 		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.
 | ||||
| 		double interpolationRate; | ||||
| 		double _interpolationRate; | ||||
| 
 | ||||
| 		/// 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.
 | ||||
| 		bool dithering; | ||||
| 		bool _dithering; | ||||
| 
 | ||||
| 		/// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate.
 | ||||
| 		double decay; | ||||
| 	}; | ||||
| 	/// smooth configuration list
 | ||||
| 	QVector<SMOOTHING_CFG> _cfgList; | ||||
| 		double _decay; | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	/// The type of smoothing to perform
 | ||||
| 	SmoothingType _smoothingType; | ||||
| 
 | ||||
| 	/// Pushes the colors into the frame queue and cleans outdated frames from memory.
 | ||||
| 	///
 | ||||
| 	/// @param ledColors The next colors to queue
 | ||||
| @@ -292,7 +309,7 @@ private: | ||||
| 	/// (Re-)Initializes the color-component vectors with given number of values.
 | ||||
| 	///
 | ||||
| 	/// @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
 | ||||
| 	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
 | ||||
| 	/// 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
 | ||||
| 	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
 | ||||
| 	///
 | ||||
| @@ -343,7 +360,7 @@ private: | ||||
| 	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.
 | ||||
| 	inline int64_t micros() const; | ||||
| 	static inline int64_t micros() ; | ||||
| 
 | ||||
| 	/// The time, when the rendering statistics were logged previously
 | ||||
| 	int64_t _renderedStatTime; | ||||
| @@ -368,3 +385,5 @@ private: | ||||
| 	/// @returns The frame weight.
 | ||||
| 	std::function<floatT(int64_t, int64_t, int64_t)> _weightFrame; | ||||
| }; | ||||
| 
 | ||||
| #endif // LINEARCOLORSMOOTHING_H
 | ||||
| @@ -112,14 +112,17 @@ void EffectEngine::handleUpdatedEffectList() | ||||
| { | ||||
| 	_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()) | ||||
| 	{ | ||||
| 		// add smoothing configs to Hyperion | ||||
| 		// add smoothing configurations to Hyperion | ||||
| 		if (def.args["smoothing-custom-settings"].toBool()) | ||||
| 		{ | ||||
| 			def.smoothCfg = _hyperion->updateSmoothingConfig( | ||||
| 				id, | ||||
| 				++specificId, | ||||
| 				def.args["smoothing-time_ms"].toInt(), | ||||
| 				def.args["smoothing-updateFrequency"].toDouble(), | ||||
| 				0 ); | ||||
| @@ -127,7 +130,7 @@ void EffectEngine::handleUpdatedEffectList() | ||||
| 		} | ||||
| 		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); | ||||
| 		} | ||||
| 		_availableEffects.push_back(def); | ||||
| @@ -137,11 +140,30 @@ void EffectEngine::handleUpdatedEffectList() | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	//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()) | ||||
| 	{ | ||||
| 		const EffectDefinition *effectDefinition = nullptr; | ||||
| @@ -181,7 +203,7 @@ int EffectEngine::runEffectScript(const QString &script, const QString &name, co | ||||
| 	_activeEffects.push_back(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); | ||||
| 	effect->start(); | ||||
|  | ||||
|   | ||||
| @@ -26,7 +26,7 @@ | ||||
| #include <leddevice/LedDeviceWrapper.h> | ||||
|  | ||||
| #include <hyperion/MultiColorAdjustment.h> | ||||
| #include "LinearColorSmoothing.h" | ||||
| #include <hyperion/LinearColorSmoothing.h> | ||||
|  | ||||
| #if defined(ENABLE_EFFECTENGINE) | ||||
| // 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 | ||||
| 	} | ||||
| 	else if(type == settings::SMOOTHING) | ||||
| 	{ | ||||
| 		_deviceSmooth->handleSettingsUpdate( type, config); | ||||
| 	} | ||||
|  | ||||
| 	// update once to push single color sets / adjustments/ ledlayout resizes and update ledBuffer color | ||||
| 	update(); | ||||
| @@ -707,8 +703,6 @@ void Hyperion::update() | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			_deviceSmooth->selectConfig(priorityInfo.smooth_cfg); | ||||
|  | ||||
| 			// feed smoothing in pause mode to maintain a smooth transition back to smooth mode | ||||
| 			if (_deviceSmooth->enabled() || _deviceSmooth->pause()) | ||||
| 			{ | ||||
|   | ||||
| @@ -2,16 +2,13 @@ | ||||
| #include <QDateTime> | ||||
| #include <QTimer> | ||||
|  | ||||
| #include "LinearColorSmoothing.h" | ||||
| #include <hyperion/LinearColorSmoothing.h> | ||||
| #include <hyperion/Hyperion.h> | ||||
|  | ||||
| #include <cmath> | ||||
| #include <chrono> | ||||
| #include <thread> | ||||
|  | ||||
| /// The number of microseconds per millisecond = 1000. | ||||
| const int64_t MS_PER_MICRO = 1000; | ||||
|  | ||||
| #if defined(COMPILER_GCC) | ||||
| #define ALWAYS_INLINE inline __attribute__((__always_inline__)) | ||||
| #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))); | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 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 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_OUTPUT_RATE = "outputRate"; | ||||
| 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; | ||||
|  | ||||
| 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) | ||||
| 	: QObject(hyperion) | ||||
| 	  , _log(nullptr) | ||||
| 	  , _hyperion(hyperion) | ||||
| 	  , _updateInterval(DEFAUL_UPDATEINTERVALL.count()) | ||||
| 	  , _settlingTime(DEFAUL_SETTLINGTIME) | ||||
| 	  , _timer(new QTimer(this)) | ||||
| 	  , _outputDelay(DEFAUL_OUTPUTDEPLAY) | ||||
| 	  , _smoothingType(SmoothingType::Linear) | ||||
| 	  , _prioMuxer(_hyperion->getMuxerInstance()) | ||||
| 	  , _updateInterval(DEFAULT_UPDATEINTERVALL.count()) | ||||
| 	  , _settlingTime(DEFAULT_SETTLINGTIME) | ||||
| 	  , _timer(nullptr) | ||||
| 	  , _outputDelay(DEFAULT_OUTPUTDEPLAY) | ||||
| 	  , _pause(false) | ||||
| 	  , _currentConfigId(0) | ||||
| 	  , _currentConfigId(SmoothingConfigID::SYSTEM) | ||||
| 	  , _enabled(false) | ||||
| 	  , _smoothingType(SmoothingType::Linear) | ||||
| 	  , tempValues(std::vector<uint64_t>(0, 0L)) | ||||
| { | ||||
| 	QString subComponent = hyperion->property("instance").toString(); | ||||
| 	_log= Logger::getInstance("SMOOTHING", subComponent); | ||||
|  | ||||
| 	// init cfg 0 (default) | ||||
| 	addConfig(DEFAUL_SETTLINGTIME, DEFAUL_UPDATEFREQUENCY, DEFAUL_OUTPUTDEPLAY); | ||||
| 	// timer | ||||
| 	_timer = new QTimer(this); | ||||
| 	_timer->setTimerType(Qt::PreciseTimer); | ||||
|  | ||||
| 	// init cfg (default) | ||||
| 	updateConfig(SmoothingConfigID::SYSTEM, DEFAULT_SETTLINGTIME, DEFAULT_UPDATEFREQUENCY, DEFAULT_OUTPUTDEPLAY); | ||||
| 	handleSettingsUpdate(settings::SMOOTHING, config); | ||||
| 	selectConfig(0, true); | ||||
|  | ||||
| 	// 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); | ||||
|  | ||||
| 	// listen for comp changes | ||||
| 	connect(_hyperion, &Hyperion::compStateChangeRequest, this, &LinearColorSmoothing::componentStateChange); | ||||
| 	// timer | ||||
| 	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) | ||||
| { | ||||
| 	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(); | ||||
| 		if (enabled() != 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(); | ||||
|  | ||||
| 		if(typeString == "linear") { | ||||
| 			cfg.smoothingType = SmoothingType::Linear; | ||||
| 		} else if(typeString == "decay") { | ||||
| 			cfg.smoothingType = SmoothingType::Decay; | ||||
| 		if(typeString == SETTINGS_KEY_DECAY) { | ||||
| 			cfg._type = SmoothingType::Decay; | ||||
| 		} | ||||
| 		else { | ||||
| 			cfg._type = SmoothingType::Linear; | ||||
| 		} | ||||
|  | ||||
| 		cfg.pause = false; | ||||
| 		cfg.settlingTime = static_cast<int64_t>(obj["time_ms"].toInt(DEFAUL_SETTLINGTIME)); | ||||
| 		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); | ||||
| 		cfg._pause = false; | ||||
| 		cfg._outputDelay = static_cast<unsigned>(obj[SETTINGS_KEY_OUTPUT_DELAY].toInt(DEFAULT_OUTPUTDEPLAY)); | ||||
|  | ||||
| 		//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 ); | ||||
| 		_cfgList[0] = cfg; | ||||
| 		cfg._outputRate = obj[SETTINGS_KEY_OUTPUT_RATE].toDouble(DEFAULT_UPDATEFREQUENCY); | ||||
| 		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 (_currentConfigId == 0) | ||||
| 		if (_currentConfigId == SmoothingConfigID::SYSTEM) | ||||
| 		{ | ||||
| 			//Debug( _log, "_currentConfigId == 0"); | ||||
| 			selectConfig(0, true); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			//Debug( _log, "_currentConfigId != 0"); | ||||
| 			selectConfig(SmoothingConfigID::SYSTEM, true); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -145,8 +166,7 @@ int LinearColorSmoothing::write(const std::vector<ColorRgb> &ledValues) | ||||
| 		_previousValues = ledValues; | ||||
| 		_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 ); | ||||
| 		QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval)); | ||||
| 		_timer->start(_updateInterval); | ||||
| 	} | ||||
|  | ||||
| 	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(); | ||||
| 	return (std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch())).count(); | ||||
| @@ -215,7 +235,7 @@ void LinearColorSmoothing::assembleAndDitherFrame() | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// The number of leds present in each frame | ||||
| 	// The number of LEDs present in each frame | ||||
| 	const size_t N = _targetValues.size(); | ||||
|  | ||||
| 	for (size_t i = 0; i < N; ++i) | ||||
| @@ -250,7 +270,7 @@ void LinearColorSmoothing::assembleFrame() | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// The number of leds present in each frame | ||||
| 	// The number of LEDs present in each frame | ||||
| 	const size_t N = _targetValues.size(); | ||||
|  | ||||
| 	for (size_t i = 0; i < N; ++i) | ||||
| @@ -438,7 +458,6 @@ void LinearColorSmoothing::updateLeds() | ||||
| 	const int64_t now = micros(); | ||||
| 	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) | ||||
| 	{ | ||||
| 		writeDirect(); | ||||
| @@ -447,12 +466,11 @@ void LinearColorSmoothing::updateLeds() | ||||
|  | ||||
| 	switch (_smoothingType) | ||||
| 	{ | ||||
| 	case Decay: | ||||
| 	case SmoothingType::Decay: | ||||
| 		performDecay(now); | ||||
| 		break; | ||||
|  | ||||
| 	case Linear: | ||||
| 		// Linear interpolation is default | ||||
| 	case SmoothingType::Linear: | ||||
| 	default: | ||||
| 		performLinear(now); | ||||
| 		break; | ||||
| @@ -461,8 +479,6 @@ void LinearColorSmoothing::updateLeds() | ||||
|  | ||||
| void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors) | ||||
| { | ||||
| 	//Debug(_log, "rememberFrame -  before _frameQueue.size() [%d]", _frameQueue.size()); | ||||
|  | ||||
| 	const int64_t now = micros(); | ||||
|  | ||||
| 	// Maintain the queue by removing outdated frames | ||||
| @@ -478,15 +494,12 @@ void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors) | ||||
|  | ||||
| 	if (p > 0) | ||||
| 	{ | ||||
| 		//Debug(_log, "rememberFrame -  erasing %d frames", p); | ||||
| 		_frameQueue.erase(_frameQueue.begin(), _frameQueue.begin() + p); | ||||
| 	} | ||||
|  | ||||
| 	// Append the latest frame at back of the queue | ||||
| 	const REMEMBERED_FRAME frame = REMEMBERED_FRAME(now, ledColors); | ||||
| 	_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() | ||||
| { | ||||
| 	QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection); | ||||
| 	_timer->stop(); | ||||
| 	//QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection); | ||||
| 	_previousValues.clear(); | ||||
|  | ||||
| 	_targetValues.clear(); | ||||
| @@ -566,71 +580,65 @@ void LinearColorSmoothing::setPause(bool pause) | ||||
|  | ||||
| unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay) | ||||
| { | ||||
| 	SMOOTHING_CFG cfg = { | ||||
| 		SmoothingType::Linear, | ||||
| 	SmoothingCfg cfg { | ||||
| 		false, | ||||
| 		settlingTime_ms, | ||||
| 		static_cast<int>(1000.0 / ledUpdateFrequency_hz), | ||||
| 		static_cast<int>(MS_PER_MICRO / ledUpdateFrequency_hz), | ||||
| 		SmoothingType::Linear, | ||||
| 		ledUpdateFrequency_hz, | ||||
| 		ledUpdateFrequency_hz, | ||||
| 		updateDelay, | ||||
| 		false, | ||||
| 		1 | ||||
| 		updateDelay | ||||
| 	}; | ||||
| 	_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; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| 	if (cfgID < static_cast<unsigned>(_cfgList.count())) | ||||
| 	int updatedCfgID = cfgID; | ||||
| 	if (cfgID < _cfgList.count()) | ||||
| 	{ | ||||
| 		SMOOTHING_CFG cfg = { | ||||
| 			SmoothingType::Linear, | ||||
| 		SmoothingCfg cfg { | ||||
| 			false, | ||||
| 			settlingTime_ms, | ||||
| 			static_cast<int>(1000.0 / ledUpdateFrequency_hz), | ||||
| 			static_cast<int>(MS_PER_MICRO / ledUpdateFrequency_hz), | ||||
| 			SmoothingType::Linear, | ||||
| 			ledUpdateFrequency_hz, | ||||
| 			ledUpdateFrequency_hz, | ||||
| 			updateDelay, | ||||
| 			false, | ||||
| 			1}; | ||||
| 			updateDelay | ||||
| 		}; | ||||
| 		_cfgList[updatedCfgID] = cfg; | ||||
| 		DebugIf(verbose && _enabled, _log,"%s", QSTRING_CSTR(getConfig(updatedCfgID))); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| 	} | ||||
|  | ||||
| 	//Debug( _log, "selectConfig FORCED - _currentConfigId [%u], force [%d]", cfg, force); | ||||
| 	if (cfg < static_cast<uint>(_cfgList.count()) ) | ||||
| 	if (cfgID < _cfgList.count() ) | ||||
| 	{ | ||||
| 		_smoothingType = _cfgList[cfg].smoothingType; | ||||
| 		_settlingTime = _cfgList[cfg].settlingTime; | ||||
| 		_outputDelay = _cfgList[cfg].outputDelay; | ||||
| 		_pause = _cfgList[cfg].pause; | ||||
| 		_outputRate = _cfgList[cfg].outputRate; | ||||
| 		_smoothingType = _cfgList[cfgID]._type; | ||||
| 		_settlingTime = _cfgList[cfgID]._settlingTime; | ||||
| 		_outputDelay = _cfgList[cfgID]._outputDelay; | ||||
| 		_pause = _cfgList[cfgID]._pause; | ||||
| 		_outputRate = _cfgList[cfgID]._outputRate; | ||||
| 		_outputIntervalMicros = int64_t(1000000.0 / _outputRate); // 1s = 1e6 µs | ||||
| 		_interpolationRate = _cfgList[cfg].interpolationRate; | ||||
| 		_interpolationRate = _cfgList[cfgID]._interpolationRate; | ||||
| 		_interpolationIntervalMicros = int64_t(1000000.0 / _interpolationRate); | ||||
| 		_dithering = _cfgList[cfg].dithering; | ||||
| 		_decay = _cfgList[cfg].decay; | ||||
| 		_dithering = _cfgList[cfgID]._dithering; | ||||
| 		_decay = _cfgList[cfgID]._decay; | ||||
| 		_invWindow = 1.0F / (MS_PER_MICRO * _settlingTime); | ||||
|  | ||||
| 		// Set _weightFrame based on the given decay | ||||
| @@ -661,33 +669,95 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force) | ||||
| 		_interpolationCounter = 0; | ||||
| 		_interpolationStatCounter = 0; | ||||
|  | ||||
| 		if (_cfgList[cfg].updateInterval != _updateInterval) | ||||
| 		if (_cfgList[cfgID]._updateInterval != _updateInterval) | ||||
| 		{ | ||||
|  | ||||
| 			QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection); | ||||
| 			_updateInterval = _cfgList[cfg].updateInterval; | ||||
| 			_timer->stop(); | ||||
| 			_updateInterval = _cfgList[cfgID]._updateInterval; | ||||
| 			if (this->enabled()) | ||||
| 			{ | ||||
| 				//Debug( _log, "_cfgList[cfg].updateInterval != _updateInterval - Restart timer - _updateInterval [%d]", _updateInterval); | ||||
| 				QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval)); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				//Debug( _log, "Smoothing disabled, do NOT restart timer"); | ||||
| 				_timer->start(_updateInterval); | ||||
| 			} | ||||
| 		} | ||||
| 		_currentConfigId = cfg; | ||||
| 		// 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() && !_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); | ||||
| 		_currentConfigId = cfgID; | ||||
| 		DebugIf(_enabled, _log,"%s", QSTRING_CSTR(getConfig(_currentConfigId))); | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	// reset to default | ||||
| 	_currentConfigId = 0; | ||||
| 	_currentConfigId = SmoothingConfigID::SYSTEM; | ||||
| 	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.origin         = "System"; | ||||
| 	_lowestPriorityInfo.owner          = ""; | ||||
| 	_lowestPriorityInfo.smooth_cfg	   = 0; | ||||
|  | ||||
| 	_activeInputs[PriorityMuxer::LOWEST_PRIORITY] = _lowestPriorityInfo; | ||||
|  | ||||
|   | ||||
| @@ -94,7 +94,7 @@ | ||||
|       "minimum": 0, | ||||
|       "maximum": 2048, | ||||
|       "default": 0, | ||||
|       "append": "edt_append_ms", | ||||
|       "append": "edt_append_frames", | ||||
|       "propertyOrder": 9 | ||||
|     } | ||||
|   }, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user