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.
This commit is contained in:
James Ferguson 2021-02-13 15:50:27 -05:00
parent aa242d897d
commit 2bc38e3784
2 changed files with 66 additions and 29 deletions

View File

@ -76,7 +76,6 @@ bool decodeIRCustom(uint32_t code);
void applyRepeatActions(); void applyRepeatActions();
void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF); void relativeChange(byte* property, int8_t amount, byte lowerBoundary = 0, byte higherBoundary = 0xFF);
void changeEffectSpeed(int8_t amount); void changeEffectSpeed(int8_t amount);
void changeBrightness(int8_t amount);
void changeEffectIntensity(int8_t amount); void changeEffectIntensity(int8_t amount);
void decodeIR(uint32_t code); void decodeIR(uint32_t code);
void decodeIR24(uint32_t code); void decodeIR24(uint32_t code);

View File

@ -21,6 +21,54 @@ uint16_t irTimesRepeated = 0;
uint8_t lastIR6ColourIdx = 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 //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" //IR codes themselves can be defined directly after "case" or in "ir_codes.h"
bool decodeIRCustom(uint32_t code) 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); *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) void changeEffectSpeed(int8_t amount)
{ {
if (effectCurrent != 0) { if (effectCurrent != 0) {
@ -142,11 +180,11 @@ void applyRepeatActions(){
if (lastRepeatableAction == ACTION_BRIGHT_UP) if (lastRepeatableAction == ACTION_BRIGHT_UP)
{ {
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); incBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
else if (lastRepeatableAction == ACTION_BRIGHT_DOWN ) else if (lastRepeatableAction == ACTION_BRIGHT_DOWN )
{ {
changeBrightness(lastRepeatableValue); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); decBrightness(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON);
} }
if (lastRepeatableAction == ACTION_SPEED_UP) if (lastRepeatableAction == ACTION_SPEED_UP)
@ -187,8 +225,8 @@ void applyRepeatActions(){
void decodeIR24(uint32_t code) void decodeIR24(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_BRIGHTER : changeBrightness(10); break; case IR24_BRIGHTER : incBrightness(); break;
case IR24_DARKER : changeBrightness(-10); break; case IR24_DARKER : decBrightness(); break;
case IR24_OFF : briLast = bri; bri = 0; break; case IR24_OFF : briLast = bri; bri = 0; break;
case IR24_ON : bri = briLast; break; case IR24_ON : bri = briLast; break;
case IR24_RED : colorFromUint32(COLOR_RED); break; case IR24_RED : colorFromUint32(COLOR_RED); break;
@ -219,8 +257,8 @@ void decodeIR24(uint32_t code)
void decodeIR24OLD(uint32_t code) void decodeIR24OLD(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_OLD_BRIGHTER : changeBrightness(10); break; case IR24_OLD_BRIGHTER : incBrightness(); break;
case IR24_OLD_DARKER : changeBrightness(-10); break; case IR24_OLD_DARKER : decBrightness(); break;
case IR24_OLD_OFF : briLast = bri; bri = 0; break; case IR24_OLD_OFF : briLast = bri; bri = 0; break;
case IR24_OLD_ON : bri = briLast; break; case IR24_OLD_ON : bri = briLast; break;
case IR24_OLD_RED : colorFromUint32(COLOR_RED); break; case IR24_OLD_RED : colorFromUint32(COLOR_RED); break;
@ -252,8 +290,8 @@ void decodeIR24OLD(uint32_t code)
void decodeIR24CT(uint32_t code) void decodeIR24CT(uint32_t code)
{ {
switch (code) { switch (code) {
case IR24_CT_BRIGHTER : changeBrightness(10); break; case IR24_CT_BRIGHTER : incBrightness(); break;
case IR24_CT_DARKER : changeBrightness(-10); break; case IR24_CT_DARKER : decBrightness(); break;
case IR24_CT_OFF : briLast = bri; bri = 0; break; case IR24_CT_OFF : briLast = bri; bri = 0; break;
case IR24_CT_ON : bri = briLast; break; case IR24_CT_ON : bri = briLast; break;
case IR24_CT_RED : colorFromUint32(COLOR_RED); break; case IR24_CT_RED : colorFromUint32(COLOR_RED); break;
@ -287,8 +325,8 @@ void decodeIR24CT(uint32_t code)
void decodeIR40(uint32_t code) void decodeIR40(uint32_t code)
{ {
switch (code) { switch (code) {
case IR40_BPLUS : changeBrightness(10); break; case IR40_BPLUS : incBrightness(); break;
case IR40_BMINUS : changeBrightness(-10); break; case IR40_BMINUS : decBrightness(); break;
case IR40_OFF : briLast = bri; bri = 0; break; case IR40_OFF : briLast = bri; bri = 0; break;
case IR40_ON : bri = briLast; break; case IR40_ON : bri = briLast; break;
case IR40_RED : colorFromUint24(COLOR_RED); break; case IR40_RED : colorFromUint24(COLOR_RED); break;
@ -344,8 +382,8 @@ void decodeIR40(uint32_t code)
void decodeIR44(uint32_t code) void decodeIR44(uint32_t code)
{ {
switch (code) { switch (code) {
case IR44_BPLUS : changeBrightness(10); break; case IR44_BPLUS : incBrightness(); break;
case IR44_BMINUS : changeBrightness(-10); break; case IR44_BMINUS : decBrightness(); break;
case IR44_OFF : briLast = bri; bri = 0; break; case IR44_OFF : briLast = bri; bri = 0; break;
case IR44_ON : bri = briLast; break; case IR44_ON : bri = briLast; break;
case IR44_RED : colorFromUint24(COLOR_RED); break; case IR44_RED : colorFromUint24(COLOR_RED); break;
@ -407,8 +445,8 @@ void decodeIR44(uint32_t code)
void decodeIR21(uint32_t code) void decodeIR21(uint32_t code)
{ {
switch (code) { switch (code) {
case IR21_BRIGHTER: changeBrightness(10); break; case IR21_BRIGHTER: incBrightness(); break;
case IR21_DARKER: changeBrightness(-10); break; case IR21_DARKER: decBrightness(); break;
case IR21_OFF: briLast = bri; bri = 0; break; case IR21_OFF: briLast = bri; bri = 0; break;
case IR21_ON: bri = briLast; break; case IR21_ON: bri = briLast; break;
case IR21_RED: colorFromUint32(COLOR_RED); break; case IR21_RED: colorFromUint32(COLOR_RED); break;
@ -437,8 +475,8 @@ void decodeIR6(uint32_t code)
{ {
switch (code) { switch (code) {
case IR6_POWER: toggleOnOff(); break; case IR6_POWER: toggleOnOff(); break;
case IR6_CHANNEL_UP: changeBrightness(10); break; case IR6_CHANNEL_UP: incBrightness(); break;
case IR6_CHANNEL_DOWN: changeBrightness(-10); break; case IR6_CHANNEL_DOWN: decBrightness(); break;
case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect case IR6_VOLUME_UP: relativeChange(&effectCurrent, 1, 0, MODE_COUNT); break; // next effect
case IR6_VOLUME_DOWN: // next palette case IR6_VOLUME_DOWN: // next palette
relativeChange(&effectPalette, 1, 0, strip.getPaletteCount() -1); 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_A : if (!applyPreset(1)) effectCurrent = FX_MODE_COLORTWINKLE; break;
case IR9_B : if (!applyPreset(2)) effectCurrent = FX_MODE_RAINBOW_CYCLE; 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_C : if (!applyPreset(3)) effectCurrent = FX_MODE_BREATH; break;
case IR9_UP : changeBrightness(16); break; case IR9_UP : incBrightness(); break;
case IR9_DOWN : changeBrightness(-16); break; case IR9_DOWN : decBrightness(); break;
//case IR9_UP : changeEffectIntensity(16); break; //case IR9_UP : changeEffectIntensity(16); break;
//case IR9_DOWN : changeEffectIntensity(-16); break; //case IR9_DOWN : changeEffectIntensity(-16); break;
case IR9_LEFT : changeEffectSpeed(-16); break; case IR9_LEFT : changeEffectSpeed(-16); break;