mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-31 05:12:33 +01:00 
			
		
		
		
	Refine twinkle to be smoother (use breathing curve) (#11350)
* Refine twinkle to be smoother (use breathing curve) * tune more for firmware size * fix bug when v=255 ~ drashna approved ~
This commit is contained in:
		
							parent
							
								
									ff2bd2ee18
								
							
						
					
					
						commit
						6e8adeeaac
					
				| @ -148,7 +148,7 @@ The following options are used to tweak the various animations: | |||||||
| |`RGBLIGHT_EFFECT_KNIGHT_OFFSET`     |`0`          |The number of LEDs to start the "Knight" animation from the start of the strip by              | | |`RGBLIGHT_EFFECT_KNIGHT_OFFSET`     |`0`          |The number of LEDs to start the "Knight" animation from the start of the strip by              | | ||||||
| |`RGBLIGHT_RAINBOW_SWIRL_RANGE`      |`255`        |Range adjustment for the rainbow swirl effect to get different swirls                          | | |`RGBLIGHT_RAINBOW_SWIRL_RANGE`      |`255`        |Range adjustment for the rainbow swirl effect to get different swirls                          | | ||||||
| |`RGBLIGHT_EFFECT_SNAKE_LENGTH`      |`4`          |The number of LEDs to light up for the "Snake" animation                                       | | |`RGBLIGHT_EFFECT_SNAKE_LENGTH`      |`4`          |The number of LEDs to light up for the "Snake" animation                                       | | ||||||
| |`RGBLIGHT_EFFECT_TWINKLE_LIFE`      |`75`         |Adjusts how quickly each LED brightens and dims when twinkling (in animation steps)            | | |`RGBLIGHT_EFFECT_TWINKLE_LIFE`      |`200`        |Adjusts how quickly each LED brightens and dims when twinkling (in animation steps)            | | ||||||
| |`RGBLIGHT_EFFECT_TWINKLE_PROBABILITY`|`1/127`     |Adjusts how likely each LED is to twinkle (on each animation step)                             | | |`RGBLIGHT_EFFECT_TWINKLE_PROBABILITY`|`1/127`     |Adjusts how likely each LED is to twinkle (on each animation step)                             | | ||||||
| 
 | 
 | ||||||
| ### Example Usage to Reduce Memory Footprint | ### Example Usage to Reduce Memory Footprint | ||||||
|  | |||||||
| @ -42,6 +42,9 @@ | |||||||
| #ifndef MIN | #ifndef MIN | ||||||
| #    define MIN(a, b) (((a) < (b)) ? (a) : (b)) | #    define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||||||
| #endif | #endif | ||||||
|  | #ifndef MAX | ||||||
|  | #    define MAX(a, b) (((a) > (b)) ? (a) : (b)) | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef RGBLIGHT_SPLIT | #ifdef RGBLIGHT_SPLIT | ||||||
| /* for split keyboard */ | /* for split keyboard */ | ||||||
| @ -933,7 +936,7 @@ void rgblight_task(void) { | |||||||
| #    endif | #    endif | ||||||
| #    ifdef RGBLIGHT_EFFECT_TWINKLE | #    ifdef RGBLIGHT_EFFECT_TWINKLE | ||||||
|         else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { |         else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { | ||||||
|             interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); |             interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30); | ||||||
|             effect_func   = (effect_func_t)rgblight_effect_twinkle; |             effect_func   = (effect_func_t)rgblight_effect_twinkle; | ||||||
|         } |         } | ||||||
| #    endif | #    endif | ||||||
| @ -975,8 +978,7 @@ void rgblight_task(void) { | |||||||
| 
 | 
 | ||||||
| #endif /* RGBLIGHT_USE_TIMER */ | #endif /* RGBLIGHT_USE_TIMER */ | ||||||
| 
 | 
 | ||||||
| // Effects
 | #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE) | ||||||
| #ifdef RGBLIGHT_EFFECT_BREATHING |  | ||||||
| 
 | 
 | ||||||
| #    ifndef RGBLIGHT_EFFECT_BREATHE_CENTER | #    ifndef RGBLIGHT_EFFECT_BREATHE_CENTER | ||||||
| #        ifndef RGBLIGHT_BREATHE_TABLE_SIZE | #        ifndef RGBLIGHT_BREATHE_TABLE_SIZE | ||||||
| @ -985,17 +987,24 @@ void rgblight_task(void) { | |||||||
| #        include <rgblight_breathe_table.h> | #        include <rgblight_breathe_table.h> | ||||||
| #    endif | #    endif | ||||||
| 
 | 
 | ||||||
|  | static uint8_t breathe_calc(uint8_t pos) { | ||||||
|  |     // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
 | ||||||
|  | #    ifdef RGBLIGHT_EFFECT_BREATHE_TABLE | ||||||
|  |     return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]); | ||||||
|  | #    else | ||||||
|  |     return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); | ||||||
|  | #    endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | // Effects
 | ||||||
|  | #ifdef RGBLIGHT_EFFECT_BREATHING | ||||||
|  | 
 | ||||||
| __attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; | __attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; | ||||||
| 
 | 
 | ||||||
