Inspired by the recent work of Stefan Petrick ,

Inspired by the recent work of @Stefan_Petrick , I present to the community a 12-bit ColorFromPalette function, which is almost entirely a copy of the original ColorFromPalette function.

The only difference is in the precision of the index- it is expecting a 12-bit number instead of an 8-bit number, range 0-4095.

Performance should be roughly the same as the original.

Note that I left the brightness logic as-is… if somebody else wants to take a stab at that, please feel free.

I tested this on a well-wrapped palette with these colors- CRGB(1, 1, 1), CRGB(13, 13, 255), CRGB(1, 1, 1), CRGB(255, 127, 1), and if I do say so myself, the results look fantastic.

Awesome work, @Jeff_Hannan ! Would you possibly mind showing a short example how to use it - maybe a Gist on Github?

leds[i] = ColorFromPalette12(pal, 12bit_index, brightness, blendType);

As simple as that?!

I actually wrote it to use your most recent smooth noise.

It only required a few changes.

First, the control parameters-

//ctrl[0][0] = (ctrl[0][0] + noise[0][0][0] + noise[0][1][0] + noise [0][0][1] + noise[0][1][1]) / 20;
ctrl[0][0] = noise[0][0][0] >> 4;
//…etc

Then the data scaling (we want 0-4095)…

//data = data / 41;
data = data / 10;

And finally, the mapping-
//leds[XY(x, y)] = CRGB(a[noise[0][x][y]], 0, 0);
leds[XY(x, y)] = ColorFromPalette12(myPal, noise[0][x][y], 255, LINEARBLEND);

I’ll try to wrap it all up into a tidy example and post the whole thing.

Oh nice @Jeff_Hannan . I look forward to getting to try this out.

Btw, unless it’s just a few lines of code, can you share code on http://gist.github.com ? It makes it much easier to read, especially on mobile devices, and also easier to discuss since there are line numbers that can be referenced.

Amazing! Can´t wait to try this. Today I also got a big gift from the PJRC forum - have a perfectly smooth noise_float32 function now. Only 85 fps on T3.2, but 896 fps (sic) on T3.6… Will put it all together tomorrow.

Per Marc’s request, this is just the function with a little bit of usage instructions. The comments that start with //* are mine, and these are the only changes from the original function.

The real “magic” is in line 32. Going from 4-bit precision to 8-bit precision here, for values being passed into 8-bit precision functions, made all the difference.

Thank you @Jeff_Hannan

It’s worth noting that 12-bits of precision was a very convenient choice, based on how the original ColorFromPalette function works.

In the original, the “high” four bits control which two entries on the palette are being used, and the “low” four bits control the blending between those two palette entries.

In this modified 12-bit version, the “high” four bits control which two entries on the palette are being used, and the “low” EIGHT bits control the blending between those two palette entries.

Controlling the blending with 8 bits instead of 4 bits, it’s like a whole new world.

Nice code, and thank you, @Jeff_Hannan ! Would you be interested in contributing this code to the library?

Tested it, it improves the edge quality a lot. Thank you, @Jeff_Hannan . Impossible to record on video. Here some example code comparing 12-bit and 8-bit ColorFromPalette side by side and using a float32 noise implementation. https://gist.github.com/StefanPetrick/d3e309dd2c839279c5746913594c22a6

It’s all yours, @Mark_Kriegsman ! Thank you for the library- without it, we wouldn’t be here.

I wasn’t 100% sure about two things…

1- the name of the function… I tried to find a convention that made sense, but if you already have something in mind or if I missed something elsewhere, then please do use a better name.

2- the input range. 0-4095 is the expected range, and the code is tuned for this. If you pass in extra bits on the high end, they just get dropped. This has the effect of wrapping the function four times through the 16-bit space (pass in 4097, it is treated as a 2). I have found this to be confusing when putting it to use in my code, but it is precise. It might be better if the function expects a “full” 16-bit number (0-65535), and then drops the “low” 4-bits to do the calculation. As such, two functions might be the answer here, one expecting a 12-bit index, and one expecting a full 16-bit index.

It looks like I wasn’t the first person to have this idea, per this pull request-

This is exactly what I described in the above “alternate” that expects a full 16-bit index.

“pass in 4097, it is treated as a 2”
I find this practical because it allows an easy rotation of the palette like
ColorFromPalette12(pal, i + (millis() / 10), …