6#include "./led_layout_array.h"
9#include "fl/math_macros.h"
14float LuminanceDecay(
float time) {
16 static const Datum kData[] = {
28 const float key = time * 255.f;
29 static const int n =
sizeof(kData) /
sizeof(kData[0]);
30 float approx_val = Interp(key, kData, n);
33 static const float k = (1.0f / 255.f);
34 const float out = approx_val * k;
38float CalcLuminance(
float time_delta_ms,
39 bool sustain_pedal_on,
43 if (key.curr_color_.v_ <= 0.0) {
47 const bool dampened_key = (key_idx < kFirstNoteNoDamp);
49 const float decay_factor = CalcDecayFactor(sustain_pedal_on,
52 key.velocity_ * (1.f/127.f),
58 float brigthness_factor = 0.0f;
61 brigthness_factor = sqrt(sqrt(key.orig_color_.v_));
64 brigthness_factor = key.orig_color_.v_;
66 return LuminanceDecay(decay_factor) * brigthness_factor;
69 return decay_factor * key.orig_color_.v_;
73float CalcSaturation(
float time_delta_ms,
const ColorHSV& color,
bool key_on) {
74 if (color.v_ <= 0.0) {
80 static const float kDefaultSaturationTime = 0.05f * 1000.f;
83 float saturation_factor = mapf(time_delta_ms,
84 0.0f, kDefaultSaturationTime,
88 saturation_factor = MIN(1.0f, saturation_factor);
91 return saturation_factor;
97void Painter::Paint(uint32_t now_ms,
102 for (
int i = 0; i < KeyboardState::kNumKeys; ++i) {
103 Key& key = keyboard->keys_[i];
105 const float time_delta_ms =
static_cast<float>(now_ms - key.event_time_);
107 const float lum = CalcLuminance(time_delta_ms, keyboard->sustain_pedal_, key, i);
108 const float sat = CalcSaturation(time_delta_ms, key.curr_color_, key.on_);
114 key.curr_color_.v_ = lum;
115 key.curr_color_.s_ = sat;
119 light_rope->Set(i, key.curr_color_.ToRGB());
125 case Painter::kBlockNote: {
126 light_rope->DrawSequentialRepeat(kNumLightsPerNote);
129 case Painter::kColumnNote: {
130 light_rope->DrawRepeat(led_columns.array, kNumKeys);
133 case Painter::kVUNote: {
134 PaintVuNotes(now_ms, *keyboard, led_columns.array, kNumKeys, light_rope);
137 case Painter::kVUMidNote: {
138 PaintVuMidNotesFade(delta_ms, *keyboard, led_columns.array, kNumKeys, light_rope);
142 case Painter::kVegas: {
143 VegasVisualizer(*keyboard, led_columns.array, kNumKeys, light_rope);
147 case Painter::kBrightSurprise: {
148 PaintBrightSurprise(*keyboard, led_columns.array, kNumKeys, light_rope);
152 case Painter::kVUSpaceInvaders: {
153 PaintVuSpaceInvaders(now_ms, *keyboard, led_columns.array, kNumKeys, light_rope);
158 dprint(
"Unknown mode: "); dprint(vis_state); dprint(
".\n");
163void Painter::PaintVuNotes(uint32_t ,
165 const int* led_column_table,
int led_column_table_length,
168 led_rope->RawBeginDraw();
170 for (
int i = 0; i < led_column_table_length; ++i) {
171 const Key& key = keyboard.keys_[i];
175 bool black_key =
false;
176 switch (key.idx_ % 12) {
186 const int pixel_count = led_column_table[i];
187 const int draw_pixel_count = ceil(pixel_count * sqrt(key.curr_color_.v_));
189 const int black_pixel_count = pixel_count - draw_pixel_count;
190 const Color3i& c = *led_rope->GetIterator(i);
193 const bool reverse_correct = black_key == (key.idx_ % 2);
195 if (reverse_correct) {
196 for (
int j = 0; j < draw_pixel_count; ++j) {
197 if (j < draw_pixel_count - 1) {
198 led_rope->RawDrawPixel(c);
201 ColorHSV hsv(random(512) / 512.f, random(512) / 512.f, 1.0);
202 led_rope->RawDrawPixel(hsv.ToRGB());
206 for (
int j = 0; j < black_pixel_count; ++j) {
207 led_rope->RawDrawPixel(Color3i::Black());
210 for (
int j = 0; j < black_pixel_count; ++j) {
211 led_rope->RawDrawPixel(Color3i::Black());
214 for (
int j = draw_pixel_count - 1; j >= 0; --j) {
215 if (j < draw_pixel_count - 1) {
216 led_rope->RawDrawPixel(c);
219 ColorHSV hsv(random(512) / 512.f, random(512) / 512.f, 1.0);
220 led_rope->RawDrawPixel(hsv.ToRGB());
225 led_rope->RawCommitDraw();
228void Painter::PaintVuMidNotesFade(uint32_t ,
230 const int* led_column_table,
int led_column_table_length,
240 float SumBrightness()
const {
243 out += (fade_factor * n_fade0);
244 out += (fade_factor * n_fade1);
253 static DrawPoints Generate(
int n_led,
float factor) {
255 memset(&out, 0,
sizeof(out));
256 if (n_led == 0 || factor == 0.0f) {
257 out.n_black0 = n_led;
260 const int is_odd = (n_led % 2);
261 const int n_half_lights = n_led / 2 + is_odd;
262 const float f_half_fill = n_half_lights * factor;
263 const int n_half_fill =
static_cast<int>(f_half_fill);
265 float fade_pix_perc = f_half_fill -
static_cast<float>(n_half_fill);
266 int n_fade_pix = fade_pix_perc < 1.0f;
267 if (n_half_fill == 0) {
270 int n_half_black = n_half_lights - n_half_fill - n_fade_pix;
273 if (n_half_fill > 0) {
274 n_fill_pix = n_half_fill * 2 + (is_odd ? -1 : 0);
277 out.n_black0 = n_half_black;
278 out.n_fade0 = n_fade_pix;
279 out.n_fill = n_fill_pix;
280 out.n_fade1 = n_fade_pix;
281 if (!n_fill_pix && is_odd) {
284 out.n_black1 = n_half_black;
285 out.fade_factor = fade_pix_perc;
291 led_rope->RawBeginDraw();
293 for (
int i = 0; i < led_column_table_length; ++i) {
294 const Key& key = keyboard.keys_[i];
296 float active_lights_factor = key.IntensityFactor();
302 const int n_led = led_column_table[i];
304 if (active_lights_factor > 0.0f) {
305 DrawPoints dp = F::Generate(n_led, active_lights_factor);
313 c.v_ = dp.fade_factor;
314 fade_col = c.ToRGB();
317 led_rope->RawDrawPixels(Color3i::Black(), dp.n_black0);
318 led_rope->RawDrawPixels(fade_col, dp.n_fade0);
319 led_rope->RawDrawPixels(color, dp.n_fill);
320 led_rope->RawDrawPixels(fade_col, dp.n_fade1);
321 led_rope->RawDrawPixels(Color3i::Black(), dp.n_black1);
324 if (active_lights_factor > 0.0) {
325 int total_lights_on = dp.SumBrightness();
330 #define P(X) dprint(", "#X ": "); dprint(X);
336 P(active_lights_factor);
342 led_rope->RawDrawPixels(Color3i::Black(), n_led);
350 led_rope->RawCommitDraw();
354 const int* led_column_table,
int led_column_table_length,
357 led_rope->RawBeginDraw();
359 uint32_t skipped_lights = 0;
360 for (
int i = 0; i < led_column_table_length; ++i) {
361 const Key& key = keyboard.keys_[i];
362 uint32_t painted_lights = 0;
365 const float active_lights_factor = led_column_table[i] * sqrt(key.curr_color_.v_);
366 const float inactive_lights_factor = 1.0f - active_lights_factor;
367 const float taper_point_1 = inactive_lights_factor / 2.0f;
368 const float taper_point_2 = taper_point_1 + active_lights_factor;
370 const int taper_idx_1 =
static_cast<int>(floor(taper_point_1 * led_column_table[i]));
371 const int taper_idx_2 =
static_cast<int>(floor(taper_point_2 * led_column_table[i]));
373 const Color3i c = key.curr_color_.ToRGB();
375 for (
int i = 0; i < taper_idx_1 / 2; ++i) {
376 led_rope->RawDrawPixel(Color3i::Black());
380 int length = taper_idx_2 - taper_idx_1;
381 for (
int i = 0; i < min(200, length); ++i) {
382 led_rope->RawDrawPixel(c);
386 length = led_column_table[i] - taper_idx_2;
387 for (
int i = 0; i < length; ++i) {
388 led_rope->RawDrawPixel(Color3i::Black());
391 skipped_lights += MAX(0,
static_cast<int32_t
>(led_column_table[i]) -
static_cast<int32_t
>(painted_lights));
394 for (uint32_t i = 0; i < skipped_lights; ++i) {
395 led_rope->RawDrawPixel(Color3i::Black());
398 led_rope->RawCommitDraw();
401void Painter::PaintBrightSurprise(
403 const int* led_column_table,
int led_column_table_length,
406 led_rope->RawBeginDraw();
407 int total_counted = 0;
412 for (
int i = 0; i < KeyboardState::kNumKeys; ++i) {
413 const Key& key = keyboard.keys_[i];
416 if (key.curr_color_.v_ > 0.0f) {
417 const Color3i rgb = key.curr_color_.ToRGB();
425 float denom = total_counted ? total_counted : 1;
433 for (
int i = 0; i < led_column_table_length; ++i) {
434 const int n = led_column_table[i];
435 for (
int i = 0; i < n; ++i) {
436 led_rope->RawDrawPixel(rgb);
439 led_rope->RawCommitDraw();
442void Painter::PaintVuSpaceInvaders(uint32_t ,
444 const int* led_column_table,
int led_column_table_length,
446 led_rope->RawBeginDraw();
448 Color3i black = Color3i::Black();
450 for (
int i = 0; i < led_column_table_length; ++i) {
451 const Key& key = keyboard.keys_[i];
453 const int pixel_count = led_column_table[i];
454 const int draw_pixel_count = ceil(pixel_count * sqrt(key.curr_color_.v_));
456 const int black_pixel_count = pixel_count - draw_pixel_count;
460 for (
int j = 0; j < black_pixel_count; ++j) {
461 led_rope->RawDrawPixel(*led_rope->GetIterator(i));
463 for (
int j = 0; j < draw_pixel_count; ++j) {
464 led_rope->RawDrawPixel(black);
468 for (
int j = 0; j < draw_pixel_count; ++j) {
469 led_rope->RawDrawPixel(black);
472 for (
int j = 0; j < black_pixel_count; ++j) {
473 led_rope->RawDrawPixel(*led_rope->GetIterator(i));
477 led_rope->RawCommitDraw();
#define P(x)
Reads a single byte from the p array.