| void rgblight_effect_breathing(animation_status_t *anim) { | void rgblight_effect_breathing(animation_status_t *anim) { | ||||||
|     float val; |     uint8_t val = breathe_calc(anim->pos); | ||||||
| 
 |  | ||||||
|     // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
 |  | ||||||
| #    ifdef RGBLIGHT_EFFECT_BREATHE_TABLE |  | ||||||
|     val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]); |  | ||||||
| #    else |  | ||||||
|     val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); |  | ||||||
| #    endif |  | ||||||
|     rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); |     rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); | ||||||
|     anim->pos = (anim->pos + 1); |     anim->pos = (anim->pos + 1); | ||||||
| } | } | ||||||
| @ -1247,48 +1256,54 @@ void rgblight_effect_alternating(animation_status_t *anim) { | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef RGBLIGHT_EFFECT_TWINKLE | #ifdef RGBLIGHT_EFFECT_TWINKLE | ||||||
| __attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; | __attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5}; | ||||||
| 
 | 
 | ||||||
| typedef struct PACKED { | typedef struct PACKED { | ||||||
|     HSV     hsv; |     HSV     hsv; | ||||||
|     uint8_t life; |     uint8_t life; | ||||||
|     bool    up; |     uint8_t max_life; | ||||||
| } TwinkleState; | } TwinkleState; | ||||||
| 
 | 
 | ||||||
| static TwinkleState led_twinkle_state[RGBLED_NUM]; | static TwinkleState led_twinkle_state[RGBLED_NUM]; | ||||||
| 
 | 
 | ||||||
| void rgblight_effect_twinkle(animation_status_t *anim) { | void rgblight_effect_twinkle(animation_status_t *anim) { | ||||||
|     bool random_color = anim->delta / 3; |     const bool random_color = anim->delta / 3; | ||||||
|     bool restart      = anim->pos == 0; |     const bool restart      = anim->pos == 0; | ||||||
|     anim->pos               = 1; |     anim->pos               = 1; | ||||||
| 
 | 
 | ||||||
|  |     const uint8_t bottom = breathe_calc(0); | ||||||
|  |     const uint8_t top    = breathe_calc(127); | ||||||
|  | 
 | ||||||
|  |     uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; } | ||||||
|  |     uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; } | ||||||
|  | 
 | ||||||
|     for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { |     for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||||||
|         TwinkleState *t = &(led_twinkle_state[i]); |         TwinkleState *t = &(led_twinkle_state[i]); | ||||||
|         HSV *         c = &(t->hsv); |         HSV *         c = &(t->hsv); | ||||||
|         if (restart) { | 
 | ||||||
|             // Restart
 |  | ||||||
|             t->life  = 0; |  | ||||||
|             t->hsv.v = 0; |  | ||||||
|         } else if (t->life) { |  | ||||||
|             // This LED is already on, either brightening or dimming
 |  | ||||||
|             t->life--; |  | ||||||
|             uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; |  | ||||||
|             c->v       = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; |  | ||||||
|             if (t->life == 0 && t->up) { |  | ||||||
|                 t->up   = false; |  | ||||||
|                 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; |  | ||||||
|             } |  | ||||||
|         if (!random_color) { |         if (!random_color) { | ||||||
|             c->h = rgblight_config.hue; |             c->h = rgblight_config.hue; | ||||||
|             c->s = rgblight_config.sat; |             c->s = rgblight_config.sat; | ||||||
|         } |         } | ||||||
|         } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) { | 
 | ||||||
|             // This LED is off, but was randomly selected to start brightening
 |         if (restart) { | ||||||
|             c->h    = random_color ? rand() % 0xFF : rgblight_config.hue; |             // Restart
 | ||||||
|             c->s    = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; |             t->life = 0; | ||||||
|             c->v    = 0; |             c->v    = 0; | ||||||
|             t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; |         } else if (t->life) { | ||||||
|             t->up   = true; |             // This LED is already on, either brightening or dimming
 | ||||||
|  |             t->life--; | ||||||
|  |             uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom); | ||||||
|  |             c->v             = scale(rgblight_config.val, unscaled); | ||||||
|  |         } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) { | ||||||
|  |             // This LED is off, but was randomly selected to start brightening
 | ||||||
|  |             if (random_color) { | ||||||
|  |                 c->h = rand() % 0xFF; | ||||||
|  |                 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2); | ||||||
|  |             } | ||||||
|  |             c->v        = 0; | ||||||
|  |             t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val)); | ||||||
|  |             t->life     = t->max_life; | ||||||
|         } else { |         } else { | ||||||
|             // This LED is off, and was NOT selected to start brightening
 |             // This LED is off, and was NOT selected to start brightening
 | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -150,7 +150,7 @@ enum RGBLIGHT_EFFECT_MODE { | |||||||
| #    endif | #    endif | ||||||
| 
 | 
 | ||||||
| #    ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE | #    ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE | ||||||
| #        define RGBLIGHT_EFFECT_TWINKLE_LIFE 75 | #        define RGBLIGHT_EFFECT_TWINKLE_LIFE 200 | ||||||
| #    endif | #    endif | ||||||
| 
 | 
 | ||||||
| #    ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY | #    ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Joshua Diamond
						Joshua Diamond