mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
per effect smoothing (#456)
* add dynamic smoothing first step * extend prio muxer to hold smoothing preset id * add icons for systray * fix missing changes in prio muxer * implement specific smoothing params for effects * refactoring: std::min/max to qMin/Max * some code optimization * fix schema and translation * revoke change of python include order * fix eol in effect shemas * optimize random,candle and fadecandy json schemas
This commit is contained in:
parent
6625a318ac
commit
6279dcb2a9
@ -139,23 +139,23 @@ SET( JSON_FILES
|
|||||||
config/hyperion.config.json.default
|
config/hyperion.config.json.default
|
||||||
${HYPERION_SCHEMAS}
|
${HYPERION_SCHEMAS}
|
||||||
)
|
)
|
||||||
#EXECUTE_PROCESS (
|
EXECUTE_PROCESS (
|
||||||
# COMMAND python test/jsonchecks/checkjson.py ${JSON_FILES}
|
COMMAND python test/jsonchecks/checkjson.py ${JSON_FILES}
|
||||||
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
# RESULT_VARIABLE CHECK_JSON_FAILED
|
RESULT_VARIABLE CHECK_JSON_FAILED
|
||||||
#)
|
)
|
||||||
#IF ( ${CHECK_JSON_FAILED} )
|
IF ( ${CHECK_JSON_FAILED} )
|
||||||
# MESSAGE (FATAL_ERROR "check of json files failed" )
|
MESSAGE (FATAL_ERROR "check of json files failed" )
|
||||||
#ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
#EXECUTE_PROCESS (
|
EXECUTE_PROCESS (
|
||||||
# COMMAND python test/jsonchecks/checkeffects.py effects effects/schema
|
COMMAND python test/jsonchecks/checkeffects.py effects effects/schema
|
||||||
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
# RESULT_VARIABLE CHECK_EFFECTS_FAILED
|
RESULT_VARIABLE CHECK_EFFECTS_FAILED
|
||||||
#)
|
)
|
||||||
#IF ( ${CHECK_EFFECTS_FAILED} )
|
IF ( ${CHECK_EFFECTS_FAILED} )
|
||||||
# MESSAGE (FATAL_ERROR "check of json effect files failed" )
|
MESSAGE (FATAL_ERROR "check of json effect files failed" )
|
||||||
#ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
EXECUTE_PROCESS (
|
EXECUTE_PROCESS (
|
||||||
COMMAND python test/jsonchecks/checkschema.py config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json
|
COMMAND python test/jsonchecks/checkschema.py config/hyperion.config.json.default libsrc/hyperion/hyperion.schema.json
|
||||||
|
@ -603,8 +603,15 @@
|
|||||||
"edt_conf_log_heading_title" : "Protokoll",
|
"edt_conf_log_heading_title" : "Protokoll",
|
||||||
"edt_conf_log_level_title" : "Protokollstufe",
|
"edt_conf_log_level_title" : "Protokollstufe",
|
||||||
"edt_conf_log_level_expl" : "Abhängig der Stufe sind weniger oder mehr Meldungen sichtbar.",
|
"edt_conf_log_level_expl" : "Abhängig der Stufe sind weniger oder mehr Meldungen sichtbar.",
|
||||||
|
"edt_eff_smooth_custom_title" : "Aktivere Glättung",
|
||||||
|
"edt_eff_smooth_time_ms_title" : "Glättung: Zeit",
|
||||||
|
"edt_eff_smooth_updateFrequency_title" : "Glättung: Aktualisierungsfrequenz",
|
||||||
|
"edt_eff_smooth_updateDelay_title" : "Glättung: Aktualisierungsverzögerung",
|
||||||
|
"edt_eff_smooth_pause_title" : "Glättung pausieren",
|
||||||
"edt_eff_candle_header" : "Kerze",
|
"edt_eff_candle_header" : "Kerze",
|
||||||
|
"edt_eff_candle_header_desc" : "Flackerndes Kerzenlicht",
|
||||||
"edt_eff_police_header" : "Polizei",
|
"edt_eff_police_header" : "Polizei",
|
||||||
|
"edt_eff_police_header_desc" : "Lights like a police car in action",
|
||||||
"edt_eff_fade_header" : "Farbübergang",
|
"edt_eff_fade_header" : "Farbübergang",
|
||||||
"edt_eff_rainbowmood_header" : "Regenbogen",
|
"edt_eff_rainbowmood_header" : "Regenbogen",
|
||||||
"edt_eff_rainbowmood_header_desc" : "Alle LEDs Regenbogen Farbübergang",
|
"edt_eff_rainbowmood_header_desc" : "Alle LEDs Regenbogen Farbübergang",
|
||||||
|
@ -604,9 +604,17 @@
|
|||||||
"edt_conf_log_heading_title" : "Logging",
|
"edt_conf_log_heading_title" : "Logging",
|
||||||
"edt_conf_log_level_title" : "Log-Level",
|
"edt_conf_log_level_title" : "Log-Level",
|
||||||
"edt_conf_log_level_expl" : "Depending on loglevel you see less or more messages in your log.",
|
"edt_conf_log_level_expl" : "Depending on loglevel you see less or more messages in your log.",
|
||||||
|
"edt_eff_smooth_custom_title" : "Enable smoothing",
|
||||||
|
"edt_eff_smooth_time_ms_title" : "Smoothing time",
|
||||||
|
"edt_eff_smooth_updateFrequency_title" : "Smoothing update frequency",
|
||||||
|
"edt_eff_smooth_updateDelay_title" : "Smoothing update delay",
|
||||||
|
"edt_eff_smooth_pause_title" : "Pause smoothing",
|
||||||
"edt_eff_candle_header" : "Candle",
|
"edt_eff_candle_header" : "Candle",
|
||||||
|
"edt_eff_candle_header_desc" : "Shimmering candles",
|
||||||
"edt_eff_police_header" : "Police",
|
"edt_eff_police_header" : "Police",
|
||||||
|
"edt_eff_police_header_desc" : "Lights like a police car in action",
|
||||||
"edt_eff_fade_header" : "Fade",
|
"edt_eff_fade_header" : "Fade",
|
||||||
|
"edt_eff_fade_header_desc" : "Fades between colors",
|
||||||
"edt_eff_rainbowmood_header" : "Rainbow Mood",
|
"edt_eff_rainbowmood_header" : "Rainbow Mood",
|
||||||
"edt_eff_rainbowmood_header_desc" : "All leds rainbow mood",
|
"edt_eff_rainbowmood_header_desc" : "All leds rainbow mood",
|
||||||
"edt_eff_knightrider_header" : "Knight Rider",
|
"edt_eff_knightrider_header" : "Knight Rider",
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
"sleepTime" : 0.20,
|
"sleepTime" : 0.20,
|
||||||
"brightness" : 100,
|
"brightness" : 100,
|
||||||
"color" : [ 255, 138, 0 ],
|
"color" : [ 255, 138, 0 ],
|
||||||
"candles" : "all"
|
"candles" : "all",
|
||||||
|
"smoothing-custom-settings" : true,
|
||||||
|
"smoothing-time_ms" : 500,
|
||||||
|
"smoothing-updateDelay" : 0,
|
||||||
|
"smoothing-updateFrequency" : 20.0,
|
||||||
|
"smoothing-pause" : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,17 @@ minStepTime = float(hyperion.latchTime)/1000.0
|
|||||||
currentR = currentG = currentB = 0
|
currentR = currentG = currentB = 0
|
||||||
|
|
||||||
# create color table for fading from start to end color
|
# create color table for fading from start to end color
|
||||||
steps = float(abs(max((colorEnd[0] - colorStart[0]),max((colorEnd[1] - colorStart[1]),(colorEnd[2] - colorStart[2])))))
|
steps = float(max(abs(colorEnd[0] - colorStart[0]),max(abs(colorEnd[1] - colorStart[1]),abs(colorEnd[2] - colorStart[2]))))
|
||||||
color_step = (
|
color_step = (0,0,0)
|
||||||
|
|
||||||
|
if steps == 0:
|
||||||
|
steps = 1
|
||||||
|
else:
|
||||||
|
color_step = (
|
||||||
(colorEnd[0] - colorStart[0]) / steps,
|
(colorEnd[0] - colorStart[0]) / steps,
|
||||||
(colorEnd[1] - colorStart[1]) / steps,
|
(colorEnd[1] - colorStart[1]) / steps,
|
||||||
(colorEnd[2] - colorStart[2]) / steps
|
(colorEnd[2] - colorStart[2]) / steps
|
||||||
)
|
)
|
||||||
|
|
||||||
calcChannel = lambda i: min(max(int(round(colorStart[i] + color_step[i]*step)),0), colorEnd[i] if colorStart[i] < colorEnd[i] else colorStart[i])
|
calcChannel = lambda i: min(max(int(round(colorStart[i] + color_step[i]*step)),0), colorEnd[i] if colorStart[i] < colorEnd[i] else colorStart[i])
|
||||||
colors = []
|
colors = []
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
"args" :
|
"args" :
|
||||||
{
|
{
|
||||||
"speed" : 750,
|
"speed" : 750,
|
||||||
"saturation" : 1.0
|
"saturation" : 1.0,
|
||||||
|
"smoothing-custom-settings" : true,
|
||||||
|
"smoothing-time_ms" : 200,
|
||||||
|
"smoothing-updateDelay" : 0,
|
||||||
|
"smoothing-updateFrequency" : 20.0,
|
||||||
|
"smoothing-pause" : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,70 @@
|
|||||||
"step": 0.01,
|
"step": 0.01,
|
||||||
"append" : "edt_append_s",
|
"append" : "edt_append_s",
|
||||||
"propertyOrder" : 6
|
"propertyOrder" : 6
|
||||||
|
},
|
||||||
|
"smoothing-custom-settings" :
|
||||||
|
{
|
||||||
|
"type" : "boolean",
|
||||||
|
"title" : "edt_eff_smooth_custom_title",
|
||||||
|
"default" : false,
|
||||||
|
"propertyOrder" : 7
|
||||||
|
},
|
||||||
|
"smoothing-time_ms" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_eff_smooth_time_ms_title",
|
||||||
|
"minimum" : 25,
|
||||||
|
"maximum": 600,
|
||||||
|
"default" : 200,
|
||||||
|
"append" : "edt_append_ms",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 8
|
||||||
|
},
|
||||||
|
"smoothing-updateFrequency" :
|
||||||
|
{
|
||||||
|
"type" : "number",
|
||||||
|
"title" : "edt_eff_smooth_updateFrequency_title",
|
||||||
|
"minimum" : 1.0,
|
||||||
|
"maximum" : 100.0,
|
||||||
|
"default" : 25.0,
|
||||||
|
"append" : "edt_append_hz",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 9
|
||||||
|
},
|
||||||
|
"smoothing-updateDelay" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_eff_smooth_updateDelay_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"maximum": 2048,
|
||||||
|
"default" : 0,
|
||||||
|
"append" : "edt_append_ms",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 10
|
||||||
|
},
|
||||||
|
"smoothing-pause" :
|
||||||
|
{
|
||||||
|
"type" : "boolean",
|
||||||
|
"title" : "edt_eff_smooth_pause_title",
|
||||||
|
"default" : false,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 12
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"title": "edt_eff_markerDepth",
|
"title": "edt_eff_markerDepth",
|
||||||
"default": 5,
|
"default": 5,
|
||||||
"minimum" : 1,
|
"minimum" : 0,
|
||||||
"maximum" : 50,
|
"maximum" : 50,
|
||||||
"append" : "edt_append_percent",
|
"append" : "edt_append_percent",
|
||||||
"options": {
|
"options": {
|
||||||
|
@ -20,6 +20,70 @@
|
|||||||
"maximum" : 1.0,
|
"maximum" : 1.0,
|
||||||
"step" : 0.1,
|
"step" : 0.1,
|
||||||
"propertyOrder" : 2
|
"propertyOrder" : 2
|
||||||
|
},
|
||||||
|
"smoothing-custom-settings" :
|
||||||
|
{
|
||||||
|
"type" : "boolean",
|
||||||
|
"title" : "edt_eff_smooth_custom_title",
|
||||||
|
"default" : false,
|
||||||
|
"propertyOrder" : 3
|
||||||
|
},
|
||||||
|
"smoothing-time_ms" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_eff_smooth_time_ms_title",
|
||||||
|
"minimum" : 25,
|
||||||
|
"maximum": 600,
|
||||||
|
"default" : 200,
|
||||||
|
"append" : "edt_append_ms",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 4
|
||||||
|
},
|
||||||
|
"smoothing-updateFrequency" :
|
||||||
|
{
|
||||||
|
"type" : "number",
|
||||||
|
"title" : "edt_eff_smooth_updateFrequency_title",
|
||||||
|
"minimum" : 1.0,
|
||||||
|
"maximum" : 100.0,
|
||||||
|
"default" : 25.0,
|
||||||
|
"append" : "edt_append_hz",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 5
|
||||||
|
},
|
||||||
|
"smoothing-updateDelay" :
|
||||||
|
{
|
||||||
|
"type" : "integer",
|
||||||
|
"title" : "edt_eff_smooth_updateDelay_title",
|
||||||
|
"minimum" : 0,
|
||||||
|
"maximum": 2048,
|
||||||
|
"default" : 0,
|
||||||
|
"append" : "edt_append_ms",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 6
|
||||||
|
},
|
||||||
|
"smoothing-pause" :
|
||||||
|
{
|
||||||
|
"type" : "boolean",
|
||||||
|
"title" : "edt_eff_smooth_pause_title",
|
||||||
|
"default" : false,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"smoothing-custom-settings": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyOrder" : 7
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
@ -8,4 +8,5 @@ struct EffectDefinition
|
|||||||
{
|
{
|
||||||
QString name, script, file;
|
QString name, script, file;
|
||||||
QJsonObject args;
|
QJsonObject args;
|
||||||
|
unsigned smoothCfg;
|
||||||
};
|
};
|
||||||
|
@ -48,7 +48,7 @@ public slots:
|
|||||||
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
|
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
|
||||||
|
|
||||||
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
||||||
int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, const QString &pythonScript = "", const QString &origin = "System");
|
int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, const QString &pythonScript = "", const QString &origin = "System", unsigned smoothCfg=0);
|
||||||
|
|
||||||
/// Clear any effect running on the provided channel
|
/// Clear any effect running on the provided channel
|
||||||
void channelCleared(int priority);
|
void channelCleared(int priority);
|
||||||
@ -65,7 +65,7 @@ private:
|
|||||||
bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema);
|
bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema);
|
||||||
|
|
||||||
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
/// Run the specified effect on the given priority channel and optionally specify a timeout
|
||||||
int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System");
|
int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System", unsigned smoothCfg=0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Hyperion * _hyperion;
|
Hyperion * _hyperion;
|
||||||
|
@ -47,6 +47,7 @@ class EffectEngine;
|
|||||||
class RgbChannelAdjustment;
|
class RgbChannelAdjustment;
|
||||||
class MultiColorAdjustment;
|
class MultiColorAdjustment;
|
||||||
class KODIVideoChecker;
|
class KODIVideoChecker;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
|
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
|
||||||
/// the priority muxer.
|
/// the priority muxer.
|
||||||
@ -188,6 +189,9 @@ public:
|
|||||||
|
|
||||||
int getLatchTime() const;
|
int getLatchTime() const;
|
||||||
|
|
||||||
|
/// forward smoothing config
|
||||||
|
unsigned addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
/// Writes a single color to all the leds for the given time and priority
|
/// Writes a single color to all the leds for the given time and priority
|
||||||
@ -206,8 +210,9 @@ public slots:
|
|||||||
/// @param[in] timeout_ms The time the leds are set to the given colors [ms]
|
/// @param[in] timeout_ms The time the leds are set to the given colors [ms]
|
||||||
/// @param[in] component The current component
|
/// @param[in] component The current component
|
||||||
/// @param[in] origin Who set it
|
/// @param[in] origin Who set it
|
||||||
|
/// @param[in] smoothCfg smoothing config id
|
||||||
///
|
///
|
||||||
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects = true, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System");
|
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects = true, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System", unsigned smoothCfg=SMOOTHING_MODE_DEFAULT);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Writes the given colors to all leds for the given time and priority
|
/// Writes the given colors to all leds for the given time and priority
|
||||||
|
@ -15,6 +15,11 @@
|
|||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
|
|
||||||
|
// global defines
|
||||||
|
#define SMOOTHING_MODE_DEFAULT 0
|
||||||
|
#define SMOOTHING_MODE_PAUSE 1
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The PriorityMuxer handles the priority channels. Led values input is written to the priority map
|
/// The PriorityMuxer handles the priority channels. Led values input is written to the priority map
|
||||||
/// and the muxer keeps track of all active priorities. The current priority can be queried and per
|
/// and the muxer keeps track of all active priorities. The current priority can be queried and per
|
||||||
@ -40,6 +45,8 @@ public:
|
|||||||
hyperion::Components componentId;
|
hyperion::Components componentId;
|
||||||
/// Who set it
|
/// Who set it
|
||||||
QString origin;
|
QString origin;
|
||||||
|
/// id fo smoothing config
|
||||||
|
unsigned smooth_cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The lowest possible priority, which is used when no priority channels are active
|
/// The lowest possible priority, which is used when no priority channels are active
|
||||||
@ -99,7 +106,7 @@ public:
|
|||||||
/// @param[in] component The component of the channel
|
/// @param[in] component The component of the channel
|
||||||
/// @param[in] origin Who set the channel
|
/// @param[in] origin Who set the channel
|
||||||
///
|
///
|
||||||
void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms=-1, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System");
|
void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms=-1, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System", unsigned smooth_cfg=SMOOTHING_MODE_DEFAULT);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Clears the specified priority channel
|
/// Clears the specified priority channel
|
||||||
|
@ -78,13 +78,14 @@ void Effect::registerHyperionExtensionModule()
|
|||||||
PyImport_AppendInittab("hyperion", &PyInit_hyperion);
|
PyImport_AppendInittab("hyperion", &PyInit_hyperion);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args, const QString & origin)
|
Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args, const QString & origin, unsigned smoothCfg)
|
||||||
: QThread()
|
: QThread()
|
||||||
, _mainThreadState(mainThreadState)
|
, _mainThreadState(mainThreadState)
|
||||||
, _priority(priority)
|
, _priority(priority)
|
||||||
, _timeout(timeout)
|
, _timeout(timeout)
|
||||||
, _script(script)
|
, _script(script)
|
||||||
, _name(name)
|
, _name(name)
|
||||||
|
, _smoothCfg(smoothCfg)
|
||||||
, _args(args)
|
, _args(args)
|
||||||
, _endTime(-1)
|
, _endTime(-1)
|
||||||
, _interpreterThreadState(nullptr)
|
, _interpreterThreadState(nullptr)
|
||||||
@ -93,7 +94,7 @@ Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const
|
|||||||
, _colors()
|
, _colors()
|
||||||
, _origin(origin)
|
, _origin(origin)
|
||||||
, _imageSize(Hyperion::getInstance()->getLedGridSize())
|
, _imageSize(Hyperion::getInstance()->getLedGridSize())
|
||||||
,_image(_imageSize,QImage::Format_ARGB32_Premultiplied)
|
, _image(_imageSize,QImage::Format_ARGB32_Premultiplied)
|
||||||
{
|
{
|
||||||
_colors.resize(_imageProcessor->getLedCount());
|
_colors.resize(_imageProcessor->getLedCount());
|
||||||
_colors.fill(ColorRgb::BLACK);
|
_colors.fill(ColorRgb::BLACK);
|
||||||
@ -277,7 +278,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
|
|||||||
if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue))
|
if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue))
|
||||||
{
|
{
|
||||||
effect->_colors.fill(color);
|
effect->_colors.fill(color);
|
||||||
effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin);
|
effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
|
||||||
return Py_BuildValue("");
|
return Py_BuildValue("");
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -295,7 +296,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
char * data = PyByteArray_AS_STRING(bytearray);
|
char * data = PyByteArray_AS_STRING(bytearray);
|
||||||
memcpy(effect->_colors.data(), data, length);
|
memcpy(effect->_colors.data(), data, length);
|
||||||
effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin);
|
effect->setColors(effect->_priority, effect->_colors.toStdVector(), timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
|
||||||
return Py_BuildValue("");
|
return Py_BuildValue("");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -365,7 +366,7 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args)
|
|||||||
memcpy(image.memptr(), data, length);
|
memcpy(image.memptr(), data, length);
|
||||||
std::vector<ColorRgb> v = effect->_colors.toStdVector();
|
std::vector<ColorRgb> v = effect->_colors.toStdVector();
|
||||||
effect->_imageProcessor->process(image, v);
|
effect->_imageProcessor->process(image, v);
|
||||||
effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin);
|
effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
|
||||||
return Py_BuildValue("");
|
return Py_BuildValue("");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -456,7 +457,7 @@ PyObject* Effect::wrapImageShow(PyObject *self, PyObject *args)
|
|||||||
memcpy(image.memptr(), binaryImage.data(), binaryImage.size());
|
memcpy(image.memptr(), binaryImage.data(), binaryImage.size());
|
||||||
std::vector<ColorRgb> v = effect->_colors.toStdVector();
|
std::vector<ColorRgb> v = effect->_colors.toStdVector();
|
||||||
effect->_imageProcessor->process(image, v);
|
effect->_imageProcessor->process(image, v);
|
||||||
effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin);
|
effect->setColors(effect->_priority, v, timeout, false, hyperion::COMP_EFFECT, effect->_origin, effect->_smoothCfg);
|
||||||
|
|
||||||
return Py_BuildValue("");
|
return Py_BuildValue("");
|
||||||
}
|
}
|
||||||
@ -552,7 +553,7 @@ PyObject* Effect::wrapImageConicalGradient(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
argsOK = true;
|
argsOK = true;
|
||||||
}
|
}
|
||||||
angle = std::max(std::min(angle,360),0);
|
angle = qMax(qMin(angle,360),0);
|
||||||
|
|
||||||
if (argsOK)
|
if (argsOK)
|
||||||
{
|
{
|
||||||
@ -644,7 +645,7 @@ PyObject* Effect::wrapImageRadialGradient(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
|
|
||||||
QRect myQRect(startX,startY,width,height);
|
QRect myQRect(startX,startY,width,height);
|
||||||
QRadialGradient gradient(QPoint(centerX,centerY), std::max(radius,0) );
|
QRadialGradient gradient(QPoint(centerX,centerY), qMax(radius,0) );
|
||||||
char * data = PyByteArray_AS_STRING(bytearray);
|
char * data = PyByteArray_AS_STRING(bytearray);
|
||||||
|
|
||||||
for (int idx=0; idx<length; idx+=4)
|
for (int idx=0; idx<length; idx+=4)
|
||||||
@ -774,8 +775,8 @@ PyObject* Effect::wrapImageDrawPie(PyObject *self, PyObject *args)
|
|||||||
if (argsOK)
|
if (argsOK)
|
||||||
{
|
{
|
||||||
QPainter * painter = effect->_painter;
|
QPainter * painter = effect->_painter;
|
||||||
startAngle = std::max(std::min(startAngle,360),0);
|
startAngle = qMax(qMin(startAngle,360),0);
|
||||||
spanAngle = std::max(std::min(spanAngle,360),-360);
|
spanAngle = qMax(qMin(spanAngle,360),-360);
|
||||||
|
|
||||||
if( argCount == 7 || argCount == 5 )
|
if( argCount == 7 || argCount == 5 )
|
||||||
{
|
{
|
||||||
@ -1045,7 +1046,7 @@ PyObject* Effect::wrapImageMinSize(PyObject *self, PyObject *args)
|
|||||||
{
|
{
|
||||||
delete effect->_painter;
|
delete effect->_painter;
|
||||||
|
|
||||||
effect->_image = effect->_image.scaled(std::max(width,w),std::max(height,h), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
effect->_image = effect->_image.scaled(qMax(width,w),qMax(height,h), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||||
effect->_imageSize = effect->_image.size();
|
effect->_imageSize = effect->_image.size();
|
||||||
effect->_painter = new QPainter(&(effect->_image));
|
effect->_painter = new QPainter(&(effect->_image));
|
||||||
}
|
}
|
||||||
@ -1075,7 +1076,7 @@ PyObject* Effect::wrapImageCRotate(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
if ( argCount == 1 && PyArg_ParseTuple(args, "i", &angle ) )
|
if ( argCount == 1 && PyArg_ParseTuple(args, "i", &angle ) )
|
||||||
{
|
{
|
||||||
angle = std::max(std::min(angle,360),0);
|
angle = qMax(qMin(angle,360),0);
|
||||||
effect->_painter->rotate(angle);
|
effect->_painter->rotate(angle);
|
||||||
return Py_BuildValue("");
|
return Py_BuildValue("");
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class Effect : public QThread
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject(), const QString & origin="System");
|
Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject(), const QString & origin="System", unsigned smoothCfg=0);
|
||||||
virtual ~Effect();
|
virtual ~Effect();
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
@ -44,7 +44,7 @@ public slots:
|
|||||||
signals:
|
signals:
|
||||||
void effectFinished(Effect * effect);
|
void effectFinished(Effect * effect);
|
||||||
|
|
||||||
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components componentconst, QString origin);
|
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components componentconst, QString origin, unsigned smoothCfg);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void effectFinished();
|
void effectFinished();
|
||||||
@ -96,6 +96,7 @@ private:
|
|||||||
|
|
||||||
const QString _script;
|
const QString _script;
|
||||||
const QString _name;
|
const QString _name;
|
||||||
|
unsigned _smoothCfg;
|
||||||
|
|
||||||
const QJsonObject _args;
|
const QJsonObject _args;
|
||||||
|
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#undef B0
|
#undef B0
|
||||||
|
|
||||||
// Stl includes
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QResource>
|
#include <QResource>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
// hyperion util includes
|
// hyperion util includes
|
||||||
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
||||||
@ -41,7 +39,7 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const QJsonObject & jsonEffectCo
|
|||||||
readEffects();
|
readEffects();
|
||||||
|
|
||||||
// initialize the python interpreter
|
// initialize the python interpreter
|
||||||
Debug(_log,"Initializing Python interpreter");
|
Debug(_log, "Initializing Python interpreter");
|
||||||
Effect::registerHyperionExtensionModule();
|
Effect::registerHyperionExtensionModule();
|
||||||
Py_InitializeEx(0);
|
Py_InitializeEx(0);
|
||||||
PyEval_InitThreads(); // Create the GIL
|
PyEval_InitThreads(); // Create the GIL
|
||||||
@ -86,7 +84,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
|
|||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
Error( log, "Effect file '%s' could not be loaded", fileName.toUtf8().constData());
|
Error( log, "Effect file '%s' could not be loaded", QSTRING_CSTR(fileName));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +106,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Error( log, "Error while reading effect: '%s' at Line: '%i' , Column: %i", error.errorString().toUtf8().constData(), errorLine, errorColumn);
|
Error( log, "Error while reading effect: '%s' at Line: '%i' , Column: %i",QSTRING_CSTR( error.errorString()), errorLine, errorColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
@ -120,7 +118,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
|
|||||||
|
|
||||||
if (!schema.open(QIODevice::ReadOnly))
|
if (!schema.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
Error( log, "Schema not found: %s", schema.errorString().toUtf8().constData());
|
Error( log, "Schema not found: %s", QSTRING_CSTR(schema.errorString()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +140,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Error( log, "ERROR: Json schema wrong: '%s' at Line: '%i' , Column: %i", error.errorString().toUtf8().constData(), errorLine, errorColumn);
|
Error( log, "ERROR: Json schema wrong: '%s' at Line: '%i' , Column: %i", QSTRING_CSTR(error.errorString()), errorLine, errorColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.close();
|
schema.close();
|
||||||
@ -154,7 +152,7 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
|
|||||||
if (!schemaChecker.validate(configEffect.object()).first)
|
if (!schemaChecker.validate(configEffect.object()).first)
|
||||||
{
|
{
|
||||||
const QStringList & errors = schemaChecker.getMessages();
|
const QStringList & errors = schemaChecker.getMessages();
|
||||||
foreach (auto & error, errors)
|
for (auto & error : errors)
|
||||||
{
|
{
|
||||||
Error( log, "Error while checking '%s':%s", QSTRING_CSTR(fileName), QSTRING_CSTR(error));
|
Error( log, "Error while checking '%s':%s", QSTRING_CSTR(fileName), QSTRING_CSTR(error));
|
||||||
}
|
}
|
||||||
@ -180,12 +178,27 @@ bool EffectEngine::loadEffectDefinition(const QString &path, const QString &effe
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
(!fileInfo.exists())
|
(!fileInfo.exists())
|
||||||
? effectDefinition.script = path + QDir::separator().toLatin1() + scriptName
|
? effectDefinition.script = path + QDir::separator() + scriptName
|
||||||
: effectDefinition.script = scriptName;
|
: effectDefinition.script = scriptName;
|
||||||
}
|
}
|
||||||
|
|
||||||
effectDefinition.args = config["args"].toObject();
|
effectDefinition.args = config["args"].toObject();
|
||||||
|
effectDefinition.smoothCfg = SMOOTHING_MODE_PAUSE;
|
||||||
|
if (effectDefinition.args["smoothing-custom-settings"].toBool())
|
||||||
|
{
|
||||||
|
bool pause = effectDefinition.args["smoothing-pause"].toBool();
|
||||||
|
if (pause)
|
||||||
|
{
|
||||||
|
effectDefinition.smoothCfg = _hyperion->addSmoothingConfig(pause);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
effectDefinition.smoothCfg = _hyperion->addSmoothingConfig(
|
||||||
|
effectDefinition.args["smoothing-time_ms"].toInt(),
|
||||||
|
effectDefinition.args["smoothing-updateFrequency"].toDouble(),
|
||||||
|
effectDefinition.args["smoothing-updateDelay"].toInt() );
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +214,7 @@ bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSc
|
|||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
Error( log, "Effect schema '%s' could not be loaded", fileName.toUtf8().constData());
|
Error( log, "Effect schema '%s' could not be loaded", QSTRING_CSTR(fileName));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +236,7 @@ bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Error( log, "Error while reading effect schema: '%s' at Line: '%i' , Column: %i", error.errorString().toUtf8().constData(), errorLine, errorColumn);
|
Error( log, "Error while reading effect schema: '%s' at Line: '%i' , Column: %i", QSTRING_CSTR(error.errorString()), errorLine, errorColumn);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,17 +253,13 @@ bool EffectEngine::loadEffectSchema(const QString &path, const QString &effectSc
|
|||||||
if (scriptName.isEmpty() || !pyFile.open(QIODevice::ReadOnly))
|
if (scriptName.isEmpty() || !pyFile.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
|
fileName = path + "schema/" + QDir::separator() + effectSchemaFile;
|
||||||
Error( log, "Python script '%s' in effect schema '%s' could not be loaded", scriptName.toUtf8().constData(), fileName.toUtf8().constData());
|
Error( log, "Python script '%s' in effect schema '%s' could not be loaded", QSTRING_CSTR(scriptName), QSTRING_CSTR(fileName));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pyFile.close();
|
pyFile.close();
|
||||||
|
|
||||||
if (scriptName.mid(0, 1) == ":" )
|
effectSchema.pyFile = (scriptName.mid(0, 1) == ":" ) ? ":/effects/"+scriptName.mid(1) : path + QDir::separator() + scriptName;
|
||||||
effectSchema.pyFile = ":/effects/"+scriptName.mid(1);
|
|
||||||
else
|
|
||||||
effectSchema.pyFile = path + QDir::separator().toLatin1() + scriptName;
|
|
||||||
|
|
||||||
effectSchema.pySchema = tempSchemaEffect;
|
effectSchema.pySchema = tempSchemaEffect;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -279,38 +288,36 @@ void EffectEngine::readEffects()
|
|||||||
disableList << efx.toString();
|
disableList << efx.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<QString, EffectDefinition> availableEffects;
|
QMap<QString, EffectDefinition> availableEffects;
|
||||||
foreach (const QString & path, efxPathList )
|
for (const QString & path : efxPathList )
|
||||||
{
|
{
|
||||||
QDir directory(path);
|
QDir directory(path);
|
||||||
if (!directory.exists())
|
if (!directory.exists())
|
||||||
{
|
{
|
||||||
if(directory.mkpath(path))
|
if(directory.mkpath(path))
|
||||||
{
|
{
|
||||||
Warning(_log, "New Effect path \"%s\" created successfull",path.toUtf8().constData() );
|
Warning(_log, "New Effect path \"%s\" created successfull", QSTRING_CSTR(path) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Warning(_log, "Failed to create Effect path \"%s\", please check permissions",path.toUtf8().constData() );
|
Warning(_log, "Failed to create Effect path \"%s\", please check permissions", QSTRING_CSTR(path) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int efxCount = 0;
|
int efxCount = 0;
|
||||||
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
||||||
foreach (const QString & filename, filenames)
|
for (const QString & filename : filenames)
|
||||||
{
|
{
|
||||||
EffectDefinition def;
|
EffectDefinition def;
|
||||||
if (loadEffectDefinition(path, filename, def))
|
if (loadEffectDefinition(path, filename, def))
|
||||||
{
|
{
|
||||||
if (availableEffects.find(def.name) != availableEffects.end())
|
InfoIf(availableEffects.find(def.name) != availableEffects.end(), _log,
|
||||||
{
|
"effect overload effect '%s' is now taken from %s'", QSTRING_CSTR(def.name), QSTRING_CSTR(path) );
|
||||||
Info(_log, "effect overload effect '%s' is now taken from %s'", def.name.toUtf8().constData(), path.toUtf8().constData() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( disableList.contains(def.name) )
|
if ( disableList.contains(def.name) )
|
||||||
{
|
{
|
||||||
Info(_log, "effect '%s' not loaded, because it is disabled in hyperion config", def.name.toUtf8().constData());
|
Info(_log, "effect '%s' not loaded, because it is disabled in hyperion config", QSTRING_CSTR(def.name));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -319,13 +326,13 @@ void EffectEngine::readEffects()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Info(_log, "%d effects loaded from directory %s", efxCount, path.toUtf8().constData());
|
Info(_log, "%d effects loaded from directory %s", efxCount, QSTRING_CSTR(path));
|
||||||
|
|
||||||
// collect effect schemas
|
// collect effect schemas
|
||||||
efxCount = 0;
|
efxCount = 0;
|
||||||
directory = path + "schema/";
|
directory = path + "schema/";
|
||||||
QStringList pynames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
QStringList pynames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
|
||||||
foreach (const QString & pyname, pynames)
|
for (const QString & pyname : pynames)
|
||||||
{
|
{
|
||||||
EffectSchema pyEffect;
|
EffectSchema pyEffect;
|
||||||
if (loadEffectSchema(path, pyname, pyEffect))
|
if (loadEffectSchema(path, pyname, pyEffect))
|
||||||
@ -334,20 +341,16 @@ void EffectEngine::readEffects()
|
|||||||
efxCount++;
|
efxCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (efxCount > 0)
|
InfoIf(efxCount > 0, _log, "%d effect schemas loaded from directory %s", efxCount, QSTRING_CSTR((path + "schema/")));
|
||||||
Info(_log, "%d effect schemas loaded from directory %s", efxCount, (path + "schema/").toUtf8().constData());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(auto item, availableEffects)
|
for(auto item : availableEffects)
|
||||||
{
|
{
|
||||||
_availableEffects.push_back(item.second);
|
_availableEffects.push_back(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_availableEffects.size() == 0)
|
ErrorIf(_availableEffects.size()==0, _log, "no effects found, check your effect directories");
|
||||||
{
|
|
||||||
Error(_log, "no effects found, check your effect directories");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -355,9 +358,9 @@ int EffectEngine::runEffect(const QString &effectName, int priority, int timeout
|
|||||||
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
|
return runEffect(effectName, QJsonObject(), priority, timeout, "", origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin)
|
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg)
|
||||||
{
|
{
|
||||||
Info( _log, "run effect %s on channel %d", effectName.toUtf8().constData(), priority);
|
Info( _log, "run effect %s on channel %d", QSTRING_CSTR(effectName), priority);
|
||||||
|
|
||||||
if (pythonScript.isEmpty())
|
if (pythonScript.isEmpty())
|
||||||
{
|
{
|
||||||
@ -373,23 +376,23 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args,
|
|||||||
if (effectDefinition == nullptr)
|
if (effectDefinition == nullptr)
|
||||||
{
|
{
|
||||||
// no such effect
|
// no such effect
|
||||||
Error(_log, "effect %s not found", effectName.toUtf8().constData());
|
Error(_log, "effect %s not found", QSTRING_CSTR(effectName));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin);
|
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin, effectDefinition->smoothCfg);
|
||||||
}
|
}
|
||||||
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin);
|
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin, smoothCfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin)
|
int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin, unsigned smoothCfg)
|
||||||
{
|
{
|
||||||
// clear current effect on the channel
|
// clear current effect on the channel
|
||||||
channelCleared(priority);
|
channelCleared(priority);
|
||||||
|
|
||||||
// create the effect
|
// create the effect
|
||||||
Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args, origin);
|
Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args, origin, smoothCfg);
|
||||||
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString)), Qt::QueuedConnection);
|
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString,unsigned)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int,bool,hyperion::Components,const QString,unsigned)), Qt::QueuedConnection);
|
||||||
connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*)));
|
connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*)));
|
||||||
_activeEffects.push_back(effect);
|
_activeEffects.push_back(effect);
|
||||||
|
|
||||||
|
@ -31,8 +31,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height)
|
AmlogicGrabber::AmlogicGrabber(const unsigned width, const unsigned height)
|
||||||
: _width(std::max(160u, width)) // Minimum required width or height is 160
|
: _width(qMax(160u, width)) // Minimum required width or height is 160
|
||||||
, _height(std::max(160u, height))
|
, _height(qMax(160u, height))
|
||||||
, _amlogicCaptureDev(-1)
|
, _amlogicCaptureDev(-1)
|
||||||
, _log(Logger::getInstance("AMLOGICGRABBER"))
|
, _log(Logger::getInstance("AMLOGICGRABBER"))
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ V4L2Grabber::V4L2Grabber(const QString & device
|
|||||||
, _height(height)
|
, _height(height)
|
||||||
, _lineLength(-1)
|
, _lineLength(-1)
|
||||||
, _frameByteSize(-1)
|
, _frameByteSize(-1)
|
||||||
, _frameDecimation(std::max(1, frameDecimation))
|
, _frameDecimation(qMax(1, frameDecimation))
|
||||||
, _noSignalCounterThreshold(50)
|
, _noSignalCounterThreshold(50)
|
||||||
, _noSignalThresholdColor(ColorRgb{0,0,0})
|
, _noSignalThresholdColor(ColorRgb{0,0,0})
|
||||||
, _signalDetectionEnabled(true)
|
, _signalDetectionEnabled(true)
|
||||||
@ -62,8 +62,8 @@ V4L2Grabber::V4L2Grabber(const QString & device
|
|||||||
, _deviceAutoDiscoverEnabled(false)
|
, _deviceAutoDiscoverEnabled(false)
|
||||||
|
|
||||||
{
|
{
|
||||||
_imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation));
|
_imageResampler.setHorizontalPixelDecimation(qMax(1, horizontalPixelDecimation));
|
||||||
_imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation));
|
_imageResampler.setVerticalPixelDecimation(qMax(1, verticalPixelDecimation));
|
||||||
|
|
||||||
getV4Ldevices();
|
getV4Ldevices();
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSign
|
|||||||
_noSignalThresholdColor.red = uint8_t(255*redSignalThreshold);
|
_noSignalThresholdColor.red = uint8_t(255*redSignalThreshold);
|
||||||
_noSignalThresholdColor.green = uint8_t(255*greenSignalThreshold);
|
_noSignalThresholdColor.green = uint8_t(255*greenSignalThreshold);
|
||||||
_noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold);
|
_noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold);
|
||||||
_noSignalCounterThreshold = std::max(1, noSignalCounterThreshold);
|
_noSignalCounterThreshold = qMax(1, noSignalCounterThreshold);
|
||||||
|
|
||||||
Info(_log, "Signal threshold set to: {%d, %d, %d}", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue );
|
Info(_log, "Signal threshold set to: {%d, %d, %d}", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue );
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
// STL includes
|
|
||||||
#include <iostream>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
|
|
||||||
// X11Grabber includes
|
|
||||||
#include <grabber/X11Grabber.h>
|
#include <grabber/X11Grabber.h>
|
||||||
|
|
||||||
X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation)
|
X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation)
|
||||||
@ -137,7 +132,7 @@ Image<ColorRgb> & X11Grabber::grab()
|
|||||||
{
|
{
|
||||||
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
|
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
|
||||||
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
|
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
|
||||||
double scale = std::min(scale_y, scale_x);
|
double scale = qMin(scale_y, scale_x);
|
||||||
|
|
||||||
_transform =
|
_transform =
|
||||||
{
|
{
|
||||||
@ -215,7 +210,7 @@ int X11Grabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
{
|
{
|
||||||
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
|
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
|
||||||
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
|
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
|
||||||
double scale = std::min(scale_y, scale_x);
|
double scale = qMin(scale_y, scale_x);
|
||||||
|
|
||||||
_transform =
|
_transform =
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
|
|
||||||
// STL includes
|
// STL includes
|
||||||
#include <cassert>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
// QT includes
|
// QT includes
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
@ -208,10 +206,10 @@ LedString Hyperion::createLedString(const QJsonValue& ledsConfig, const ColorOrd
|
|||||||
{
|
{
|
||||||
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
|
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
|
||||||
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
|
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
|
||||||
led.minX_frac = std::max(0.0, std::min(1.0, hscanConfig["minimum"].toDouble()));
|
led.minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble()));
|
||||||
led.maxX_frac = std::max(0.0, std::min(1.0, hscanConfig["maximum"].toDouble()));
|
led.maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble()));
|
||||||
led.minY_frac = std::max(0.0, std::min(1.0, vscanConfig["minimum"].toDouble()));
|
led.minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble()));
|
||||||
led.maxY_frac = std::max(0.0, std::min(1.0, vscanConfig["maximum"].toDouble()));
|
led.maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble()));
|
||||||
// Fix if the user swapped min and max
|
// Fix if the user swapped min and max
|
||||||
if (led.minX_frac > led.maxX_frac)
|
if (led.minX_frac > led.maxX_frac)
|
||||||
{
|
{
|
||||||
@ -287,10 +285,10 @@ QSize Hyperion::getLedLayoutGridSize(const QJsonValue& ledsConfig)
|
|||||||
{
|
{
|
||||||
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
|
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
|
||||||
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
|
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
|
||||||
double minX_frac = std::max(0.0, std::min(1.0, hscanConfig["minimum"].toDouble()));
|
double minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble()));
|
||||||
double maxX_frac = std::max(0.0, std::min(1.0, hscanConfig["maximum"].toDouble()));
|
double maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble()));
|
||||||
double minY_frac = std::max(0.0, std::min(1.0, vscanConfig["minimum"].toDouble()));
|
double minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble()));
|
||||||
double maxY_frac = std::max(0.0, std::min(1.0, vscanConfig["maximum"].toDouble()));
|
double maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble()));
|
||||||
// Fix if the user swapped min and max
|
// Fix if the user swapped min and max
|
||||||
if (minX_frac > maxX_frac)
|
if (minX_frac > maxX_frac)
|
||||||
{
|
{
|
||||||
@ -345,7 +343,7 @@ LinearColorSmoothing * Hyperion::createColorSmoothing(const QJsonObject & smooth
|
|||||||
device->setEnable(smoothingConfig["enable"].toBool(true));
|
device->setEnable(smoothingConfig["enable"].toBool(true));
|
||||||
InfoIf(!device->enabled(), CORE_LOGGER,"Smoothing disabled");
|
InfoIf(!device->enabled(), CORE_LOGGER,"Smoothing disabled");
|
||||||
|
|
||||||
assert(device != nullptr);
|
Q_ASSERT(device != nullptr);
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,6 +425,8 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
|
|||||||
getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState());
|
getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState());
|
||||||
getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState());
|
getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState());
|
||||||
|
|
||||||
|
_deviceSmooth->addConfig(true); // add pause to config 1
|
||||||
|
|
||||||
// setup the timer
|
// setup the timer
|
||||||
_timer.setSingleShot(true);
|
_timer.setSingleShot(true);
|
||||||
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
|
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||||
@ -436,12 +436,12 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
|
|||||||
QObject::connect(&_timerBonjourResolver, SIGNAL(timeout()), this, SLOT(bonjourResolve()));
|
QObject::connect(&_timerBonjourResolver, SIGNAL(timeout()), this, SLOT(bonjourResolve()));
|
||||||
_timerBonjourResolver.start();
|
_timerBonjourResolver.start();
|
||||||
|
|
||||||
// create the effect engine
|
// create the effect engine, must be initialized after smoothing!
|
||||||
_effectEngine = new EffectEngine(this,qjsonConfig["effects"].toObject() );
|
_effectEngine = new EffectEngine(this,qjsonConfig["effects"].toObject() );
|
||||||
|
|
||||||
const QJsonObject& device = qjsonConfig["device"].toObject();
|
const QJsonObject& device = qjsonConfig["device"].toObject();
|
||||||
unsigned int hwLedCount = device["ledCount"].toInt(getLedCount());
|
unsigned int hwLedCount = device["ledCount"].toInt(getLedCount());
|
||||||
_hwLedCount = std::max(hwLedCount, getLedCount());
|
_hwLedCount = qMax(hwLedCount, getLedCount());
|
||||||
Debug(_log,"configured leds: %d hw leds: %d", getLedCount(), _hwLedCount);
|
Debug(_log,"configured leds: %d hw leds: %d", getLedCount(), _hwLedCount);
|
||||||
WarningIf(hwLedCount < getLedCount(), _log, "more leds configured than available. check 'ledCount' in 'device' section");
|
WarningIf(hwLedCount < getLedCount(), _log, "more leds configured than available. check 'ledCount' in 'device' section");
|
||||||
|
|
||||||
@ -478,6 +478,11 @@ int Hyperion::getLatchTime() const
|
|||||||
return _device->getLatchTime();
|
return _device->getLatchTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned Hyperion::addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
||||||
|
{
|
||||||
|
return _deviceSmooth->addConfig(settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
|
||||||
|
}
|
||||||
|
|
||||||
void Hyperion::freeObjects(bool emitCloseSignal)
|
void Hyperion::freeObjects(bool emitCloseSignal)
|
||||||
{
|
{
|
||||||
if (emitCloseSignal)
|
if (emitCloseSignal)
|
||||||
@ -664,7 +669,7 @@ void Hyperion::setColor(int priority, const ColorRgb &color, const int timeout_m
|
|||||||
setColors(priority, ledColors, timeout_ms, clearEffects, hyperion::COMP_COLOR);
|
setColors(priority, ledColors, timeout_ms, clearEffects, hyperion::COMP_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, bool clearEffects, hyperion::Components component, const QString origin)
|
void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, bool clearEffects, hyperion::Components component, const QString origin, unsigned smoothCfg)
|
||||||
{
|
{
|
||||||
// clear effects if this call does not come from an effect
|
// clear effects if this call does not come from an effect
|
||||||
if (clearEffects)
|
if (clearEffects)
|
||||||
@ -675,11 +680,11 @@ void Hyperion::setColors(int priority, const std::vector<ColorRgb>& ledColors, c
|
|||||||
if (timeout_ms > 0)
|
if (timeout_ms > 0)
|
||||||
{
|
{
|
||||||
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
|
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
|
||||||
_muxer.setInput(priority, ledColors, timeoutTime, component, origin);
|
_muxer.setInput(priority, ledColors, timeoutTime, component, origin, smoothCfg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_muxer.setInput(priority, ledColors, -1, component, origin);
|
_muxer.setInput(priority, ledColors, -1, component, origin, smoothCfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! _sourceAutoSelectEnabled || priority == _muxer.getCurrentPriority())
|
if (! _sourceAutoSelectEnabled || priority == _muxer.getCurrentPriority())
|
||||||
@ -891,7 +896,8 @@ void Hyperion::update()
|
|||||||
// Write the data to the device
|
// Write the data to the device
|
||||||
if (_device->enabled())
|
if (_device->enabled())
|
||||||
{
|
{
|
||||||
_deviceSmooth->setPause(priorityInfo.componentId == hyperion::COMP_EFFECT);
|
_deviceSmooth->selectConfig(priorityInfo.smooth_cfg);
|
||||||
|
|
||||||
// feed smoothing in pause mode to maintain a smooth transistion back to smoth mode
|
// feed smoothing in pause mode to maintain a smooth transistion back to smoth mode
|
||||||
if (_deviceSmooth->enabled() || _deviceSmooth->pause())
|
if (_deviceSmooth->enabled() || _deviceSmooth->pause())
|
||||||
_deviceSmooth->setLedValues(_ledBuffer);
|
_deviceSmooth->setLedValues(_ledBuffer);
|
||||||
@ -907,9 +913,9 @@ void Hyperion::update()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int timeout_ms = std::max(0, int(priorityInfo.timeoutTime_ms - QDateTime::currentMSecsSinceEpoch()));
|
int timeout_ms = qMax(0, int(priorityInfo.timeoutTime_ms - QDateTime::currentMSecsSinceEpoch()));
|
||||||
// std::min() 200ms forced refresh if color is active to update priorityMuxer properly for forced serverinfo push
|
// qMin() 200ms forced refresh if color is active to update priorityMuxer properly for forced serverinfo push
|
||||||
_timer.start(std::min(timeout_ms, 200));
|
_timer.start(qMin(timeout_ms, 200));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
// STL includes
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
// hyperion includes
|
|
||||||
#include <hyperion/ImageToLedsMap.h>
|
#include <hyperion/ImageToLedsMap.h>
|
||||||
|
|
||||||
using namespace hyperion;
|
using namespace hyperion;
|
||||||
@ -21,8 +15,8 @@ ImageToLedsMap::ImageToLedsMap(
|
|||||||
, _colorsMap()
|
, _colorsMap()
|
||||||
{
|
{
|
||||||
// Sanity check of the size of the borders (and width and height)
|
// Sanity check of the size of the borders (and width and height)
|
||||||
assert(_width > 2*_verticalBorder);
|
Q_ASSERT(_width > 2*_verticalBorder);
|
||||||
assert(_height > 2*_horizontalBorder);
|
Q_ASSERT(_height > 2*_horizontalBorder);
|
||||||
|
|
||||||
// Reserve enough space in the map for the leds
|
// Reserve enough space in the map for the leds
|
||||||
_colorsMap.reserve(leds.size());
|
_colorsMap.reserve(leds.size());
|
||||||
@ -42,18 +36,18 @@ ImageToLedsMap::ImageToLedsMap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute the index boundaries for this led
|
// Compute the index boundaries for this led
|
||||||
unsigned minX_idx = xOffset + unsigned(std::round(actualWidth * led.minX_frac));
|
unsigned minX_idx = xOffset + unsigned(qRound(actualWidth * led.minX_frac));
|
||||||
unsigned maxX_idx = xOffset + unsigned(std::round(actualWidth * led.maxX_frac));
|
unsigned maxX_idx = xOffset + unsigned(qRound(actualWidth * led.maxX_frac));
|
||||||
unsigned minY_idx = yOffset + unsigned(std::round(actualHeight * led.minY_frac));
|
unsigned minY_idx = yOffset + unsigned(qRound(actualHeight * led.minY_frac));
|
||||||
unsigned maxY_idx = yOffset + unsigned(std::round(actualHeight * led.maxY_frac));
|
unsigned maxY_idx = yOffset + unsigned(qRound(actualHeight * led.maxY_frac));
|
||||||
|
|
||||||
// make sure that the area is at least a single led large
|
// make sure that the area is at least a single led large
|
||||||
minX_idx = std::min(minX_idx, xOffset + actualWidth - 1);
|
minX_idx = qMin(minX_idx, xOffset + actualWidth - 1);
|
||||||
if (minX_idx == maxX_idx)
|
if (minX_idx == maxX_idx)
|
||||||
{
|
{
|
||||||
maxX_idx = minX_idx + 1;
|
maxX_idx = minX_idx + 1;
|
||||||
}
|
}
|
||||||
minY_idx = std::min(minY_idx, yOffset + actualHeight - 1);
|
minY_idx = qMin(minY_idx, yOffset + actualHeight - 1);
|
||||||
if (minY_idx == maxY_idx)
|
if (minY_idx == maxY_idx)
|
||||||
{
|
{
|
||||||
maxY_idx = minY_idx + 1;
|
maxY_idx = minY_idx + 1;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
using namespace hyperion;
|
using namespace hyperion;
|
||||||
|
|
||||||
|
// ledUpdateFrequency_hz = 0 > cause divide by zero!
|
||||||
LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpdateFrequency_hz, int settlingTime_ms, unsigned updateDelay, bool continuousOutput)
|
LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpdateFrequency_hz, int settlingTime_ms, unsigned updateDelay, bool continuousOutput)
|
||||||
: LedDevice()
|
: LedDevice()
|
||||||
, _ledDevice(ledDevice)
|
, _ledDevice(ledDevice)
|
||||||
@ -18,14 +19,20 @@ LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpd
|
|||||||
, _writeToLedsEnable(true)
|
, _writeToLedsEnable(true)
|
||||||
, _continuousOutput(continuousOutput)
|
, _continuousOutput(continuousOutput)
|
||||||
, _pause(false)
|
, _pause(false)
|
||||||
|
, _currentConfigId(0)
|
||||||
{
|
{
|
||||||
_log = Logger::getInstance("Smoothing");
|
_log = Logger::getInstance("Smoothing");
|
||||||
_timer.setSingleShot(false);
|
_timer.setSingleShot(false);
|
||||||
_timer.setInterval(_updateInterval);
|
_timer.setInterval(_updateInterval);
|
||||||
|
|
||||||
|
selectConfig( addConfig(_settlingTime, ledUpdateFrequency_hz, updateDelay) );
|
||||||
|
|
||||||
|
// add pause on cfg 1
|
||||||
|
SMOOTHING_CFG cfg = {true, 100, 50, 0};
|
||||||
|
_cfgList.append(cfg);
|
||||||
|
Info( _log, "smoothing cfg %d: pause", _cfgList.count()-1);
|
||||||
|
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(updateLeds()));
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(updateLeds()));
|
||||||
Info( _log, "Created linear-smoothing with interval: %d ms, settlingTime: %d ms, updateDelay: %d frames",
|
|
||||||
_updateInterval, settlingTime_ms, _outputDelay );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinearColorSmoothing::~LinearColorSmoothing()
|
LinearColorSmoothing::~LinearColorSmoothing()
|
||||||
@ -160,3 +167,44 @@ void LinearColorSmoothing::setPause(bool pause)
|
|||||||
_pause = pause;
|
_pause = pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
||||||
|
{
|
||||||
|
SMOOTHING_CFG cfg = {false, settlingTime_ms, int64_t(1000.0/ledUpdateFrequency_hz), updateDelay};
|
||||||
|
_cfgList.append(cfg);
|
||||||
|
|
||||||
|
Info( _log, "smoothing cfg %d: interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _cfgList.count()-1, cfg.updateInterval, cfg.settlingTime, cfg.outputDelay );
|
||||||
|
return _cfgList.count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinearColorSmoothing::selectConfig(unsigned cfg)
|
||||||
|
{
|
||||||
|
if (_currentConfigId == cfg)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cfg < (unsigned)_cfgList.count())
|
||||||
|
{
|
||||||
|
_settlingTime = _cfgList[cfg].settlingTime;
|
||||||
|
_outputDelay = _cfgList[cfg].outputDelay;
|
||||||
|
_pause = _cfgList[cfg].pause;
|
||||||
|
|
||||||
|
if (_cfgList[cfg].updateInterval != _updateInterval)
|
||||||
|
{
|
||||||
|
_timer.stop();
|
||||||
|
_updateInterval = _cfgList[cfg].updateInterval;
|
||||||
|
_timer.setInterval(_updateInterval);
|
||||||
|
_timer.start();
|
||||||
|
}
|
||||||
|
_currentConfigId = cfg;
|
||||||
|
InfoIf( enabled() && !_pause, _log, "set smoothing cfg: %d, interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _currentConfigId, _updateInterval, _settlingTime, _outputDelay );
|
||||||
|
InfoIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset to default
|
||||||
|
_currentConfigId = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
// hyperion incluse
|
// hyperion incluse
|
||||||
#include <leddevice/LedDevice.h>
|
#include <leddevice/LedDevice.h>
|
||||||
@ -33,7 +34,7 @@ public:
|
|||||||
/// write updated values as input for the smoothing filter
|
/// write updated values as input for the smoothing filter
|
||||||
///
|
///
|
||||||
/// @param ledValues The color-value per led
|
/// @param ledValues The color-value per led
|
||||||
/// @return Zero on succes else negative
|
/// @return Zero on success else negative
|
||||||
///
|
///
|
||||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||||
|
|
||||||
@ -45,6 +46,9 @@ public:
|
|||||||
bool pause() { return _pause; } ;
|
bool pause() { return _pause; } ;
|
||||||
bool enabled() { return LedDevice::enabled() && !_pause; };
|
bool enabled() { return LedDevice::enabled() && !_pause; };
|
||||||
|
|
||||||
|
unsigned addConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
|
||||||
|
bool selectConfig(unsigned cfg);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
/// Timer callback which writes updated led values to the led device
|
/// Timer callback which writes updated led values to the led device
|
||||||
void updateLeds();
|
void updateLeds();
|
||||||
@ -61,10 +65,10 @@ private:
|
|||||||
LedDevice * _ledDevice;
|
LedDevice * _ledDevice;
|
||||||
|
|
||||||
/// The interval at which to update the leds (msec)
|
/// The interval at which to update the leds (msec)
|
||||||
const int64_t _updateInterval;
|
int64_t _updateInterval;
|
||||||
|
|
||||||
/// The time after which the updated led values have been fully applied (msec)
|
/// The time after which the updated led values have been fully applied (msec)
|
||||||
const int64_t _settlingTime;
|
int64_t _settlingTime;
|
||||||
|
|
||||||
/// The Qt timer object
|
/// The Qt timer object
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
@ -82,7 +86,7 @@ private:
|
|||||||
std::vector<ColorRgb> _previousValues;
|
std::vector<ColorRgb> _previousValues;
|
||||||
|
|
||||||
/// The number of updates to keep in the output queue (delayed) before being output
|
/// The number of updates to keep in the output queue (delayed) before being output
|
||||||
const unsigned _outputDelay;
|
unsigned _outputDelay;
|
||||||
/// The output queue
|
/// The output queue
|
||||||
std::list<std::vector<ColorRgb> > _outputQueue;
|
std::list<std::vector<ColorRgb> > _outputQueue;
|
||||||
|
|
||||||
@ -94,4 +98,17 @@ private:
|
|||||||
|
|
||||||
/// Flag for pausing
|
/// Flag for pausing
|
||||||
bool _pause;
|
bool _pause;
|
||||||
|
|
||||||
|
struct SMOOTHING_CFG
|
||||||
|
{
|
||||||
|
bool pause;
|
||||||
|
int64_t settlingTime;
|
||||||
|
int64_t updateInterval;
|
||||||
|
unsigned outputDelay;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// config list
|
||||||
|
QVector<SMOOTHING_CFG> _cfgList;
|
||||||
|
|
||||||
|
unsigned _currentConfigId;
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
|
|
||||||
// STL includes
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
// Hyperion includes
|
// Hyperion includes
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
#include "MultiColorAdjustment.h"
|
#include "MultiColorAdjustment.h"
|
||||||
@ -29,8 +25,8 @@ void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment)
|
|||||||
|
|
||||||
void MultiColorAdjustment::setAdjustmentForLed(const QString& id, const unsigned startLed, const unsigned endLed)
|
void MultiColorAdjustment::setAdjustmentForLed(const QString& id, const unsigned startLed, const unsigned endLed)
|
||||||
{
|
{
|
||||||
assert(startLed <= endLed);
|
Q_ASSERT(startLed <= endLed);
|
||||||
assert(endLed < _ledAdjustments.size());
|
Q_ASSERT(endLed < _ledAdjustments.size());
|
||||||
|
|
||||||
// Get the identified adjustment (don't care if is nullptr)
|
// Get the identified adjustment (don't care if is nullptr)
|
||||||
ColorAdjustment * adjustment = getAdjustment(id);
|
ColorAdjustment * adjustment = getAdjustment(id);
|
||||||
@ -83,10 +79,9 @@ void MultiColorAdjustment::setBacklightEnabled(bool enable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MultiColorAdjustment::applyAdjustment(std::vector<ColorRgb>& ledColors)
|
void MultiColorAdjustment::applyAdjustment(std::vector<ColorRgb>& ledColors)
|
||||||
{
|
{
|
||||||
const size_t itCnt = std::min(_ledAdjustments.size(), ledColors.size());
|
const size_t itCnt = qMin(_ledAdjustments.size(), ledColors.size());
|
||||||
for (size_t i=0; i<itCnt; ++i)
|
for (size_t i=0; i<itCnt; ++i)
|
||||||
{
|
{
|
||||||
ColorAdjustment* adjustment = _ledAdjustments[i];
|
ColorAdjustment* adjustment = _ledAdjustments[i];
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include <iostream>
|
|
||||||
// STL includes
|
// STL includes
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -27,7 +26,6 @@ PriorityMuxer::PriorityMuxer(int ledCount)
|
|||||||
|
|
||||||
PriorityMuxer::~PriorityMuxer()
|
PriorityMuxer::~PriorityMuxer()
|
||||||
{
|
{
|
||||||
// empty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PriorityMuxer::getCurrentPriority() const
|
int PriorityMuxer::getCurrentPriority() const
|
||||||
@ -55,7 +53,7 @@ const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority)
|
|||||||
return elemIt.value();
|
return elemIt.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms, hyperion::Components component, const QString origin)
|
void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms, hyperion::Components component, const QString origin, unsigned smooth_cfg)
|
||||||
{
|
{
|
||||||
InputInfo& input = _activeInputs[priority];
|
InputInfo& input = _activeInputs[priority];
|
||||||
input.priority = priority;
|
input.priority = priority;
|
||||||
@ -63,7 +61,8 @@ void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& le
|
|||||||
input.ledColors = ledColors;
|
input.ledColors = ledColors;
|
||||||
input.componentId = component;
|
input.componentId = component;
|
||||||
input.origin = origin;
|
input.origin = origin;
|
||||||
_currentPriority = std::min(_currentPriority, priority);
|
input.smooth_cfg = smooth_cfg;
|
||||||
|
_currentPriority = qMin(_currentPriority, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PriorityMuxer::clearInput(const int priority)
|
void PriorityMuxer::clearInput(const int priority)
|
||||||
@ -102,7 +101,7 @@ void PriorityMuxer::setCurrentTime(const int64_t& now)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_currentPriority = std::min(_currentPriority, infoIt->priority);
|
_currentPriority = qMin(_currentPriority, infoIt->priority);
|
||||||
|
|
||||||
// call emitReq when effect or color is running with timeout > -1, blacklist prio 255
|
// call emitReq when effect or color is running with timeout > -1, blacklist prio 255
|
||||||
if(infoIt->priority < 254 && infoIt->timeoutTime_ms > -1 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR))
|
if(infoIt->priority < 254 && infoIt->timeoutTime_ms > -1 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR))
|
||||||
|
@ -16,7 +16,7 @@ bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
|
|||||||
ProviderSpi::init(deviceConfig);
|
ProviderSpi::init(deviceConfig);
|
||||||
|
|
||||||
const unsigned int startFrameSize = 4;
|
const unsigned int startFrameSize = 4;
|
||||||
const unsigned int endFrameSize = std::max<unsigned int>(((_ledCount + 15) / 16), 4);
|
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), 4);
|
||||||
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
|
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
|
||||||
|
|
||||||
_ledBuffer.resize(APAbufferSize, 0xFF);
|
_ledBuffer.resize(APAbufferSize, 0xFF);
|
||||||
|
@ -26,7 +26,7 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
|
|||||||
{
|
{
|
||||||
const unsigned int startFrameSize = 4;
|
const unsigned int startFrameSize = 4;
|
||||||
const unsigned int bytesPerRGBLed = 4;
|
const unsigned int bytesPerRGBLed = 4;
|
||||||
const unsigned int endFrameSize = std::max<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed);
|
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed);
|
||||||
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
|
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
|
||||||
|
|
||||||
// init constant data values
|
// init constant data values
|
||||||
|
@ -38,7 +38,7 @@ bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
|
|||||||
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
|
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
|
||||||
_rs232Port.setStopBits(QSerialPort::TwoStop);
|
_rs232Port.setStopBits(QSerialPort::TwoStop);
|
||||||
|
|
||||||
_dmxLedCount = std::min(_ledCount, 512/_dmxSlotsPerLed);
|
_dmxLedCount = qMin(_ledCount, 512/_dmxSlotsPerLed);
|
||||||
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
|
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
|
||||||
|
|
||||||
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);
|
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);
|
||||||
|
@ -209,7 +209,7 @@ int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
|
|||||||
|
|
||||||
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
||||||
{
|
{
|
||||||
int count = std::min(_hwLedCount,size);
|
int count = qMin(_hwLedCount,size);
|
||||||
for (int i=0; i<count; i++)
|
for (int i=0; i<count; i++)
|
||||||
{
|
{
|
||||||
const ColorRgb & color = ledValues[i];
|
const ColorRgb & color = ledValues[i];
|
||||||
|
@ -252,7 +252,7 @@ int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
|
|||||||
|
|
||||||
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
||||||
{
|
{
|
||||||
int count = std::min(_hwLedCount, _ledCount);
|
int count = qMin(_hwLedCount, _ledCount);
|
||||||
|
|
||||||
for (int i = 0; i < count ; ++i)
|
for (int i = 0; i < count ; ++i)
|
||||||
{
|
{
|
||||||
|
@ -81,7 +81,7 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
|
|||||||
|
|
||||||
for (LedDeviceLightpack * device : _lightpacks)
|
for (LedDeviceLightpack * device : _lightpacks)
|
||||||
{
|
{
|
||||||
int count = std::min(device->getLedCount(), size);
|
int count = qMin(device->getLedCount(), size);
|
||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,7 @@ The Sequence field is set to 0x00 to disable this feature.
|
|||||||
if ( (ledIdx == _ledRGBCount-1) || (dmxIdx >= DMX_MAX) )
|
if ( (ledIdx == _ledRGBCount-1) || (dmxIdx >= DMX_MAX) )
|
||||||
{
|
{
|
||||||
prepare(thisUniverse, _artnet_seq, dmxIdx);
|
prepare(thisUniverse, _artnet_seq, dmxIdx);
|
||||||
retVal &= writeBytes(18 + std::min(dmxIdx, DMX_MAX), artnet_packet.raw);
|
retVal &= writeBytes(18 + qMin(dmxIdx, DMX_MAX), artnet_packet.raw);
|
||||||
|
|
||||||
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
|
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
|
||||||
thisUniverse ++;
|
thisUniverse ++;
|
||||||
|
@ -34,24 +34,44 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"title":"edt_dev_spec_FCmanualControl_title",
|
"title":"edt_dev_spec_FCmanualControl_title",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"setFcConfig": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"propertyOrder" : 5
|
"propertyOrder" : 5
|
||||||
},
|
},
|
||||||
"ledOn": {
|
"ledOn": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"title":"edt_dev_spec_FCledToOn_title",
|
"title":"edt_dev_spec_FCledToOn_title",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"setFcConfig": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"propertyOrder" : 6
|
"propertyOrder" : 6
|
||||||
},
|
},
|
||||||
"interpolation": {
|
"interpolation": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"title":"edt_dev_spec_interpolation_title",
|
"title":"edt_dev_spec_interpolation_title",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"setFcConfig": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"propertyOrder" : 7
|
"propertyOrder" : 7
|
||||||
},
|
},
|
||||||
"dither": {
|
"dither": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"title":"edt_dev_spec_dithering_title",
|
"title":"edt_dev_spec_dithering_title",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"setFcConfig": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"propertyOrder" : 8
|
"propertyOrder" : 8
|
||||||
},
|
},
|
||||||
"gamma" : {
|
"gamma" : {
|
||||||
@ -59,11 +79,21 @@
|
|||||||
"title" : "edt_dev_spec_gamma_title",
|
"title" : "edt_dev_spec_gamma_title",
|
||||||
"minimum" : 0.1,
|
"minimum" : 0.1,
|
||||||
"maximum": 5.0,
|
"maximum": 5.0,
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"setFcConfig": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"propertyOrder" : 9
|
"propertyOrder" : 9
|
||||||
},
|
},
|
||||||
"whitepoint" : {
|
"whitepoint" : {
|
||||||
"type" : "array",
|
"type" : "array",
|
||||||
"title" : "edt_dev_spec_whitepoint_title",
|
"title" : "edt_dev_spec_whitepoint_title",
|
||||||
|
"options": {
|
||||||
|
"dependencies": {
|
||||||
|
"setFcConfig": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"propertyOrder" : 10,
|
"propertyOrder" : 10,
|
||||||
"default" : [255,255,255],
|
"default" : [255,255,255],
|
||||||
"maxItems" : 3,
|
"maxItems" : 3,
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
// system includes
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
// project includes
|
// project includes
|
||||||
#include <udplistener/UDPListener.h>
|
#include <udplistener/UDPListener.h>
|
||||||
|
|
||||||
@ -123,7 +120,7 @@ void UDPListener::processTheDatagram(const QByteArray * datagram, const QHostAdd
|
|||||||
|
|
||||||
std::vector<ColorRgb> _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK);
|
std::vector<ColorRgb> _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK);
|
||||||
|
|
||||||
for (int ledIndex=0; ledIndex < std::min(packetLedCount, hyperionLedCount); ledIndex++) {
|
for (int ledIndex=0; ledIndex < qMin(packetLedCount, hyperionLedCount); ledIndex++) {
|
||||||
ColorRgb & rgb = _ledColors[ledIndex];
|
ColorRgb & rgb = _ledColors[ledIndex];
|
||||||
rgb.red = datagram->at(ledIndex*3+0);
|
rgb.red = datagram->at(ledIndex*3+0);
|
||||||
rgb.green = datagram->at(ledIndex*3+1);
|
rgb.green = datagram->at(ledIndex*3+1);
|
||||||
|
@ -1,9 +1,3 @@
|
|||||||
// STL includes
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
// Utils includes
|
|
||||||
#include <utils/RgbChannelAdjustment.h>
|
#include <utils/RgbChannelAdjustment.h>
|
||||||
|
|
||||||
RgbChannelAdjustment::RgbChannelAdjustment(QString channelName)
|
RgbChannelAdjustment::RgbChannelAdjustment(QString channelName)
|
||||||
@ -64,9 +58,9 @@ void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t & re
|
|||||||
|
|
||||||
if (!_initialized[input])
|
if (!_initialized[input])
|
||||||
{
|
{
|
||||||
_mapping[RED ][input] = std::min( ((_brightness * input * _adjust[RED ]) / 65025), UINT8_MAX);
|
_mapping[RED ][input] = qMin( ((_brightness * input * _adjust[RED ]) / 65025), UINT8_MAX);
|
||||||
_mapping[GREEN][input] = std::min( ((_brightness * input * _adjust[GREEN]) / 65025), UINT8_MAX);
|
_mapping[GREEN][input] = qMin( ((_brightness * input * _adjust[GREEN]) / 65025), UINT8_MAX);
|
||||||
_mapping[BLUE ][input] = std::min( ((_brightness * input * _adjust[BLUE ]) / 65025), UINT8_MAX);
|
_mapping[BLUE ][input] = qMin( ((_brightness * input * _adjust[BLUE ]) / 65025), UINT8_MAX);
|
||||||
_initialized[input] = true;
|
_initialized[input] = true;
|
||||||
}
|
}
|
||||||
red = _mapping[RED ][input];
|
red = _mapping[RED ][input];
|
||||||
|
@ -19,7 +19,7 @@ void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, const WhiteAlgorithm algori
|
|||||||
{
|
{
|
||||||
case SUBTRACT_MINIMUM:
|
case SUBTRACT_MINIMUM:
|
||||||
{
|
{
|
||||||
output->white = std::min(std::min(input.red, input.green), input.blue);
|
output->white = qMin(qMin(input.red, input.green), input.blue);
|
||||||
output->red = input.red - output->white;
|
output->red = input.red - output->white;
|
||||||
output->green = input.green - output->white;
|
output->green = input.green - output->white;
|
||||||
output->blue = input.blue - output->white;
|
output->blue = input.blue - output->white;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
#include <iostream>
|
#include <QtCore/qmath.h>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include <utils/RgbTransform.h>
|
#include <utils/RgbTransform.h>
|
||||||
|
|
||||||
RgbTransform::RgbTransform()
|
RgbTransform::RgbTransform()
|
||||||
@ -55,9 +53,9 @@ void RgbTransform::initializeMapping()
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
_mappingR[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaR) * 255), 0), 255);
|
_mappingR[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaR) * 255), 0), 255);
|
||||||
_mappingG[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaG) * 255), 0), 255);
|
_mappingG[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaG) * 255), 0), 255);
|
||||||
_mappingB[i] = std::min(std::max((int)(std::pow(i / 255.0, _gammaB) * 255), 0), 255);
|
_mappingB[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaB) * 255), 0), 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +68,7 @@ int RgbTransform::getBacklightThreshold() const
|
|||||||
void RgbTransform::setBacklightThreshold(int backlightThreshold)
|
void RgbTransform::setBacklightThreshold(int backlightThreshold)
|
||||||
{
|
{
|
||||||
_backlightThreshold = backlightThreshold;
|
_backlightThreshold = backlightThreshold;
|
||||||
_sumBrightnessLow = 765.0 * ((std::pow(2.0,(_backlightThreshold/100)*2)-1) / 3.0);
|
_sumBrightnessLow = 765.0 * ((qPow(2.0,(_backlightThreshold/100)*2)-1) / 3.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RgbTransform::getBacklightColored() const
|
bool RgbTransform::getBacklightColored() const
|
||||||
@ -129,9 +127,9 @@ void RgbTransform::updateBrightnessComponents()
|
|||||||
{
|
{
|
||||||
B_in = (_brightness<50)? -0.09*_brightness+7.5 : -0.04*_brightness+5.0;
|
B_in = (_brightness<50)? -0.09*_brightness+7.5 : -0.04*_brightness+5.0;
|
||||||
|
|
||||||
_brightness_rgb = std::ceil(std::min(255.0,255.0/B_in));
|
_brightness_rgb = std::ceil(qMin(255.0,255.0/B_in));
|
||||||
_brightness_cmy = std::ceil(std::min(255.0,255.0/(B_in*Fcmy)));
|
_brightness_cmy = std::ceil(qMin(255.0,255.0/(B_in*Fcmy)));
|
||||||
_brightness_w = std::ceil(std::min(255.0,255.0/(B_in*Fw)));
|
_brightness_w = std::ceil(qMin(255.0,255.0/(B_in*Fw)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +147,6 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
|
|||||||
green = _mappingR[green];
|
green = _mappingR[green];
|
||||||
blue = _mappingR[blue];
|
blue = _mappingR[blue];
|
||||||
|
|
||||||
//std::cout << (int)red << " " << (int)green << " " << (int)blue << " => ";
|
|
||||||
// apply brightnesss
|
// apply brightnesss
|
||||||
int rgbSum = red+green+blue;
|
int rgbSum = red+green+blue;
|
||||||
|
|
||||||
@ -164,7 +161,7 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
|
|||||||
if (blue ==0) blue = 1;
|
if (blue ==0) blue = 1;
|
||||||
rgbSum = red+green+blue;
|
rgbSum = red+green+blue;
|
||||||
}
|
}
|
||||||
double cL =std::min((int)(_sumBrightnessLow /rgbSum), 255);
|
double cL =qMin((int)(_sumBrightnessLow /rgbSum), 255);
|
||||||
|
|
||||||
red *= cL;
|
red *= cL;
|
||||||
green *= cL;
|
green *= cL;
|
||||||
@ -172,11 +169,10 @@ void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
red = std::min((int)(_sumBrightnessLow/3.0), 255);
|
red = qMin((int)(_sumBrightnessLow/3.0), 255);
|
||||||
green = red;
|
green = red;
|
||||||
blue = red;
|
blue = red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//std::cout << _sumBrightnessLow << " " << (int)red << " " << (int)green << " " << (int)blue << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ SysTray::SysTray(HyperionDaemon *hyperiond, quint16 webPort)
|
|||||||
_trayIcon->setIcon(icon);
|
_trayIcon->setIcon(icon);
|
||||||
_trayIcon->show();
|
_trayIcon->show();
|
||||||
setWindowIcon(icon);
|
setWindowIcon(icon);
|
||||||
_colorDlg.setModal(true);
|
|
||||||
_colorDlg.setOptions(QColorDialog::NoButtons);
|
_colorDlg.setOptions(QColorDialog::NoButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,21 +57,31 @@ void SysTray::iconActivated(QSystemTrayIcon::ActivationReason reason)
|
|||||||
void SysTray::createTrayIcon()
|
void SysTray::createTrayIcon()
|
||||||
{
|
{
|
||||||
quitAction = new QAction(tr("&Quit"), this);
|
quitAction = new QAction(tr("&Quit"), this);
|
||||||
|
QIcon quitIcon = QIcon::fromTheme("application-exit");
|
||||||
|
quitAction->setIcon(quitIcon);
|
||||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||||
|
|
||||||
colorAction = new QAction(tr("&Color"), this);
|
colorAction = new QAction(tr("&Color"), this);
|
||||||
|
QIcon colorIcon = QIcon::fromTheme("applications-graphics");
|
||||||
|
colorAction->setIcon(colorIcon);
|
||||||
connect(colorAction, SIGNAL(triggered()), this, SLOT(showColorDialog()));
|
connect(colorAction, SIGNAL(triggered()), this, SLOT(showColorDialog()));
|
||||||
|
|
||||||
settingsAction = new QAction(tr("&Settings"), this);
|
settingsAction = new QAction(tr("&Settings"), this);
|
||||||
|
QIcon settingsIcon = QIcon::fromTheme("preferences-system");
|
||||||
|
settingsAction->setIcon(settingsIcon);
|
||||||
connect(settingsAction, SIGNAL(triggered()), this, SLOT(settings()));
|
connect(settingsAction, SIGNAL(triggered()), this, SLOT(settings()));
|
||||||
|
|
||||||
clearAction = new QAction(tr("&Clear"), this);
|
clearAction = new QAction(tr("&Clear"), this);
|
||||||
|
QIcon clearIcon = QIcon::fromTheme("edit-delete");
|
||||||
|
clearAction->setIcon(clearIcon);
|
||||||
connect(clearAction, SIGNAL(triggered()), this, SLOT(clearEfxColor()));
|
connect(clearAction, SIGNAL(triggered()), this, SLOT(clearEfxColor()));
|
||||||
|
|
||||||
const std::list<EffectDefinition> efxs = _hyperion->getEffects();
|
const std::list<EffectDefinition> efxs = _hyperion->getEffects();
|
||||||
_trayIconMenu = new QMenu(this);
|
_trayIconMenu = new QMenu(this);
|
||||||
_trayIconEfxMenu = new QMenu(_trayIconMenu);
|
_trayIconEfxMenu = new QMenu(_trayIconMenu);
|
||||||
_trayIconEfxMenu->setTitle(tr("Effects"));
|
_trayIconEfxMenu->setTitle(tr("Effects"));
|
||||||
|
QIcon efxIcon = QIcon::fromTheme("media-playback-start");
|
||||||
|
_trayIconEfxMenu->setIcon(efxIcon);
|
||||||
for (auto efx : efxs)
|
for (auto efx : efxs)
|
||||||
{
|
{
|
||||||
QAction *efxAction = new QAction(efx.name, this);
|
QAction *efxAction = new QAction(efx.name, this);
|
||||||
|
Loading…
Reference in New Issue
Block a user