FastLED 3.9.15
Loading...
Searching...
No Matches
Painter.cpp
Go to the documentation of this file.
1
2
3#include <Arduino.h>
4
5#include "./Painter.h"
7#include "./dprint.h"
8#include "./Keyboard.h"
9#include "fl/math/math.h"
10#include "fl/math/math.h"
11#include "fl/log/log.h"
12#include "fl/stl/cstring.h"
13
14namespace {
15
16float LuminanceDecay(float time) {
17 typedef InterpData<float, float> Datum;
18 static const Datum kData[] = {
19 Datum(0, 0),
20 Datum(1, 0),
21 Datum(10, 0),
22 Datum(47, 60),
23 Datum(120, 100),
24 Datum(230, 160),
25 Datum(250, 255),
26 Datum(254, 255),
27 Datum(255, 64),
28 };
29
30 const float key = time * 255.f;
31 static const int n = sizeof(kData) / sizeof(kData[0]);
32 float approx_val = Interp(key, kData, n);
33
34
35 static const float k = (1.0f / 255.f);
36 const float out = approx_val * k;
37 return out;
38}
39
40float CalcLuminance(float time_delta_ms,
41 bool sustain_pedal_on,
42 const Key& key,
43 int key_idx) {
44
45 if (key.mCurrColor.v_ <= 0.0) {
46 return 0.0;
47 }
48
49 const bool dampened_key = (key_idx < kFirstNoteNoDamp);
50
51 const float decay_factor = CalcDecayFactor(sustain_pedal_on,
52 key.mOn,
53 key_idx,
54 key.mVelocity * (1.f/127.f), // Normalizing
55 dampened_key,
56 time_delta_ms);
57
58 if (key.mOn) {
59 //const float brigthness_factor = sin(key.mOrigColor.v_ * PI / 2.0);
60 float brigthness_factor = 0.0f;
61
62 if (kUseLedCurtin) {
63 brigthness_factor = fl::sqrt(fl::sqrt(key.mOrigColor.v_));
64 } else {
65 //brigthness_factor = key.mOrigColor.v_ * key.mOrigColor.v_;
66 brigthness_factor = key.mOrigColor.v_;
67 }
68 return LuminanceDecay(decay_factor) * brigthness_factor;
69 //return 1.0f;
70 } else {
71 return decay_factor * key.mOrigColor.v_;
72 }
73}
74
75float CalcSaturation(float time_delta_ms, const ColorHSV& color, bool key_on) {
76 if (color.v_ <= 0.0) {
77 return color.s_;
78 }
79 if (!key_on) {
80 return 1.0f;
81 }
82 static const float kDefaultSaturationTime = 0.05f * 1000.f;
83
84 // At time = 0.0 the saturation_factor will be at 0.0 and then transition to 1.0
85 float saturation_factor = mapf(time_delta_ms,
86 0.0f, kDefaultSaturationTime,
87 0.0f, 1.0f);
88 // As time increases the saturation factor will continue
89 // to grow past 1.0. We use min to clamp it back to 1.0.
90 saturation_factor = fl::min(1.0f, saturation_factor);
91 // TODO - make the saturation interpolate between the original
92 // color and the unsaturated state.
93 return saturation_factor;
94}
95
96} // namespace.
97
98
99void Painter::Paint(uint32_t now_ms,
100 uint32_t delta_ms,
101 VisState vis_state,
103 LedRopeInterface* light_rope) {
104 for (int i = 0; i < KeyboardState::kNumKeys; ++i) {
105 Key& key = keyboard->mKeys[i];
106
107 const float time_delta_ms = static_cast<float>(now_ms - key.mEventTime);
108
109 const float lum = CalcLuminance(time_delta_ms, keyboard->mSustainPedal, key, i);
110 const float sat = CalcSaturation(time_delta_ms, key.mCurrColor, key.mOn);
111
112 //if (key.mIdx == 56) {
113 // dprint("lum: "); dprint(lum*255.f); dprint(" sat:"); dprintln(sat*255.f);
114 //}
115
116 key.mCurrColor.v_ = lum;
117 key.mCurrColor.s_ = sat;
118
119 // Removing this line breaks one of the visualizers...
120 // TODO: Figure out a cleaner solution.
121 light_rope->Set(i, key.mCurrColor.ToRGB());
122 }
123
124 LedColumns led_columns = LedLayoutArray();
125
126 switch (vis_state) {
127 case Painter::kBlockNote: {
129 break;
130 }
132 light_rope->DrawRepeat(led_columns.array, kNumKeys);
133 break;
134 }
135 case Painter::kVUNote: {
136 PaintVuNotes(now_ms, *keyboard, led_columns.array, kNumKeys, light_rope);
137 break;
138 }
139 case Painter::kVUMidNote: {
140 PaintVuMidNotesFade(delta_ms, *keyboard, led_columns.array, kNumKeys, light_rope);
141 break;
142 }
143
144 case Painter::kVegas: { // aka "vegas mode?"
145 VegasVisualizer(*keyboard, led_columns.array, kNumKeys, light_rope);
146 break;
147 }
148
150 PaintBrightSurprise(*keyboard, led_columns.array, kNumKeys, light_rope);
151 break;
152 }
153
155 PaintVuSpaceInvaders(now_ms, *keyboard, led_columns.array, kNumKeys, light_rope);
156 break;
157 }
158
159 default:
160 dprint("Unknown mode: "); dprint(vis_state); dprint(".\n");
161 break;
162 }
163}
164
165void Painter::PaintVuNotes(uint32_t /*now_ms*/,
166 const KeyboardState& keyboard,
167 const int* led_column_table, int led_column_table_length,
169
170
171 FL_WARN("\n\n############## VU NOTES ################\n\n");
172
173 led_rope->RawBeginDraw();
174
175 for (int i = 0; i < led_column_table_length; ++i) {
176 const Key& key = keyboard.mKeys[i];
177
178
179 // Map the white keys to the bottom and the black keys to the top.
180 bool black_key = false;
181 switch (key.mIdx % 12) {
182 case 1:
183 case 4:
184 case 6:
185 case 9:
186 case 11:
187 black_key = true;
188 break;
189 }
190
191 const int pixel_count = led_column_table[i];
192 const int draw_pixel_count = fl::ceil(pixel_count * fl::sqrt(key.mCurrColor.v_));
193
194 const int black_pixel_count = pixel_count - draw_pixel_count;
195 const Color3i& c = *led_rope->GetIterator(i);
196
197
198 const bool reverse_correct = black_key == (key.mIdx % 2);
199
200 if (reverse_correct) {
201 for (int j = 0; j < draw_pixel_count; ++j) {
202 if (j < draw_pixel_count - 1) {
203 led_rope->RawDrawPixel(c);
204 } else {
205 // Last pixel.
206 ColorHSV hsv(random(512) / 512.f, random(512) / 512.f, 1.0);
207 led_rope->RawDrawPixel(hsv.ToRGB());
208 }
209 }
210
211 for (int j = 0; j < black_pixel_count; ++j) {
212 led_rope->RawDrawPixel(Color3i::Black());
213 }
214 } else {
215 for (int j = 0; j < black_pixel_count; ++j) {
216 led_rope->RawDrawPixel(Color3i::Black());
217 }
218
219 for (int j = draw_pixel_count - 1; j >= 0; --j) {
220 if (j < draw_pixel_count - 1) {
221 led_rope->RawDrawPixel(c);
222 } else {
223 // Last pixel.
224 ColorHSV hsv(random(512) / 512.f, random(512) / 512.f, 1.0);
225 led_rope->RawDrawPixel(hsv.ToRGB());
226 }
227 }
228 }
229 }
230 led_rope->RawCommitDraw();
231}
232
233void Painter::PaintVuMidNotesFade(uint32_t /*delta_ms*/,
234 const KeyboardState& keyboard,
235 const int* led_column_table, int led_column_table_length,
237
238 FL_WARN("\n\n############## VU MID NOTES FADE ################\n\n");
239
240 struct DrawPoints {
241 int n_black0;
242 int n_fade0;
243 int n_fill;
244 int n_fade1;
245 int n_black1;
246 float fade_factor; // 0->1.0
247
248 float SumBrightness() const {
249 float out = 0;
250 out += n_fill;
251 out += (fade_factor * n_fade0);
252 out += (fade_factor * n_fade1);
253 return out;
254 }
255 };
256
257 // Generator for the DrawPoints struct above.
258 // n_led: How many led's there are in total.
259 // factor: 0->1, indicates % of led's "on".
260 struct F {
261 static DrawPoints Generate(int n_led, float factor) {
262 DrawPoints out;
263 fl::memset(&out, 0, sizeof(out));
264 if (n_led == 0 || factor == 0.0f) {
265 out.n_black0 = n_led;
266 return out;
267 }
268 const int is_odd = (n_led % 2);
269 const int n_half_lights = n_led / 2 + is_odd;
270 const float f_half_fill = n_half_lights * factor;
271 const int n_half_fill = static_cast<int>(f_half_fill); // Truncates float.
272
273 float fade_pix_perc = f_half_fill - static_cast<float>(n_half_fill);
274 int n_fade_pix = fade_pix_perc < 1.0f;
275 if (n_half_fill == 0) {
276 n_fade_pix = 1;
277 }
278 int n_half_black = n_half_lights - n_half_fill - n_fade_pix;
279
280 int n_fill_pix = 0;
281 if (n_half_fill > 0) {
282 n_fill_pix = n_half_fill * 2 + (is_odd ? -1 : 0);
283 }
284
285 out.n_black0 = n_half_black;
286 out.n_fade0 = n_fade_pix;
287 out.n_fill = n_fill_pix;
288 out.n_fade1 = n_fade_pix;
289 if (!n_fill_pix && is_odd) {
290 out.n_fade1 = 0;
291 }
292 out.n_black1 = n_half_black;
293 out.fade_factor = fade_pix_perc;
294 return out;
295 }
296 };
297
298
299 led_rope->RawBeginDraw();
300
301 for (int i = 0; i < led_column_table_length; ++i) {
302 const Key& key = keyboard.mKeys[i];
303
304 float active_lights_factor = key.IntensityFactor();
305
306 //if (key.mCurrColor.v_ <= 0.f) {
307 // active_lights_factor = 0.0;
308 //}
309
310 const int n_led = led_column_table[i];
311
312 if (active_lights_factor > 0.0f) {
313 DrawPoints dp = F::Generate(n_led, active_lights_factor);
314
315 ColorHSV hsv = key.mCurrColor;
316 hsv.v_ = 1.0;
317 Color3i color = hsv.ToRGB();
318 // Now figure out optional fade color
319 Color3i fade_col;
320 ColorHSV c = key.mCurrColor;
321 c.v_ = dp.fade_factor;
322 fade_col = c.ToRGB();
323
324 // Output to graphics.
325 led_rope->RawDrawPixels(Color3i::Black(), dp.n_black0);
326 led_rope->RawDrawPixels(fade_col, dp.n_fade0);
327 led_rope->RawDrawPixels(color, dp.n_fill);
328 led_rope->RawDrawPixels(fade_col, dp.n_fade1);
329 led_rope->RawDrawPixels(Color3i::Black(), dp.n_black1);
330
331#ifdef DEBUG_PAINTER
332 if (active_lights_factor > 0.0) {
333 int total_lights_on = dp.SumBrightness();
334 //dprint("total_lights_on: "); dprint(total_lights_on);
335 //dprint(", total lights written: "); dprintln(total_lights_on + dp.n_black0 + dp.n_black1);
336
337 //float total = (dp.n_fade0 * dp.fade_factor) + (dp.n_fade1 * dp.fade_factor) + static_cast<float>(dp.n_fill);
338 #define P(X) dprint(", "#X ": "); dprint(X);
339
340 //dprint("active_lights_factor: "); dprintln(active_lights_factor);
341
342 //P(dp.n_black0); P(dp.n_fade0); P(dp.n_fill); P(dp.n_fade1); P(dp.n_black1); P(dp.fade_factor);
343 P(total_lights_on);
344 P(active_lights_factor);
345 //P(total);
346 dprintln("");
347 }
348#endif
349 } else {
350 led_rope->RawDrawPixels(Color3i::Black(), n_led);
351 }
352
353
354
355 }
356
357
358 led_rope->RawCommitDraw();
359}
360
362 const int* led_column_table, int led_column_table_length,
364
365 led_rope->RawBeginDraw();
366
367 uint32_t skipped_lights = 0;
368 for (int i = 0; i < led_column_table_length; ++i) {
369 const Key& key = keyboard.mKeys[i];
370 uint32_t painted_lights = 0;
371
372 // % of lights that are active.
373 const float active_lights_factor = led_column_table[i] * fl::sqrt(key.mCurrColor.v_);
374 const float inactive_lights_factor = 1.0f - active_lights_factor;
375 const float taper_point_1 = inactive_lights_factor / 2.0f;
376 const float taper_point_2 = taper_point_1 + active_lights_factor;
377
378 const int taper_idx_1 = static_cast<int>(fl::floor(taper_point_1 * led_column_table[i]));
379 const int taper_idx_2 = static_cast<int>(fl::floor(taper_point_2 * led_column_table[i]));
380
381 const Color3i c = key.mCurrColor.ToRGB();
382
383 for (int i = 0; i < taper_idx_1 / 2; ++i) {
384 led_rope->RawDrawPixel(Color3i::Black());
385 painted_lights++;
386 }
387
388 int length = taper_idx_2 - taper_idx_1;
389 for (int i = 0; i < fl::min(200, length); ++i) {
390 led_rope->RawDrawPixel(c);
391 painted_lights++;
392 }
393
394 length = led_column_table[i] - taper_idx_2;
395 for (int i = 0; i < length; ++i) {
396 led_rope->RawDrawPixel(Color3i::Black());
397 painted_lights++;
398 }
399 skipped_lights += fl::max(0, static_cast<int32_t>(led_column_table[i]) - static_cast<int32_t>(painted_lights));
400 }
401
402 for (uint32_t i = 0; i < skipped_lights; ++i) {
403 led_rope->RawDrawPixel(Color3i::Black());
404 }
405
406 led_rope->RawCommitDraw();
407}
408
410 const KeyboardState& keyboard,
411 const int* led_column_table, int led_column_table_length,
413
414 led_rope->RawBeginDraw();
415 int total_counted = 0;
416
417 float r, g, b;
418 r = g = b = 0;
419
420 for (int i = 0; i < KeyboardState::kNumKeys; ++i) {
421 const Key& key = keyboard.mKeys[i];
422
423
424 if (key.mCurrColor.v_ > 0.0f) {
425 const Color3i rgb = key.mCurrColor.ToRGB();
426 r += rgb.r_;
427 g += rgb.g_;
428 b += rgb.b_;
429 ++total_counted;
430 }
431 }
432
433 float denom = total_counted ? total_counted : 1;
434 r /= denom;
435 g /= denom;
436 b /= denom;
437
438
439 const Color3i rgb(r, g, b);
440
441 for (int i = 0; i < led_column_table_length; ++i) {
442 const int n = led_column_table[i];
443 for (int i = 0; i < n; ++i) {
444 led_rope->RawDrawPixel(rgb);
445 }
446 }
447 led_rope->RawCommitDraw();
448}
449
450void Painter::PaintVuSpaceInvaders(uint32_t /*now_ms*/,
451 const KeyboardState& keyboard,
452 const int* led_column_table, int led_column_table_length,
454 led_rope->RawBeginDraw();
455
456 Color3i black = Color3i::Black();
457
458 for (int i = 0; i < led_column_table_length; ++i) {
459 const Key& key = keyboard.mKeys[i];
460
461 const int pixel_count = led_column_table[i];
462 const int draw_pixel_count = fl::ceil(pixel_count * fl::sqrt(key.mCurrColor.v_));
463
464 const int black_pixel_count = pixel_count - draw_pixel_count;
465
466 // If i is even
467 if (i % 2 == 0) {
468 for (int j = 0; j < black_pixel_count; ++j) {
469 led_rope->RawDrawPixel(*led_rope->GetIterator(i));
470 }
471 for (int j = 0; j < draw_pixel_count; ++j) {
472 led_rope->RawDrawPixel(black);
473 }
474 } else {
475
476 for (int j = 0; j < draw_pixel_count; ++j) {
477 led_rope->RawDrawPixel(black);
478 }
479
480 for (int j = 0; j < black_pixel_count; ++j) {
481 led_rope->RawDrawPixel(*led_rope->GetIterator(i));
482 }
483 }
484 }
485 led_rope->RawCommitDraw();
486}
ValT Interp(const KeyT &k, const InterpData< KeyT, ValT > *array, const int n)
@ kFirstNoteNoDamp
Definition Keyboard.h:15
LedRopeTCL led_rope(kNumKeys)
KeyboardState keyboard
static const int kNumKeys
Definition Keyboard.h:101
virtual void Set(int i, const Color3i &c)=0
virtual void DrawRepeat(const int *value_array, int array_length)=0
virtual void DrawSequentialRepeat(int repeat)=0
fl::UISlider length("Length", 1.0f, 0.0f, 1.0f, 0.01f)
#define dprint(x)
Definition dprint.h:13
#define dprintln(x)
Definition dprint.h:14
Definition Luminova.h:46
LedColumns LedLayoutArray()
#define FL_WARN(X)
Definition log.h:276
Centralized logging categories for FastLED hardware interfaces and subsystems.
float CalcLuminance(float time_delta_ms, bool sustain_pedal_on, const Key &key, int key_idx)
Definition Painter.cpp:40
float CalcSaturation(float time_delta_ms, const ColorHSV &color, bool key_on)
Definition Painter.cpp:75
float LuminanceDecay(float time)
Definition Painter.cpp:16
FL_DISABLE_WARNING_PUSH U constexpr common_type_t< T, U > min(T a, U b) FL_NOEXCEPT
Definition math.h:71
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
constexpr enable_if< is_fixed_point< T >::value, T >::type ceil(T x) FL_NOEXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type sqrt(T x) FL_NOEXCEPT
void * memset(void *s, int c, size_t n) FL_NOEXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type floor(T x) FL_NOEXCEPT
@ kUseLedCurtin
Definition settings.h:15
@ kNumLightsPerNote
Definition settings.h:6
@ kNumKeys
Definition settings.h:5
uint8_t b_
Definition color.h:56
uint8_t g_
Definition color.h:56
uint8_t r_
Definition color.h:56
static Color3i Black()
Definition color.h:7
Definition color.h:6
float v_
Definition color.h:108
Color3i ToRGB() const
Definition color.cpp:129
float s_
Definition color.h:108
uint8_t mVelocity
Definition Keyboard.h:39
bool mOn
Definition Keyboard.h:36
ColorHSV mOrigColor
Definition Keyboard.h:47
float IntensityFactor() const
Definition Keyboard.cpp:66
unsigned long mEventTime
Definition Keyboard.h:41
int mIdx
Definition Keyboard.h:40
ColorHSV mCurrColor
Definition Keyboard.h:48
Definition Keyboard.h:22
const int * array
static void PaintBrightSurprise(const KeyboardState &keyboard, const int *led_column_table, int led_column_table_length, LedRopeInterface *led_rope)
Definition Painter.cpp:409
@ kVUMidNote
Definition Painter.h:13
@ kVUSpaceInvaders
Definition Painter.h:17
@ kVegas
Definition Painter.h:18
@ kBlockNote
Definition Painter.h:15
@ kBrightSurprise
Definition Painter.h:19
@ kVUNote
Definition Painter.h:16
@ kColumnNote
Definition Painter.h:14
static void PaintVuNotes(uint32_t now_ms, const KeyboardState &keyboard, const int *led_column_table, int led_column_table_length, LedRopeInterface *led_rope)
Definition Painter.cpp:165
static void PaintVuSpaceInvaders(uint32_t now_ms, const KeyboardState &keyboard, const int *led_column_table, int led_column_table_length, LedRopeInterface *led_rope)
Definition Painter.cpp:450
static void Paint(uint32_t now_ms, uint32_t delta_ms, VisState vis_state, KeyboardState *keyboard, LedRopeInterface *light_rope)
Definition Painter.cpp:99
static void PaintVuMidNotesFade(uint32_t delta_ms, const KeyboardState &keyboard, const int *led_column_table, int led_column_table_length, LedRopeInterface *led_rope)
Definition Painter.cpp:233
static void VegasVisualizer(const KeyboardState &keyboard, const int *led_column_table, int led_column_table_length, LedRopeInterface *led_rope)
Definition Painter.cpp:361
float mapf(float x, float in_min, float in_max, float out_min, float out_max)
Definition util.cpp:18
float CalcDecayFactor(bool sustain_pedal_on, bool key_on, int key_idx, float velocity, bool dampened_key, float time_elapsed_ms)
Definition util.cpp:71