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