From 2bc38e3784285ea5b319ac976c42b6faf6acb6b3 Mon Sep 17 00:00:00 2001 From: James Ferguson Date: Sat, 13 Feb 2021 15:50:27 -0500 Subject: [PATCH] IR: change to non-linear brightness steps Prior Incrementing/decrementing by fixed steps (typically 10) means large perceptual jumps at low brightness and small jumps at high brightness. This change moves to a geometric progression, closer at the bottom of the range and widely spaced at the top. While it could be done as a relative jump (incrementing by bri/4 and decrementing bri/5 works quite well), it makes for irregular behavior when moving back and forth. --- wled00/fcn_declare.h | 1 - wled00/ir.cpp | 94 +++++++++++++++++++++++++++++++------------- 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 9d053e27..14af50df 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -76,7 +76,6 @@ bool decodeIRCustom(uint32_t code); void applyRepeatActions(); void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF); void changeEffectSpeed(int8_t amount); -void changeBrightness(int8_t amount); void changeEffectIntensity(int8_t amount); void decodeIR(uint32_t code); void decodeIR24(uint32_t code); diff --git a/wled00/ir.cpp b/wled00/ir.cpp index 70c920e0..9bdc81b4 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -21,6 +21,54 @@ uint16_t irTimesRepeated = 0; uint8_t lastIR6ColourIdx = 0; +// brightnessSteps: a static array of brightness levels following a geometric +// progression. Can be generated from the following Python, adjusting the +// arbitrary 4.5 value to taste: +// +// def values(level): +// while level >= 5: +// yield int(level) +// level -= level / 4.5 +// result = [v for v in reversed(list(values(255)))] +// print("%d values: %s" % (len(result), result)) +// +// It would be hard to maintain repeatable steps if calculating this on the fly. +const byte brightnessSteps[] = { + 5, 7, 9, 12, 16, 20, 26, 34, 43, 56, 72, 93, 119, 154, 198, 255 +}; +const size_t numBrightnessSteps = sizeof(brightnessSteps) / sizeof(uint8_t); + +// increment `bri` to the next `brightnessSteps` value +void incBrightness() +{ + // dumb incremental search is efficient enough for so few items + for (int index = 0; index < numBrightnessSteps; ++index) + { + if (brightnessSteps[index] > bri) + { + bri = brightnessSteps[index]; + lastRepeatableAction = ACTION_BRIGHT_UP; + break; + } + } +} + +// decrement `bri` to the next `brightnessSteps` value +void decBrightness() +{ + // dumb incremental search is efficient enough for so few items + for (int index = numBrightnessSteps - 1; index >= 0; --index) + { + if (brightnessSteps[index] < bri) + { + bri = brightnessSteps[index]; + lastRepeatableAction = ACTION_BRIGHT_DOWN; + break; + } + } +} + + //Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control //IR codes themselves can be defined directly after "case" or in "ir_codes.h" bool decodeIRCustom(uint32_t code) @@ -47,16 +95,6 @@ void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte high *property = (byte)constrain(new_val,0.1,255.1); } -void changeBrightness(int8_t amount) -{ - int16_t new_val = bri + amount; - if (new_val < 5) new_val = 5; //minimum brightness A=5 - bri = (byte)constrain(new_val,0.1,255.1); - if(amount > 0) lastRepeatableAction = ACTION_BRIGHT_UP; - if(amount < 0) lastRepeatableAction = ACTION_BRIGHT_DOWN; - lastRepeatableValue = amount; -} - void changeEffectSpeed(int8_t amount) { if (effectCurrent != 0) { @@ -142,11 +180,11 @@ void applyRepeatActions(){ if (lastRepeatableAction == ACTION_BRIGHT_UP) { - changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); + incBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); } else if (lastRepeatableAction == ACTION_BRIGHT_DOWN ) { - changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); + decBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); } if (lastRepeatableAction == ACTION_SPEED_UP) @@ -187,8 +225,8 @@ void applyRepeatActions(){ void decodeIR24(uint32_t code) { switch (code) { - case IR24_BRIGHTER : changeBrightness(10); break; - case IR24_DARKER : changeBrightness(-10); break; + case IR24_BRIGHTER : incBrightness(); break; + case IR24_DARKER : decBrightness(); break; case IR24_OFF : briLast = bri; bri = 0; break; case IR24_ON : bri = briLast; break; case IR24_RED : colorFromUint32(COLOR_RED); break; @@ -219,8 +257,8 @@ void decodeIR24(uint32_t code) void decodeIR24OLD(uint32_t code) { switch (code) { - case IR24_OLD_BRIGHTER : changeBrightness(10); break; - case IR24_OLD_DARKER : changeBrightness(-10); break; + case IR24_OLD_BRIGHTER : incBrightness(); break; + case IR24_OLD_DARKER : decBrightness(); break; case IR24_OLD_OFF : briLast = bri; bri = 0; break; case IR24_OLD_ON : bri = briLast; break; case IR24_OLD_RED : colorFromUint32(COLOR_RED); break; @@ -252,8 +290,8 @@ void decodeIR24OLD(uint32_t code) void decodeIR24CT(uint32_t code) { switch (code) { - case IR24_CT_BRIGHTER : changeBrightness(10); break; - case IR24_CT_DARKER : changeBrightness(-10); break; + case IR24_CT_BRIGHTER : incBrightness(); break; + case IR24_CT_DARKER : decBrightness(); break; case IR24_CT_OFF : briLast = bri; bri = 0; break; case IR24_CT_ON : bri = briLast; break; case IR24_CT_RED : colorFromUint32(COLOR_RED); break; @@ -287,8 +325,8 @@ void decodeIR24CT(uint32_t code) void decodeIR40(uint32_t code) { switch (code) { - case IR40_BPLUS : changeBrightness(10); break; - case IR40_BMINUS : changeBrightness(-10); break; + case IR40_BPLUS : incBrightness(); break; + case IR40_BMINUS : decBrightness(); break; case IR40_OFF : briLast = bri; bri = 0; break; case IR40_ON : bri = briLast; break; case IR40_RED : colorFromUint24(COLOR_RED); break; @@ -344,8 +382,8 @@ void decodeIR40(uint32_t code) void decodeIR44(uint32_t code) { switch (code) { - case IR44_BPLUS : changeBrightness(10); break; - case IR44_BMINUS : changeBrightness(-10); break; + case IR44_BPLUS : incBrightness(); break; + case IR44_BMINUS : decBrightness(); break; case IR44_OFF : briLast = bri; bri = 0; break; case IR44_ON : bri = briLast; break; case IR44_RED : colorFromUint24(COLOR_RED); break; @@ -407,8 +445,8 @@ void decodeIR44(uint32_t code) void decodeIR21(uint32_t code) { switch (code) { - case IR21_BRIGHTER: changeBrightness(10); break; - case IR21_DARKER: changeBrightness(-10); break; + case IR21_BRIGHTER: incBrightness(); break; + case IR21_DARKER: decBrightness(); break; case IR21_OFF: briLast = bri; bri = 0; break; case IR21_ON: bri = briLast; break; case IR21_RED: colorFromUint32(COLOR_RED); break; @@ -437,8 +475,8 @@ void decodeIR6(uint32_t code) { switch (code) { case IR6_POWER: toggleOnOff(); break; - case IR6_CHANNEL_UP: changeBrightness(10); break; - case IR6_CHANNEL_DOWN: changeBrightness(-10); break; + case IR6_CHANNEL_UP: incBrightness(); break; + case IR6_CHANNEL_DOWN: decBrightness(); break; case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect case IR6_VOLUME_DOWN: // next palette relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1); @@ -472,8 +510,8 @@ void decodeIR9(uint32_t code) case IR9_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break; case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; break; case IR9_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break; - case IR9_UP : changeBrightness(16); break; - case IR9_DOWN : changeBrightness(-16); break; + case IR9_UP : incBrightness(); break; + case IR9_DOWN : decBrightness(); break; //case IR9_UP : changeEffectIntensity(16); break; //case IR9_DOWN : changeEffectIntensity(-16); break; case IR9_LEFT : changeEffectSpeed(-16); break;