From 30b1a1b25f381486686b891b3ac305a2b36dd4c6 Mon Sep 17 00:00:00 2001 From: LordGrey Date: Thu, 22 Dec 2022 20:10:44 +0100 Subject: [PATCH] Add Temperature adjustment --- assets/webconfig/i18n/en.json | 9 +- assets/webconfig/js/content_remote.js | 7 +- assets/webconfig/js/wizard.js | 7 +- cmake/packages.cmake | 2 +- config/hyperion.config.json.default | 3 +- include/hyperion/ColorAdjustment.h | 2 +- include/hyperion/ColorCorrection.h | 18 +++ include/hyperion/Hyperion.h | 20 +++ include/hyperion/MultiColorCorrection.h | 69 ++++++++++ include/utils/KelvinToRgb.h | 72 +++++++++++ include/utils/RgbChannelCorrection.h | 66 ++++++++++ include/utils/hyperion.h | 101 +++++++++++++++ .../api/JSONRPC_schema/schema-adjustment.json | 7 + libsrc/api/JsonAPI.cpp | 14 ++ libsrc/hyperion/Hyperion.cpp | 40 ++++++ libsrc/hyperion/MultiColorCorrection.cpp | 103 +++++++++++++++ libsrc/hyperion/schema/schema-color.json | 18 ++- libsrc/utils/RgbChannelCorrection.cpp | 120 ++++++++++++++++++ 18 files changed, 666 insertions(+), 12 deletions(-) create mode 100644 include/hyperion/ColorCorrection.h create mode 100644 include/hyperion/MultiColorCorrection.h create mode 100644 include/utils/KelvinToRgb.h create mode 100644 include/utils/RgbChannelCorrection.h create mode 100644 libsrc/hyperion/MultiColorCorrection.cpp create mode 100644 libsrc/utils/RgbChannelCorrection.cpp diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index bb3453b8..455979b4 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -227,6 +227,7 @@ "edt_append_degree": "°", "edt_append_frames": "frames", "edt_append_hz": "Hz", + "edt_append_kelvin": "K", "edt_append_leds": "LEDs", "edt_append_ms": "ms", "edt_append_ns": "ns", @@ -261,6 +262,8 @@ "edt_conf_color_blue_title": "Blue", "edt_conf_color_brightnessComp_expl": "Compensates brightness differences between red green blue, cyan magenta yellow and white. 100 means full compensation, 0 no compensation", "edt_conf_color_brightnessComp_title": "Brightness compensation", + "edt_conf_color_brightnessGain_expl": "Adjusts the brightness of colors. 1.0 means no change, over 1.0 increases brightness, under 1.0 decreases brightness.", + "edt_conf_color_brightnessGain_title": "Brightness gain", "edt_conf_color_brightness_expl": "set overall brightness of LEDs", "edt_conf_color_brightness_title": "Brightness", "edt_conf_color_channelAdjustment_header_expl": "Create color profiles that could be assigned to a specific component. Adjust color, gamma, brightness, compensation and more.", @@ -287,10 +290,10 @@ "edt_conf_color_magenta_title": "Magenta", "edt_conf_color_red_expl": "The calibrated red value.", "edt_conf_color_red_title": "Red", + "edt_conf_color_temperature_expl": "Adjusts the corlor temperature.", + "edt_conf_color_temperature_title": "Temperature", "edt_conf_color_saturationGain_expl": "Adjusts the saturation of colors. 1.0 means no change, over 1.0 increases saturation, under 1.0 desaturates.", "edt_conf_color_saturationGain_title": "Saturation gain", - "edt_conf_color_brightnessGain_expl": "Adjusts the brightness of colors. 1.0 means no change, over 1.0 increases brightness, under 1.0 decreases brightness.", - "edt_conf_color_brightnessGain_title": "Brightness gain", "edt_conf_color_white_expl": "The calibrated white value.", "edt_conf_color_white_title": "White", "edt_conf_color_yellow_expl": "The calibrated yellow value.", @@ -446,6 +449,8 @@ "edt_conf_smooth_heading_title": "Smoothing", "edt_conf_smooth_interpolationRate_expl": "Speed of the calculation of smooth intermediate frames.", "edt_conf_smooth_interpolationRate_title": "Interpolation Rate", + "edt_conf_smooth_outputRate_expl": "The output speed to your LED controller.", + "edt_conf_smooth_outputRate_title": "Output Rate", "edt_conf_smooth_time_ms_expl": "How long should the smoothing gather pictures?", "edt_conf_smooth_time_ms_title": "Time", "edt_conf_smooth_type_expl": "Type of smoothing.", diff --git a/assets/webconfig/js/content_remote.js b/assets/webconfig/js/content_remote.js index d0c1d9c2..a999b5fc 100644 --- a/assets/webconfig/js/content_remote.js +++ b/assets/webconfig/js/content_remote.js @@ -75,11 +75,12 @@ $(document).ready(function () { sColor[key].key == "brightnessCompensation" || sColor[key].key == "backlightThreshold" || sColor[key].key == "saturationGain" || - sColor[key].key == "brightnessGain") { + sColor[key].key == "brightnessGain" || + sColor[key].key == "temperature" ) { property = ''; - if (sColor[key].append === "edt_append_percent") { - property = '
' + property + '' + $.i18n("edt_append_percent") + '
'; + if (sColor[key].append && sColor[key].append !== "" ) { + property = '
' + property + '' + $.i18n(sColor[key].append) + '
'; } } else { diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js index dedd50ed..e977e402 100755 --- a/assets/webconfig/js/wizard.js +++ b/assets/webconfig/js/wizard.js @@ -854,7 +854,12 @@ function checkUserResult(reply, usr) { function useGroupId(id) { $('#groupId').val(id); - groupLights = hueGroups[id].lights; + + //Ensure ligthIDs are strings + groupLights = hueGroups[id].lights.map(num => { + return String(num); + }); + groupLightsLocations = hueGroups[id].locations; get_hue_lights(); } diff --git a/cmake/packages.cmake b/cmake/packages.cmake index bc73057d..1dd8f6a6 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -72,7 +72,7 @@ endif() # .deb files for apt # https://cmake.org/cmake/help/latest/cpack_gen/deb.html SET ( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/package-scripts/preinst;${CMAKE_SOURCE_DIR}/cmake/package-scripts/postinst;${CMAKE_SOURCE_DIR}/cmake/package-scripts/prerm" ) -SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libcec6 | libcec4" ) +SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libcec6 | libcec4 | libcec (>= 4.0)" ) SET ( CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" ) # .rpm for rpm diff --git a/config/hyperion.config.json.default b/config/hyperion.config.json.default index a52f64ba..14333eb9 100644 --- a/config/hyperion.config.json.default +++ b/config/hyperion.config.json.default @@ -48,7 +48,8 @@ "brightness" : 100, "brightnessCompensation" : 100, "saturationGain" : 1.0, - "brightnessGain" : 1.0 + "brightnessGain" : 1.0, + "temperature" : 6600 } ] }, diff --git a/include/hyperion/ColorAdjustment.h b/include/hyperion/ColorAdjustment.h index 3e9b8dc8..99dd9315 100644 --- a/include/hyperion/ColorAdjustment.h +++ b/include/hyperion/ColorAdjustment.h @@ -1,7 +1,7 @@ #ifndef COLORADJUSTMENT_H #define COLORADJUSTMENT_H -// STL includes +// Qt includes #include // Utils includes diff --git a/include/hyperion/ColorCorrection.h b/include/hyperion/ColorCorrection.h new file mode 100644 index 00000000..478cd35d --- /dev/null +++ b/include/hyperion/ColorCorrection.h @@ -0,0 +1,18 @@ +#pragma once + +// Qt includes +#include + +// Utils includes +#include + +class ColorCorrection +{ +public: + + /// Unique identifier for this color correction + QString _id; + + /// The RGB correction + RgbChannelCorrection _rgbCorrection; +}; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 34351502..ca812f90 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #if defined(ENABLE_EFFECTENGINE) @@ -48,6 +49,7 @@ class LinearColorSmoothing; class EffectEngine; #endif class MultiColorAdjustment; +class MultiColorCorrection; class ColorAdjustment; class SettingsManager; class BGEffectHandler; @@ -181,15 +183,30 @@ public slots: /// QStringList getAdjustmentIds() const; + /// + /// Returns the list with unique correction identifiers + /// @return The list with correction identifiers + /// + QStringList getTemperatureIds() const; + /// /// Returns the ColorAdjustment with the given identifier /// @return The adjustment with the given identifier (or nullptr if the identifier does not exist) /// ColorAdjustment * getAdjustment(const QString& id) const; + /// + /// Returns the ColorCorrection with the given identifier + /// @return The correction with the given identifier (or nullptr if the identifier does not exist) + /// + ColorCorrection * getTemperature(const QString& id) const; + /// Tell Hyperion that the corrections have changed and the leds need to be updated void adjustmentsUpdated(); + /// Tell Hyperion that the corrections have changed and the leds need to be updated + void temperaturesUpdated(); + /// /// Clears the given priority channel. This will switch the led-colors to the colors of the next /// lower priority channel (or off if no more channels are set) @@ -566,6 +583,9 @@ private: /// The adjustment from raw colors to led colors MultiColorAdjustment * _raw2ledAdjustment; + /// The temperature from raw colors to led colors + MultiColorCorrection * _raw2ledTemperature; + /// The actual LedDeviceWrapper LedDeviceWrapper* _ledDeviceWrapper; diff --git a/include/hyperion/MultiColorCorrection.h b/include/hyperion/MultiColorCorrection.h new file mode 100644 index 00000000..36422871 --- /dev/null +++ b/include/hyperion/MultiColorCorrection.h @@ -0,0 +1,69 @@ +#pragma once + +// STL includes + +#include + +// Utils includes +#include +#include "utils/Logger.h" + +// Hyperion includes +#include + +/// +/// The LedColorCorrection is responsible for performing color correction from 'raw' colors +/// received as input to colors mapped to match the color-properties of the leds. +/// +class MultiColorCorrection +{ +public: + MultiColorCorrection(int ledCnt); + ~MultiColorCorrection(); + + /** + * Adds a new ColorCorrection to this MultiColorCorrection + * + * @param Correction The new ColorCorrection (ownership is transfered) + */ + void addCorrection(ColorCorrection * correction); + + void setCorrectionForLed(const QString& id, int startLed, int endLed); + + bool verifyCorrections() const; + + /// + /// Returns the identifier of all the unique ColorCorrection + /// + /// @return The list with unique id's of the ColorCorrections + QStringList & getCorrectionIds(); + + /// + /// Returns the pointer to the ColorCorrection with the given id + /// + /// @param id The identifier of the ColorCorrection + /// + /// @return The ColorCorrection with the given id (or nullptr if it does not exist) + /// + ColorCorrection* getCorrection(const QString& id); + + /// + /// Performs the color transoformation from raw-color to led-color + /// + /// @param ledColors The list with raw colors + /// + void applyCorrection(std::vector& ledColors); + +private: + /// List with Correction ids + QStringList _correctionIds; + + /// List with unique ColorCorrections + std::vector _correction; + + /// List with a pointer to the ColorCorrection for each individual led + std::vector _ledCorrections; + + // logger instance + Logger * _log; +}; diff --git a/include/utils/KelvinToRgb.h b/include/utils/KelvinToRgb.h new file mode 100644 index 00000000..e044375a --- /dev/null +++ b/include/utils/KelvinToRgb.h @@ -0,0 +1,72 @@ +#ifndef KELVINTORGB_H +#define KELVINTORGB_H + +#include + +#include + + +// Constants +namespace { +const int TEMPERATURE_MINIMUM = 1000; +const int TEMPERATUR_MAXIMUM = 40000; +} //End of constants + +static ColorRgb getRgbFromTemperature(int temperature) +{ + //Temperature input in Kelvin valid in the range 1000 K to 40000 K. White light = 6600K + temperature = qBound(TEMPERATURE_MINIMUM, temperature, TEMPERATUR_MAXIMUM); + + // All calculations require temperature / 100, so only do the conversion once. + temperature /= 100; + + // Compute each color in turn. + int red, green, blue; + + // red + if (temperature <= 66) + { + red = 255; + } + else + { + // Note: the R-squared value for this approximation is 0.988. + red = static_cast(329.698727446 * (pow(temperature - 60, -0.1332047592))); + } + + // green + if (temperature <= 66) + { + // Note: the R-squared value for this approximation is 0.996. + green = static_cast(99.4708025861 * log(temperature) - 161.1195681661); + + } + else + { + // Note: the R-squared value for this approximation is 0.987. + green = static_cast(288.1221695283 * (pow(temperature - 60, -0.0755148492))); + } + + // blue + if (temperature >= 66) + { + blue = 255; + } + else if (temperature <= 19) + { + blue = 0; + } + else + { + // Note: the R-squared value for this approximation is 0.998. + blue = static_cast(138.5177312231 * log(temperature - 10) - 305.0447927307); + } + + return { + static_cast(qBound(0, red, 255)), + static_cast(qBound(0, green, 255)), + static_cast(qBound(0, blue, 255)), + }; +} + +#endif // KELVINTORGB_H diff --git a/include/utils/RgbChannelCorrection.h b/include/utils/RgbChannelCorrection.h new file mode 100644 index 00000000..f09b9cef --- /dev/null +++ b/include/utils/RgbChannelCorrection.h @@ -0,0 +1,66 @@ +#pragma once + +// STL includes +#include + +/// Correction for a single color byte value +/// All configuration values are unsigned int and assume the color value to be between 0 and 255 +class RgbChannelCorrection +{ +public: + /// Default constructor + RgbChannelCorrection(); + + /// Constructor + /// @param correctionR + /// @param correctionG + /// @param correctionB + + RgbChannelCorrection(int correctionR, int correctionG, int correctionB); + + /// Destructor + ~RgbChannelCorrection(); + + /// @return The current correctionR value + uint8_t getcorrectionR() const; + + /// @param threshold New correctionR value + void setcorrectionR(uint8_t correctionR); + + /// @return The current correctionG value + uint8_t getcorrectionG() const; + + /// @param gamma New correctionG value + void setcorrectionG(uint8_t correctionG); + + /// @return The current correctionB value + uint8_t getcorrectionB() const; + + /// @param blacklevel New correctionB value + void setcorrectionB(uint8_t correctionB); + + /// Transform the given array value + /// @param input The input color bytes + /// @return The corrected byte value + uint8_t correctionR(uint8_t inputR) const; + uint8_t correctionG(uint8_t inputG) const; + uint8_t correctionB(uint8_t inputB) const; + + +private: + /// (re)-initilize the color mapping + void initializeMapping(); + +private: + /// The correction of R channel + int _correctionR; + /// The correction of G channel + int _correctionG; + /// The correction of B channel + int _correctionB; + + /// The mapping from input color to output color + int _mappingR[256]; + int _mappingG[256]; + int _mappingB[256]; +}; diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index 5349d38d..704c121a 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -4,8 +4,10 @@ #include #include +#include "hyperion/MultiColorCorrection.h" #include #include +#include // fg effect #include @@ -14,6 +16,8 @@ #include #endif +#include + /// /// @brief Provide utility methods for Hyperion class /// @@ -100,6 +104,32 @@ namespace hyperion { ); } + RgbChannelCorrection* createRgbChannelCorrection(const QJsonObject& colorConfig) + { + int varR = colorConfig["red"].toInt(255); + int varG = colorConfig["green"].toInt(255); + int varB = colorConfig["blue"].toInt(255); + + RgbChannelCorrection* correction = new RgbChannelCorrection(varR, varG, varB); + return correction; + } + + ColorCorrection * createColorCorrection(const QJsonObject& correctionConfig) + { + const QString id = correctionConfig["id"].toString("default"); + + RgbChannelCorrection * rgbCorrection = createRgbChannelCorrection(correctionConfig); + + ColorCorrection * correction = new ColorCorrection(); + correction->_id = id; + correction->_rgbCorrection = *rgbCorrection; + + // Cleanup the allocated individual transforms + delete rgbCorrection; + + return correction; + } + ColorAdjustment* createColorAdjustment(const QJsonObject & adjustmentConfig) { const QString id = adjustmentConfig["id"].toString("default"); @@ -179,6 +209,77 @@ namespace hyperion { return adjustment; } + MultiColorCorrection * createLedColorsTemperature(int ledCnt, const QJsonObject & colorConfig) + { + // Create the result, the corrections are added to this + MultiColorCorrection * correction = new MultiColorCorrection(ledCnt); + + const QJsonValue adjustmentConfig = colorConfig["channelAdjustment"]; + const QRegularExpression overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*"); + + const QJsonArray & adjustmentConfigArray = adjustmentConfig.toArray(); + for (signed i = 0; i < adjustmentConfigArray.size(); ++i) + { + const QJsonObject & config = adjustmentConfigArray.at(i).toObject(); + ColorAdjustment * colorAdjustment = createColorAdjustment(config); + + int temperature = config["temperature"].toInt(); + + ColorRgb rgb = getRgbFromTemperature(temperature); + + qDebug() << "createLedColorsTemperature: adjustment[temperture]: " << temperature << "-> " << rgb.toQString(); + + QJsonObject correctionConfig { + {"red", rgb.red}, + {"green", rgb.green}, + {"blue", rgb.blue} + }; + + ColorCorrection * colorCorrection = createColorCorrection(correctionConfig); + correction->addCorrection(colorCorrection); + + const QString ledIndicesStr = config["leds"].toString("").trimmed(); + if (ledIndicesStr.compare("*") == 0) + { + // Special case for indices '*' => all leds + correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); + Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [0-%d]", QSTRING_CSTR(colorCorrection->_id), ledCnt-1); + continue; + } + + if (!overallExp.match(ledIndicesStr).hasMatch()) + { + Error(Logger::getInstance("HYPERION"), "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr)); + continue; + } + + std::stringstream ss; + const QStringList ledIndexList = ledIndicesStr.split(","); + for (int i=0; i 0) + { + ss << ", "; + } + if (ledIndexList[i].contains("-")) + { + QStringList ledIndices = ledIndexList[i].split("-"); + int startInd = ledIndices[0].toInt(); + int endInd = ledIndices[1].toInt(); + correction->setCorrectionForLed(colorCorrection->_id, startInd, endInd); + ss << startInd << "-" << endInd; + } + else + { + int index = ledIndexList[i].toInt(); + correction->setCorrectionForLed(colorCorrection->_id, index, index); + ss << index; + } + } + Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str()); + } + return correction; + } + /** * Construct the 'led-string' with the integration area definition per led and the color * ordering of the RGB channels diff --git a/libsrc/api/JSONRPC_schema/schema-adjustment.json b/libsrc/api/JSONRPC_schema/schema-adjustment.json index b8856ef9..b0663736 100644 --- a/libsrc/api/JSONRPC_schema/schema-adjustment.json +++ b/libsrc/api/JSONRPC_schema/schema-adjustment.json @@ -146,6 +146,13 @@ "required" : false, "minimum" : 0.1, "maximum": 10.0 + }, + "temperature" : + { + "type" : "integer", + "required" : false, + "minimum" : 1000, + "maximum": 40000 } }, "additionalProperties": false diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 60a832b4..f937873c 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -519,6 +520,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain(); adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain(); + adjustment["temperature"] = 6600; + adjustmentArray.append(adjustment); } @@ -936,6 +939,17 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const QString if (adjustment.contains("brightnessGain")) { colorAdjustment->_okhsvTransform.setBrightnessGain(adjustment["brightnessGain"].toDouble()); + } + + if (adjustment.contains("temperature")) + { + int temperature = adjustment["temperature"].toInt(6500); + ColorRgb rgb = getRgbFromTemperature(temperature); + + ColorCorrection *colorCorrection = _hyperion->getTemperature(adjustmentId); + colorCorrection->_rgbCorrection.setcorrectionR(rgb.red); + colorCorrection->_rgbCorrection.setcorrectionG(rgb.green); + colorCorrection->_rgbCorrection.setcorrectionB(rgb.blue); } // commit the changes diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 52216f02..26a26241 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #if defined(ENABLE_EFFECTENGINE) @@ -56,6 +57,7 @@ Hyperion::Hyperion(quint8 instance, bool readonlyMode) , _imageProcessor(nullptr) , _muxer(nullptr) , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object())) + , _raw2ledTemperature(hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object())) , _ledDeviceWrapper(nullptr) , _deviceSmooth(nullptr) #if defined(ENABLE_EFFECTENGINE) @@ -100,6 +102,11 @@ void Hyperion::start() // get newVideoMode from HyperionIManager connect(this, &Hyperion::newVideoMode, this, &Hyperion::handleNewVideoMode); + if (!_raw2ledTemperature->verifyCorrections()) + { + Warning(_log, "Color temperature incorrectly set"); + } + if (!_raw2ledAdjustment->verifyAdjustments()) { Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); @@ -219,6 +226,9 @@ void Hyperion::freeObjects() delete _raw2ledAdjustment; + // delete the color temperature correction + delete _raw2ledTemperature; + #if defined(ENABLE_FORWARDER) delete _messageForwarder; #endif @@ -247,6 +257,15 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co { Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); } + + // change in color recreate ledTemperature + delete _raw2ledTemperature; + _raw2ledTemperature = hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), obj); + + if (!_raw2ledTemperature->verifyCorrections()) + { + Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); + } } else if(type == settings::LEDS) { @@ -279,6 +298,10 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co delete _raw2ledAdjustment; _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object()); + // change in leds recreate ledTemperature + delete _raw2ledTemperature; + _raw2ledTemperature = hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object()); + #if defined(ENABLE_EFFECTENGINE) // start cached effects _effectEngine->startCachedEffects(); @@ -494,17 +517,33 @@ QStringList Hyperion::getAdjustmentIds() const return _raw2ledAdjustment->getAdjustmentIds(); } +QStringList Hyperion::getTemperatureIds() const +{ + return _raw2ledTemperature->getCorrectionIds(); +} + ColorAdjustment * Hyperion::getAdjustment(const QString& id) const { return _raw2ledAdjustment->getAdjustment(id); } +ColorCorrection * Hyperion::getTemperature(const QString& id) const +{ + return _raw2ledTemperature->getCorrection(id); +} + void Hyperion::adjustmentsUpdated() { emit adjustmentChanged(); update(); } +void Hyperion::temperaturesUpdated() +{ + emit adjustmentChanged(); + update(); +} + bool Hyperion::clear(int priority, bool forceClearAll) { bool isCleared = false; @@ -680,6 +719,7 @@ void Hyperion::update() emit rawLedColors(_ledBuffer); _raw2ledAdjustment->applyAdjustment(_ledBuffer); + _raw2ledTemperature->applyCorrection(_ledBuffer); int i = 0; for (ColorRgb& color : _ledBuffer) diff --git a/libsrc/hyperion/MultiColorCorrection.cpp b/libsrc/hyperion/MultiColorCorrection.cpp new file mode 100644 index 00000000..74148e43 --- /dev/null +++ b/libsrc/hyperion/MultiColorCorrection.cpp @@ -0,0 +1,103 @@ +// Hyperion includes +#include +#include + +MultiColorCorrection::MultiColorCorrection(int ledCnt) : + _ledCorrections(ledCnt, nullptr) +, _log(Logger::getInstance("CORRECTION")) +{ +} + +MultiColorCorrection::~MultiColorCorrection() +{ + // Clean up all the correctinos + for (ColorCorrection * correction : _correction) + { + delete correction; + } +} + +void MultiColorCorrection::addCorrection(ColorCorrection * correction) +{ + _correctionIds.push_back(correction->_id); + _correction.push_back(correction); +} + +void MultiColorCorrection::setCorrectionForLed(const QString& id, int startLed, int endLed) +{ + // abort + if(startLed > endLed) + { + Error(_log,"startLed > endLed -> %d > %d", startLed, endLed); + return; + } + // catch wrong values + if(endLed > static_cast(_ledCorrections.size()-1)) + { + Warning(_log,"The color correction 'LED index' field has LEDs specified which aren't part of your led layout"); + endLed = static_cast(_ledCorrections.size()-1); + } + + // Get the identified correction (don't care if is nullptr) + ColorCorrection * correction = getCorrection(id); + for (int iLed=startLed; iLed<=endLed; ++iLed) + { + _ledCorrections[iLed] = correction; + } +} + +bool MultiColorCorrection::verifyCorrections() const +{ + bool ok = true; + for (unsigned iLed=0; iLed<_ledCorrections.size(); ++iLed) + { + ColorCorrection* adjustment = _ledCorrections[iLed]; + + if (adjustment == nullptr) + { + Warning(_log, "No correction set for led %d", iLed); + ok = false; + } + } + return ok; +} + +QStringList & MultiColorCorrection::getCorrectionIds() +{ + return _correctionIds; +} + +ColorCorrection* MultiColorCorrection::getCorrection(const QString& id) +{ + // Iterate through the unique corrections until we find the one with the given id + for (ColorCorrection * correction : _correction) + { + if (correction->_id == id) + { + return correction; + } + } + + // The ColorCorrection was not found + return nullptr; +} + +void MultiColorCorrection::applyCorrection(std::vector& ledColors) +{ + const size_t itCnt = qMin(_ledCorrections.size(), ledColors.size()); + for (size_t i=0; i_rgbCorrection.correctionR(color.red); + color.green = correction->_rgbCorrection.correctionG(color.green); + color.blue = correction->_rgbCorrection.correctionB(color.blue); + } +} diff --git a/libsrc/hyperion/schema/schema-color.json b/libsrc/hyperion/schema/schema-color.json index abe39560..33b1bdfe 100644 --- a/libsrc/hyperion/schema/schema-color.json +++ b/libsrc/hyperion/schema/schema-color.json @@ -221,6 +221,18 @@ "step" : 0.1, "propertyOrder" : 16 }, + "temperature" : + { + "type" : "integer", + "title" : "edt_conf_color_temperature_title", + "required" : true, + "minimum" : 1000, + "maximum": 40000, + "default" : 6600, + "step" : 100, + "append" : "edt_append_kelvin", + "propertyOrder" : 17 + }, "gammaRed" : { "type" : "number", @@ -230,7 +242,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 17 + "propertyOrder" : 18 }, "gammaGreen" : { @@ -241,7 +253,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 18 + "propertyOrder" : 19 }, "gammaBlue" : { @@ -252,7 +264,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 19 + "propertyOrder" : 20 } }, "additionalProperties" : false diff --git a/libsrc/utils/RgbChannelCorrection.cpp b/libsrc/utils/RgbChannelCorrection.cpp new file mode 100644 index 00000000..7fb16884 --- /dev/null +++ b/libsrc/utils/RgbChannelCorrection.cpp @@ -0,0 +1,120 @@ +// STL includes +#include + +// Utils includes +#include + +RgbChannelCorrection::RgbChannelCorrection() : + _correctionR(255), + _correctionG(255), + _correctionB(255) +{ + initializeMapping(); +} + +RgbChannelCorrection::RgbChannelCorrection(int correctionR, int correctionG, int correctionB) : + _correctionR(correctionR), + _correctionG(correctionG), + _correctionB(correctionB) +{ + initializeMapping(); +} + +RgbChannelCorrection::~RgbChannelCorrection() +{ +} + +uint8_t RgbChannelCorrection::getcorrectionR() const +{ + return _correctionR; +} + +void RgbChannelCorrection::setcorrectionR(uint8_t correctionR) +{ + _correctionR = correctionR; + initializeMapping(); +} + +uint8_t RgbChannelCorrection::getcorrectionG() const +{ + return _correctionG; +} + +void RgbChannelCorrection::setcorrectionG(uint8_t correctionG) +{ + _correctionG = correctionG; + initializeMapping(); +} + +uint8_t RgbChannelCorrection::getcorrectionB() const +{ + return _correctionB; +} + +void RgbChannelCorrection::setcorrectionB(uint8_t correctionB) +{ + _correctionB = correctionB; + initializeMapping(); +} + +uint8_t RgbChannelCorrection::correctionR(uint8_t inputR) const +{ + return _mappingR[inputR]; +} + +uint8_t RgbChannelCorrection::correctionG(uint8_t inputG) const +{ + return _mappingG[inputG]; +} + +uint8_t RgbChannelCorrection::correctionB(uint8_t inputB) const +{ + return _mappingB[inputB]; +} + +void RgbChannelCorrection::initializeMapping() +{ + // initialize the mapping + for (int i = 0; i < 256; ++i) + { + int outputR = (i * _correctionR) / 255; + if (outputR < -255) + { + outputR = -255; + } + else if (outputR > 255) + { + outputR = 255; + } + _mappingR[i] = outputR; + } + for (int i = 0; i < 256; ++i) + { + int outputG = (i * _correctionG) / 255; + if (outputG < -255) + { + outputG = -255; + } + else if (outputG > 255) + { + outputG = 255; + } + _mappingG[i] = outputG; + } + for (int i = 0; i < 256; ++i) + { + int outputB = (i * _correctionB) / 255; + if (outputB < -255) + { + outputB = -255; + } + else if (outputB > 255) + { + outputB = 255; + } + _mappingB[i] = outputB; + } + + +} +