//this sketch for simply record any fastled animation
//to rgb animation format for a4Tech Bloody B810R keyboard KeyDominator
//Yaroslaw Turbin 20-04-2022
//https://twitter.com/ldir_ko
//https://www.reddit.com/user/ldirko/
//https://vk.com/ldirko
//https://www.youtube.com/c/ldirldir/
#include "FastLED.h"
// Matrix size
#define NUM_ROWS_PLANAR 6 //virtual buffer ROWS size
#define NUM_COLS_PLANAR 29 //virtual buffer COLS size
#define NUM_LEDS (NUM_ROWS_PLANAR*NUM_COLS_PLANAR) // 174 //for tests
#define NUM_LEDS_KEYB 104
#define SAFE_INDEX NUM_LEDS_KEYB
// LEDs pin
#define DATA_PIN 3
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
// LED brightness
#define BRIGHTNESS 255
#define MAX_POWER_MILLIAMPS 700
// Define the array of leds
CRGB leds[NUM_LEDS+1];
CRGB keybLeds [NUM_LEDS_KEYB+1];
void setup() {
Serial.begin(115200);
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
// FastLED.setMaxPowerInVoltsAndMilliamps(5, MAX_POWER_MILLIAMPS);
FastLED.setBrightness(BRIGHTNESS);
}
void StartText(int frames) { //header of animation file
Serial.print("<?xml version=");
Serial.print((char)34);
Serial.print("1.0");
Serial.print((char)34);
Serial.print(" encoding=");
Serial.print((char)34);
Serial.print("Unicode");
Serial.print((char)34);
Serial.println("?>");
Serial.println("<Root>");
Serial.println("<Description>ckAnimation:RGB Plasma by ldirko. wwww.twitter.com/ldir_ko www.youtube.com/c/ldirldir/ </Description>");
Serial.println("<Time>0</Time>");
Serial.println("<BackgroundColor>000000</BackgroundColor>");
Serial.print("<FrameCount>");
Serial.print(frames);
Serial.println("</FrameCount>");
Serial.println("");
}
void OneFrame (int FrameNumber, float DisplayTime ){ //parce one frame of leds values to serial output
Serial.print("<Frame");
Serial.print(FrameNumber, DEC);
Serial.println(">");
Serial.println("<ColorPicture>");
for (int i = 0; i < NUM_LEDS_KEYB; i++) {
byte r = keybLeds[i].b; // swap r and b for keyboard format
byte g = keybLeds[i].g;
byte b = keybLeds[i].r;
if (r<16) Serial.print("0"); // add 0 before next digit if number <16 for full 2 HEX digit output
Serial.print(r,HEX);
if (g<16) Serial.print("0"); // add 0 before next digit if number <16 for full 2 HEX digit output
Serial.print(g,HEX);
if (b<16) Serial.print("0"); // add 0 before next digit if number <16 for full 2 HEX digit output
Serial.print(b,HEX);
if (i!=(NUM_LEDS-1)) Serial.print(", "); //do not print comma after last led in frame
}
Serial.println("");
Serial.print("</ColorPicture>");
Serial.println("");
Serial.print("<DisplayTime>");
Serial.print(DisplayTime, 2);
Serial.print("</DisplayTime>");
Serial.println("");
Serial.print("</Frame");
Serial.print(FrameNumber);
Serial.print(">");
Serial.println("");
Serial.println("");
}
void FinalText() { //add </Root> in final
Serial.println("</Root>");
}
byte PlanarTable[] = { // keyboard lookup map table. i made it by hand )))
0, 104, 104, 1, 2, 3, 104, 4, 104, 5, 6, 7, 104, 8, 104, 9, 10, 104, 11, 12, 104, 104, 104, 104, 104, 104, 13, 14, 15,
16, 17, 104, 18, 19, 20, 104, 21, 22, 23, 104, 24, 25, 104, 26, 27, 28, 104, 29, 104, 104, 30, 31, 32, 104, 33, 34, 35, 36,
37, 104, 38, 39, 104, 40, 41, 42, 104, 43, 44, 45, 104, 46, 47, 104, 48, 49, 104, 50, 104, 51, 52, 53, 104, 54, 55, 56, 57,
58, 104, 59, 104, 60, 61, 62, 104, 63, 64, 65, 104, 66, 67, 104, 68, 69, 104, 70, 104, 104, 104, 104, 104, 104, 71, 72, 73, 104,
104, 74, 104, 75, 76, 104, 77, 78, 79, 104, 80, 81, 82, 104, 83, 84, 104, 104, 85, 104, 104, 104, 86, 104, 104, 87, 88, 89, 90,
91, 104, 92, 93, 104, 104, 104, 104, 104, 94, 104, 104, 104, 104, 95, 96, 104, 97, 104, 98, 104, 99, 100, 101, 104, 102, 104, 103, 104
};
const uint8_t exp_gamma [256] PROGMEM = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 7, 7,
7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12,
12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 26, 27, 28,
28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 38, 39,
39, 40, 41, 42, 43, 44, 44, 45, 46, 47, 48, 49, 50, 51, 52,
53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80, 82, 83, 84, 85,
87, 89, 91, 92, 93, 95, 96, 98, 99, 100, 101, 102, 105, 106, 108,
109, 111, 112, 114, 115, 117, 118, 120, 121, 123, 125, 126, 128, 130, 131,
133, 135, 136, 138, 140, 142, 143, 145, 147, 149, 151, 152, 154, 156, 158,
160, 162, 164, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187,
190, 192, 194, 196, 198, 200, 202, 204, 207, 209, 211, 213, 216, 218, 220,
222, 225, 227, 229, 232, 234, 236, 239, 241, 244, 246, 249, 251, 253, 254, 255
};
void GammaCorrection(){ //gamma correction function
byte r,g,b;
for (uint16_t i=0; i<NUM_LEDS; i++){
r=leds[i].r;
g=leds[i].g;
b=leds[i].b;
leds[i].r = pgm_read_byte(exp_gamma + r);
leds[i].g = pgm_read_byte(exp_gamma + g);
leds[i].b = pgm_read_byte(exp_gamma + b);
}
}
void GammaCorrection_keyb(){ //gamma correction function
byte r,g,b;
for (uint16_t i=0; i<NUM_LEDS_KEYB; i++){
r=keybLeds[i].r;
g=keybLeds[i].g;
b=keybLeds[i].b;
keybLeds[i].r = pgm_read_byte(exp_gamma + r);
keybLeds[i].g = pgm_read_byte(exp_gamma + g);
keybLeds[i].b = pgm_read_byte(exp_gamma + b);
}
}
byte XY_PLANAR (byte x, byte y) { //calculate XY keyboard index
return (PlanarTable[y*NUM_COLS_PLANAR+x]);
}
int XY(byte x, byte y) {
return (y*NUM_COLS_PLANAR+x);
}
uint16_t globalframe = 0;
CRGB CalcPlasma (byte x, byte y, int a){
CRGB color;
color.b=sin8((x-8)*cos8((y+20)*8)/4+a);
color.g=(sin8(x*24+a/3)+cos8(y*16+a/2))/2;
color.r=sin8(cos8(x*16+a/3)+sin8(y*16+a/4)+a);
return (color);
}
void LedsRoutine (){ //calculate something here
int a = globalframe;
for (int x = 0; x < NUM_COLS_PLANAR; x++) {
for (int y = 0; y < NUM_ROWS_PLANAR; y++) {
int index = XY(x, y);
leds[index] = CalcPlasma(x,y,a);
int keybIndex = XY_PLANAR(x, y);
keybLeds[keybIndex]=leds[index];
}
}
GammaCorrection();
GammaCorrection_keyb();
globalframe+=10; //speed of effect
FastLED.show();
}
void LedsRoutineBack (){ //calculate something here
int a = globalframe;
for (int x = 0; x < NUM_COLS_PLANAR; x++) {
for (int y = 0; y < NUM_ROWS_PLANAR; y++) {
int index = XY(x, y);
leds[index] = CalcPlasma(x,y,a);
int keybIndex = XY_PLANAR(x, y);
keybLeds[keybIndex]=leds[index];
}
}
GammaCorrection();
GammaCorrection_keyb();
globalframe-=10; //speed of effect
FastLED.show();
}
void loop() {
static byte init = 1; //no need to change this
static int frame = 1; //no need to change this
int HowManyFrames = 80; // how many frames in animation. 80 frames is max in Keydominator!
if (init) {StartText(HowManyFrames), init=0;} //add header. run once
while (HowManyFrames>40){
LedsRoutine (); //calc one animation frame
OneFrame(frame, 0.1); //parse one animation frame. Minimal delay between frames in KeyDominator is 0.05
frame++;
HowManyFrames--;
}
while (HowManyFrames>0){ //ping-pong animation for loop anumation
LedsRoutineBack (); //calc one animation frame
OneFrame(frame, 0.1); //parse one animation frame. 0.1 - is minimal delay between frames in KeyDominator
frame++;
HowManyFrames--;
}
FinalText(); //add final text. run once
for(;;); // stop here
}