Old 11-14-2014, 07:04 PM   #1
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default Randomize color hue (EEL/PY)

Is it possible to generate random color for track/item with fixed value of lightness and saturation? In other words randomize only hue?

Thanks
Viente is offline   Reply With Quote
Old 11-14-2014, 08:28 PM   #2
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

hellzyea, it's all about tha maths.

Code:
function RGB(r,g,b) (
   r + 256 * g + 65536 * b;
);
to use, for example:

SetMediaTrackInfo_Value(track, "I_CUSTOMCOLOR", RGB(255,0,0)|0x100000))


all you need to do is convert back and forth from RGB and HSL. google search for formulas.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
Argitoth is offline   Reply With Quote
Old 11-14-2014, 08:29 PM   #3
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

Thank you! I'll try to figure out. Though i was banned from university because of math back in a days lol
Viente is offline   Reply With Quote
Old 11-14-2014, 08:32 PM   #4
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

If its not that hard and time consuming could you pleeeeease help
Viente is offline   Reply With Quote
Old 11-14-2014, 09:41 PM   #5
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

hopefully someone smarter than me will respond, this is beyond my ability to do in a timely manner.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
Argitoth is offline   Reply With Quote
Old 11-15-2014, 02:28 AM   #6
witti
Human being with feelings
 
witti's Avatar
 
Join Date: May 2012
Posts: 1,216
Default

Here are two js scripts i already created. The second one is unfinished, but may be useful (i'm not certain about the fader ranges here...).

Code:
slider1:0<0,360,1>H
slider2:1<0,1,0.01>S
slider3:1<0,1,0.01>V
slider4:0<0,1,1{HSV to RGB,RGB to HSV}>mode
slider5:0<0,255,1>R
slider6:0<0,255,1>G
slider7:0<0,255,1>B

in_pin:none
out_pin:none

@slider
h=slider1;
s=slider2;
v=slider3;

@block
slider4 == 0 ? (
c = v * s;
hdash=h/60;
x = c * (1 - abs((hdash % 2) - 1));
m = v - c;

(hdash < 1.0)?(
r=c+m;
g=x+m;
b=m;
):
(hdash < 2.0)?(
r=x+m;
g=c+m;
b=m;
):
(hdash < 3.0)?(
r=m;
g=c+m;
b=x+m;
):
(hdash < 4.0)?(
r=m;
g=x+m;
b=c+m;
):
(hdash < 5.0)?(
r=x+m;
g=m;
b=c+m;
):
(hdash < 6.0)?(
r=c+m;
g=m;
b=x+m;
):(
r=m;
g=m;
b=m;
);

slider5=floor(r*255);
sliderchange(5);
slider6=floor(g*255);
sliderchange(6);
slider7=floor(b*255);
sliderchange(7);
);

slider4 == 1 ? (
r=slider5/255;
g=slider6/255;
b=slider7/255;

minRGB = min(r, min(g,b));
maxRGB = max(r, max(g,b));

(minRGB == maxRGB) ? (
VA = minRGB;
);

d = (r==minRGB) ? g-b : ((b==minRGB) ? r-g : b-r);
h = (r==minRGB) ? 3 : ((b==minRGB) ? 1 : 5);
HA = 60*(h - d/(maxRGB - minRGB));
SA = (maxRGB - minRGB)/maxRGB;
VA = maxRGB;

slider1=floor(HA);
sliderchange(1);
slider2=floor(SA);
sliderchange(2);
slider3=floor(VA);
sliderchange(3);
);

@gfx
gfx_a = 1;
gfx_r=r;gfx_g=g;gfx_b=b;
gfx_x=0;gfx_y=0;
gfx_rectto(gfx_w,gfx_h);
Code:
slider1:201<0,201,1>Hue
slider2:100<0,100,1>Saturation
slider3:100<0,100,1>Lightness
slider5:0<0,255,1>R
slider6:0<0,255,1>G
slider7:0<0,255,1>B

in_pin:none
out_pin:none

@slider

hue = slider1 / 100;
saturation = slider2 / 100;
lightness = slider3 / 100;

@block

q = lightness < 0.5 ? lightness * ( 1 + saturation) : saturation - lightness * saturation;
p = 2 * lightness - q;

// calculate R value
t = hue + 1/3;
t < 0 ? t = t + 1;
t > 1 ? t = t - 1;

t < 1/6 ? r = p + (q - p) * 6 * t :
t < 1/2 ? r = q :
t < 2/3 ? r = p + (q - p) * (2/3 - t) * 6 :
r = p;

r = r / 2;

// calculate G value
t = hue;
t < 0 ? t = t + 1;
t > 1 ? t = t - 1;

t < 1/6 ? g = p + (q - p) * 6 * t :
t < 1/2 ? g = q :
t < 2/3 ? g = p + (q - p) * (2/3 - t) * 6 :
g = p;

g = g / 2;

// calculate B value
t = hue - 1/3;
t < 0 ? t = t + 1;
t > 1 ? t = t - 1;

t < 1/6 ? b = p + (q - p) * 6 * t :
t < 1/2 ? b = q :
t < 2/3 ? b = p + (q - p) * (2/3 - t) * 6 :
b = p;

b = b / 2;

red=255*r;
slider5=floor(red);
sliderchange(slider5);
green=255*g;
slider6=floor(green);
sliderchange(slider6);
blue=255*b;
slider7=floor(blue);
sliderchange(slider7);

@gfx 0 100
gfx_a=1;

gfx_r = r;
gfx_g = g;
gfx_b = b;

gfx_x = 0;
gfx_y = 0;
gfx_rectto(gfx_w, gfx_h);
witti is offline   Reply With Quote
Old 11-15-2014, 03:21 AM   #7
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Following this with interest .

I've got it working, but in a very crude way, using python's colorsys library (does the rgb<->HSL) plus a bunch of python functions I found somewhere in the net to convert Reaper's color number into something colorsys could understand and afterwards colorsys' return back into Reaper's number (I guess half of that part could be more or less replaced with what Argitoth posted). I don't even quite get myself what's going on there and it looks real ugly, so I am very reluctant to present "my method" as a valid solution (wouldn't work in eel anyway) here.

I always wanted to replace my HSL scripts with nicer ones, preferable eel, so this will come in handy, should I manage to take in the provided snippets. Thanks all



Question revealing my skillset:
If I understand correctly, Argitoth provided a snippet to convert an rgb tuple to the number Reaper understands. How would it look like to convert in the other direction?

Last edited by gofer; 11-15-2014 at 03:34 AM.
gofer is offline   Reply With Quote
Old 11-15-2014, 05:55 AM   #8
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

I've found this...but omg...its beyond my level of understanding.

Viente is offline   Reply With Quote
Old 11-15-2014, 06:04 AM   #9
Banned
Human being with feelings
 
Banned's Avatar
 
Join Date: Mar 2008
Location: Unwired (probably in the proximity of Amsterdam)
Posts: 4,868
Default

Some related stuff here; the HSL stuff I posted seems very similar to witti's code example.
__________________
˙lɐd 'ʎɐʍ ƃuoɹʍ ǝɥʇ ǝɔıʌǝp ʇɐɥʇ ƃuıploɥ ǝɹ,noʎ
Banned is offline   Reply With Quote
Old 11-15-2014, 07:51 AM   #10
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

I just found this page which seems to describe the HSL<->RGB conversion math (including the reasoning) in a way I believe I am pretty close to understand - and I do find parallels to what banned did, which raises hopes that I might get it at some point
http://www.niwa.nu/2013/05/math-behi...sions-rgb-hsl/

digging further in
gofer is offline   Reply With Quote
Old 11-15-2014, 09:57 AM   #11
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

int to rgb

Code:
function int2rgb(int) (
  b = int & 255;
  g = (int >> 8) & 255;
  r = (int >> 16) & 255;
  msg(sprintf(#,"%i,%i,%i\n",b,g,r));
);

int2rgb(RGB(255,0,0));
int2rgb(0x0000FF);
int2rgb(255);

function red  (i) (r = (i >> 16) & 255);
function green(i) (g = (i >> 8) & 255);
function blue (i) (i & 255 );
output
Code:
255,0,0
255,0,0
255,0,0
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-15-2014 at 10:44 AM.
Argitoth is offline   Reply With Quote
Old 11-15-2014, 12:10 PM   #12
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Thanks . That's getting me closer. Just a tiny issue:

I tried to combine your int2RGB with the RGB2int into a simple "get and set color of the first track" test script, like this:
Code:
int = GetTrackColor(GetSelectedTrack(0, 0));
b = int & 255;
g = (int >> 8) & 255;
r = (int >> 16) & 255;

//do some stuff

newint=r + 256 * g + 65536 * b;
SetTrackColor(GetSelectedTrack(0, 0), newint);
expecting the same color to be written back, so no change. But colors will toggle between two different ones instead.
It looks like here is the old Reaper BGR trap at work, and indeed if I do swap r and b in either one of the two conversions it works as expected.

But which one would be the right one to swap? Assumed that I want to take the r,g and b where it says "//do some stuff", convert them to HSL, do something and then convert back to rgb (and then to int, of course)???
gofer is offline   Reply With Quote
Old 11-15-2014, 12:27 PM   #13
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

REAPER is not switching anything around, you are!

compare:
Code:
b = int & 255;
with:
Code:
newint = r + 256
you got b and r switched around. should be this:
Code:
newint=b + 256 * g + 65536 * r;
Edit: Oh I see, well the RGB function is r+256.


My functions were made for RGB, so my functions lead you astray, should be this:
Code:
int = GetTrackColor(GetTrack(0, 0));
r = int & 255;
g = (int >> 8) & 255;
b = (int >> 16) & 255;

//do some stuff

newint=r + 256 * g + 65536 * b;
SetTrackColor(GetTrack(0, 1), newint);
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-15-2014 at 01:17 PM.
Argitoth is offline   Reply With Quote
Old 11-15-2014, 12:46 PM   #14
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Now I am even more confuzzled...

I compared your
Code:
b = int & 255;
g = (int >> 8) & 255;
r = (int >> 16) & 255;
with what my old python scripts were returning at that point and they were comform. I know my scripts work, so I deduced (until you edited your post) that I'll have to swap the other part:

Code:
function RGB(r,g,b) (
   r + 256 * g + 65536 * b;
);
into
Code:
function RGB(r,g,b) (
   b + 256 * g + 65536 * r;
);
Are you sure that it's got to be the int2rgb part?
gofer is offline   Reply With Quote
Old 11-15-2014, 01:22 PM   #15
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

I had "&0x100000" in my last code, forgot to remove that before posting.

the only thing I can't figure out is how to tell if the track is set to default color, because the track color becomes black if color is default (not set).

Edit: Figured it out. track color is 0 if is default. 0 turns track color to black. But if you get a "black" track color it is in the 16,000,000 range, so just turn 0 to -1, set color to -1 for default color. e.g color == 0 ? color = -1

Edit: But I think this is a design flaw. The default color should return the default color, not 0.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-15-2014 at 02:06 PM.
Argitoth is offline   Reply With Quote
Old 11-15-2014, 02:20 PM   #16
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

I don't remember the details, it's years ago that I wrote my color scripts, but the test for "has not custom color" is
Code:
if intColor < 16777216:
That is, if the color is below decimal 16777216 then no custom color is set. IOW, the bit in the 7th hexadecimal digit determins "has custom color". Custom color black is int == 16777216. In hexa that should be 1000000 (7th hexa bit is set all others are zero).
gofer is offline   Reply With Quote
Old 11-15-2014, 02:33 PM   #17
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

this works too:
Code:
//if not 0, do stuff, else don't
trackColor ? do stuff : dont do stuff

//if 0, return -1
!trackColor ? -1
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-15-2014 at 02:49 PM.
Argitoth is offline   Reply With Quote
Old 11-15-2014, 02:47 PM   #18
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

EDIT: scrap what I wrote here (and in post #14). I found my error (was swapping b and r in the console message as well, that's what I get when I mindlessly copy/paste)
The code in your post #13 does the correct conversions.

Now on to hsl to and fro *frowns*

Last edited by gofer; 11-15-2014 at 03:02 PM.
gofer is offline   Reply With Quote
Old 11-15-2014, 02:50 PM   #19
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

no thoughts on that, should be fine imo. as long as you can go from rgb back to rgb in the above example scripts, that's all that matters.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
Argitoth is offline   Reply With Quote
Old 11-15-2014, 03:19 PM   #20
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Edited my previous post. The method you posted in #13 is the right one.

Of course it does matter a lot that r is red and b is blue and not vice versa at the point where I hand them over to hsl conversion.
gofer is offline   Reply With Quote
Old 11-15-2014, 06:36 PM   #21
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

I am getting nicely from r,g,b to h,s,l now with this snippet:
Code:
// convert rgb to hsl:

// find min and max
G < R ? min = G : min = R;
B < min ? min = B;

G > R ? max = G : max = R;
B > max ? max = B;

// calculate luminance
l = (min + max)/2;

// calc saturation:
l < 0.5 ? s = (max - min) / (max + min) : s = (max - min) / (2.0 - max - min);

//calc hue:
max == R ? H = (G - B) / (max - min);
max == G ? H = 2.0 + (B - R) / (max - min);
max == B ? H = 4.0 + (R - G) / (max - min);

h = H * 60;
h < 0 ? h += 360;
But am having a hard time to go back to rgb as of now. Spent the last hour on that but get weird results. Going to take a nap, that should help
Thanks all, so far.

Last edited by gofer; 11-16-2014 at 03:05 AM.
gofer is offline   Reply With Quote
Old 11-15-2014, 07:03 PM   #22
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

Thank you all for your efforts. Im glad to join you with experimentations but i barely can i understand whats going on here
Viente is offline   Reply With Quote
Old 11-15-2014, 09:50 PM   #23
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

RGB to HSL (simplified code):
Code:
//get min/max
min = min(min(R,G),B);
max = max(max(R,G),B);

//calc hue:
H = (max == R ? (G - B) / (max - min):
  max == G ? 2 + (B - R) / (max - min):
  max == B ? 4 + (R - G) / (max - min))*60;
H < 0 ? H+=360;

// calculate luminance
L = (min + max)/2;

// calc saturation:
S = (max - min) / (L < 0.5 ? (max + min) : (2.0 - max - min));
translating this: http://www.niwa.nu/2013/05/math-behi...sions-rgb-hsl/
HSL to RGB (DOES NOT WORK 100%, blue formula below and/or hue formula in the above code is messed up! )
Code:
H == 0 && S == 0 ? (
  R=G=B=L;
) : (  
  L  < 0.5 ? temp1 = L * (1 + S):
  L >= 0.5 ? temp1 = L + S - L * S;
  temp2 = 2 * L - temp1;
  
  hue = H/360;
  tempR = hue + 1/3;
  tempG = hue;
  tempB = hue - 1/3;
  
  R = 
  6 * tempR < 1 ? temp2 + (temp1 - temp2) * 6 * tempR:
  2 * tempR < 1 ? temp1:
  3 * tempR < 2 ? temp2 + (temp1 - temp2) * (0.666 - tempR) * 6:
  temp2;
  
  G = 
  6 * tempG < 1 ? temp2 + (temp1 - temp2) * 6 * tempG:
  2 * tempG < 1 ? temp1:
  3 * tempG < 2 ? temp2 + (temp1 - temp2) * (0.666 - tempG) * 6:
  temp2;
  
  B = 
  6 * tempB < 1 ? temp2 + (temp1 - temp2) * 6 * tempB:
  2 * tempB < 1 ? temp1:
  3 * tempB < 2 ? temp2 + (temp1 - temp2) * (0.666 - tempB) * 6:
  temp2;

  //todo: multiply each R G B by 255
);
jesusonic fx to demonstrate:

See how the blue channel is messed up when RED is HIGH and GREEN is LOW and BLUE is between RED/GREEN? Basically, Magenta doesn't exist. Oh yeah, right square is RGB, left square is RGB to HSL back to RGB. (Both squares should be the same color. When they are not, it means something is wrong with the conversion.
Code:
slider1:0<0,1,.01>Red
slider2:0<0,1,.01>Green
slider3:0<0,1,.01>Blue

slider10:0<0,360,1>Hue
slider11:0<0,1,.01>Saturation
slider12:0<0,1,.01>Lightness

@init
function hue2rgb(a,b,c)(
  6 * a < 1 ? c + (b - c) * 6 * a:
  2 * a < 1 ? b:
  3 * a < 2 ? c + (b - c) * (0.666 - a) * 6:
  c;
);

@slider
R=slider1;
G=slider2;
B=slider3;

//calc RGB to HSL
//get min/max
min = min(min(R,G),B);
max = max(max(R,G),B);

//calc hue:
H = (max == R ? (G - B) / (max - min):
  max == G ? 2 + (B - R) / (max - min):
  max == B ? 4 + (R - G) / (max - min))*60;
H < 0 ? H+=360;

// calculate luminance
L = (min + max)/2;

// calc saturation:
S = (max - min) / (L < 0.5 ? (max + min) : (2.0 - max - min));

// calc HSL to RGB
slider10=H;
slider11=S;
slider12=L;

H == 0 && S == 0 ? (
  R2=G2=B2=L;
) : (  
  L  < 0.5 ? temp1 = L * (1 + S):
  L >= 0.5 ? temp1 = L + S - L * S;
  temp2 = 2 * L - temp1;
  
  hue = H/360;
  R2 = hue2rgb(hue + 1/3,temp1,temp2);
  G2 = hue2rgb(hue,temp1,temp2);
  B2 = hue2rgb(hue - 1/3,temp1,temp2);
);

@gfx 100 200
function set_color(r,g,b,a)
(
  gfx_r=r;gfx_g=g;gfx_b=b;gfx_a=a;
);
set_color(R,G,B,1);
gfx_rect(0,0,100,100);
set_color(R2,G2,B2,1);
gfx_rect(120,0,100,100);
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-16-2014 at 12:16 AM.
Argitoth is offline   Reply With Quote
Old 11-16-2014, 03:03 AM   #24
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Thanks Argitoth! I was hoping someone would go about simplifying.
Slapping my forehead about the "get min/max" part. I was trying quite a while to get a third argument into eels min(a,b), but didn't go for the obvious, as it seems .

Getting simplified versions of my code is a superb way to learn! Was (still is) the same when I do python, which I started here with ReaScript's birth. I've got no coding experience from further back at all (well, I did write a few lines in Kontakt, and a few very simple MIDI JS tools).
I'd post some code and someone else would go "Or just...:" and have a version usually half as long and double the clever than mine . I love that, and learn a lot from it.



Re messed up:
Although I did only a bunch of spot checks and compared with an online converter, I can savely say the RGB2HUE part did transfer all the colors I tried correctly so far, including the magenta case you describe. So I do suspect the HSL to RGB as the faulty part. But not too sure - let's see

EDIT: Here's a hint:
I loaded your JS into Reaper and looked at a few colors. For example when RGB reads 0.82/0.32/0.87. At that point the HSL sliders read 284.1176/1.0/0.66 in your JS.
Both - yours and my - original RGB2HSL code snippets give a different readout for HSL with these RGB values when used as .eel script (read via console message). It's (I round them here) 294.55/0.46/0.23. These are - according to the online converter - the correct values.
Why your JS code reads something different there, I don't know... the math is exactly the same, yet your sliders read a different output.
(BTW, the rgb color field doesn't seem to show the accurate color either - too bright)


EDIT#2:
Tried the HSL2RGB snippet - that has some glitch, too - but better than all trials I had yesterday... at least 2 of the values are accurate now, which is double of what I had (which ones are good depends on the input color) and sometimes all 3 of them, that's progress . Diving back in now



(BTW, the snippet I posted in #21 was somehow missing an "=" , as you will have noticed - wonder how that could have happened, it's there in my code. I'll smuggle it back in, as to not further confuse others who might follow this)

I think I'm going to jump into it again today, but later - this is morning coffee time hereabouts.

Last edited by gofer; 11-16-2014 at 04:38 AM.
gofer is offline   Reply With Quote
Old 11-16-2014, 03:13 AM   #25
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Hey Viente,
Porting my HSL color scripts to eel is something I want to do since quite a while now, thanks for the extra motivation.

Myself, I do somehow (not completely) get what the code does so far, but not so much why it needs to do it... but who cares as long as the numbers it spits out are useful
gofer is offline   Reply With Quote
Old 11-16-2014, 05:39 AM   #26
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

YAY!!! I think I've got it

Argitoth HSL2RGB snippet was just missing a test for tempR/tempG/tempB to make sure they are between 0 and 1.

This slightly edited version seems to do the trick (in EEL Reascript - still don't know what fails in the JS):
Code:
H == 0 && S == 0 ? (
  R=G=B=L;
) : (  
  L  < 0.5 ? temp1 = L * (1 + S):
  L >= 0.5 ? temp1 = L + S - L * S;
  temp2 = 2 * L - temp1;
  
  hue = H/360;
  tempR = hue + 1/3;
  tempG = hue;
  tempB = hue - 1/3;
  
  tempR < 0 ? tempR +=1;
  tempR > 1 ? tempR -=1;
  tempG < 0 ? tempG +=1;
  tempG > 1 ? tempG -=1;
  tempB < 0 ? tempB +=1;
  tempB > 1 ? tempB -=1;

  R = 
  6 * tempR < 1 ? temp2 + (temp1 - temp2) * 6 * tempR:
  2 * tempR < 1 ? temp1:
  3 * tempR < 2 ? temp2 + (temp1 - temp2) * (2/3 - tempR) * 6:
  temp2;
  
  G = 
  6 * tempG < 1 ? temp2 + (temp1 - temp2) * 6 * tempG:
  2 * tempG < 1 ? temp1:
  3 * tempG < 2 ? temp2 + (temp1 - temp2) * (2/3 - tempG) * 6:
  temp2;
  
  B = 
  6 * tempB < 1 ? temp2 + (temp1 - temp2) * 6 * tempB:
  2 * tempB < 1 ? temp1:
  3 * tempB < 2 ? temp2 + (temp1 - temp2) * (2/3 - tempB) * 6:
  temp2;

  //todo: multiply each R G B by 255
);
This is what I added, most likely you can do better than me:
Code:
  tempR < 0 ? tempR +=1;
  tempR > 1 ? tempR -=1;
  tempG < 0 ? tempG +=1;
  tempG > 1 ? tempG -=1;
  tempB < 0 ? tempB +=1;
  tempB > 1 ? tempB -=1;
(the tempG tests are redundant, I figure, it has to be in range, logically)

EDIT: also replaced a few 0.666 by proper 2/3, now the rounding errors are gone as well. This is now even more accurate than what python's colorsys library offers (well, IIRC, that is... for the sake of extra-happiness I'll just believe myself here)


coolcoolcoolcool!!!!

EDIT: Nope, not cool. Still not right when I actually hand newint back to the track. Still seems to be something off with int=>RGB and back.

This is 2 iterations of a script that should just rotate hue by 15degrees.
See how int of the second iteration = newint of the first (which is good) but the second iteration calculates a different RGB from that int? It should be the same as newRGB from the first, at least when rounded to integer.
Dang! this is killing me.
Attached Images
File Type: png int2hsl_AAAaargh.png (14.2 KB, 438 views)

Last edited by gofer; 11-16-2014 at 07:55 AM.
gofer is offline   Reply With Quote
Old 11-16-2014, 06:28 AM   #27
Banned
Human being with feelings
 
Banned's Avatar
 
Join Date: Mar 2008
Location: Unwired (probably in the proximity of Amsterdam)
Posts: 4,868
Default

@gofer: see how you're doing the exact same thing three times there, for r, g and b? For learning's sake, perhaps try factoring that stuff out to a second function.

Here's a little JS demonstration similar to Argitoth's, using the functions I linked to above - for accuracy's sake, I commented out my custom hue range adaptation (for 'easy complementary pairs').

Code:
slider1:0.0<0,1,.01>Hue
slider2:1.0<0,1,.01>Saturation
slider3:0.5<0,1,.01>Lightness

@init


// some color conversion functions, adapted from <http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion>
/**
 * NB: this adaptation *directly* sets gfx_r, gfx_g, and gfx_b!
 * NB: also adapted to make green = 0.5 on hue scale (instead of 0.25) for easier generation of complementary colors
 * 
 * Converts an HSL color value to RGB. Conversion formula adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1].
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  l       The lightness
 */

function hue2rgb(p, q, t)
(
    t < 0 ? t += 1;
    t > 1 ? t -= 1;
    t < 1/6 ? (
        p + (q - p) * 6 * t;
    ) : (
        t < 1/2 ? (
            q;
        ) : (
            t < 2/3 ? (
                p + (q - p) * (2/3 - t) * 6;
            ) : p;
        );
    );
);

function set_gfx_hsl(h,s,l) // local (r g b)
(
//  h <= 0.5 ? h /= 2
//           : h = 0.25 + ((h - 0.5) * 1.5); // adaptation to make green = 0.5 hue (instead of 0.25)
    
    s == 0 ? (
        r = g = b = l; // achromatic
    ) : 
    (
        q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    );
    gfx_r = r;
    gfx_g = g;
    gfx_b = b;
);


@slider
h=slider1;
s=slider2;
l=slider3;

@gfx 100 200
set_gfx_hsl(h,s,l);
gfx_rect(0,0,100,100);
__________________
˙lɐd 'ʎɐʍ ƃuoɹʍ ǝɥʇ ǝɔıʌǝp ʇɐɥʇ ƃuıploɥ ǝɹ,noʎ
Banned is offline   Reply With Quote
Old 11-16-2014, 08:03 AM   #28
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Yep, I am seeing that. Of course I tried your example yesterday (took me a while to understand). But it gave me false results (R,G and B always ended up the same value, correct for one of the colors). Because I am not sure what was going wrong (obviously my fault somewhere) I decided today to go with Argitoth' example for now - which after I added the missing range corrections is giving me proper readings.

At least I thought that... At the moment I am deeply depressed but it rather seems to be int<=>rgb conversion which is giving me the grieve (see my countless edits of the previous post.
gofer is offline   Reply With Quote
Old 11-16-2014, 08:07 AM   #29
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

i didn't even imagine its so much complicated...
Viente is offline   Reply With Quote
Old 11-16-2014, 09:06 AM   #30
Banned
Human being with feelings
 
Banned's Avatar
 
Join Date: Mar 2008
Location: Unwired (probably in the proximity of Amsterdam)
Posts: 4,868
Default

Quote:
Originally Posted by gofer View Post
[...] At the moment I am deeply depressed [...]
<gives gofer a hug and a fresh mug full of military grade espresso>
Quote:
Originally Posted by gofer View Post
[...] but it rather seems to be int<=>rgb conversion which is giving me the grieve (see my countless edits of the previous post.
Never used that integer format with REAPER myself, but I figured that was the easy part. :-/
Quote:
Originally Posted by Viente View Post
i didn't even imagine its so much complicated...
Oh man, just wait until coding geeks get into discussing the meaning of "random"...
let's hope they're willing to settle for pseudo-randomness, for your sake.
__________________
˙lɐd 'ʎɐʍ ƃuoɹʍ ǝɥʇ ǝɔıʌǝp ʇɐɥʇ ƃuıploɥ ǝɹ,noʎ
Banned is offline   Reply With Quote
Old 11-16-2014, 09:53 AM   #31
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Quote:
Originally Posted by Banned View Post
<gives gofer a hug and a fresh mug full of military grade espresso>
mmmhm, espresso
<fetches his jackhammer to drill a drop of milk into the substance>
gofer is offline   Reply With Quote
Old 11-16-2014, 10:00 AM   #32
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

JSFX


imo this works 100%, I just can't get rid of the useless 360 degree crap in the RGB to HSL conversion. Hue should be 0 to 1 because we are not using a color wheel.
(some stuff stolen from Banned)
EDIT:added slider RGB float to RGB int conversion
Code:
slider1:0.0<0,1,.01>Red
slider2:1.0<0,1,.01>Green
slider3:0.5<0,1,.01>Blue

slider5:0.0<16777216,33554431,1>RGB1

slider10:0.0<0,1,.01>Hue
slider11:1.0<0,1,.01>Saturation
slider12:0.5<0,1,.01>Lightness

slider20:0.0<16777216,33554431,1>RGB2

@init
function hue2rgb(p, q, t)
(
    t < 0 ? t += 1:
    t > 1 ? t -= 1;
    t < 1/6 ? p + (q - p) * 6 * t:
    t < 1/2 ? q:
    t < 2/3 ? p + (q - p) * (2/3 - t) * 6:
    p;
);

@slider
r=slider1;
g=slider2;
b=slider3;

/*RGB to HSL*/
min = min(min(R,G),B);
max = max(max(R,G),B);
deltaMax = max-min;

H = (max == R ? (G - B) / deltaMax:
  max == G ? 2 + (B - R) / deltaMax:
  max == B ? 4 + (R - G) / deltaMax);

//useless 360 degree crap
H = H*60;
H < 0 ? H+=360;
H/=360;

L = (min + max)/2;

S = deltaMax / (L < 0.5 ? (max + min) : 2 - max - min);

/*HSL to RGB*/
s == 0 ? (
    r2=g2=b2=l;
) : (
    q = l < 0.5 ? l * (1 + s) : l + s - l * s;
    p = 2 * l - q;
    r2 = hue2rgb(p, q, h + 1/3);
    g2 = hue2rgb(p, q, h);
    b2 = hue2rgb(p, q, h - 1/3);
);

slider10=h;
slider11=s;
slider12=l;

slider5=(r*255 + 256 * g*255 + 65536 * b*255)|0x1000000;
slider20=r2*255 + 256 * g2*255 + 65536 * b2*255|0x1000000;

@gfx 100 210
gfx_r = r;
gfx_g = g;
gfx_b = b;
gfx_rect(0,0,100,100);
gfx_r = r2;
gfx_g = g2;
gfx_b = b2;
gfx_rect(110,0,100,100);
Edit: The |0x1000000 boosts the number to the next "octave" (is that a good word to use?). Basically, instead of 0 to 16777215, it's 16777216 to 33554431.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-16-2014 at 10:22 AM.
Argitoth is offline   Reply With Quote
Old 11-16-2014, 10:31 AM   #33
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

I am certainly using a color wheel, as I need to be able to substract 15 degrees hue from red. HSL is built on a hue circle, that's one of the points of the whole construct.

Now trying to create an eel script from your JS... (sigh)

EDIT: As of now I'm getting the same r2=b2=g2 shit as in my yesterday's attempts (no, saturation is not zero).
Losing temper by the minute.

Last edited by gofer; 11-16-2014 at 10:57 AM.
gofer is offline   Reply With Quote
Old 11-16-2014, 11:00 AM   #34
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

post your full eel code.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
Argitoth is offline   Reply With Quote
Old 11-16-2014, 11:12 AM   #35
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Got behind the r=b=g... I needed to put the H/360 somewhere else...

But now I am at the same point as with my previous script (as shown in the screencap)

Here's the script so far: (designed to rotate hue by 15 degrees - but often unwillingly changes saturation and luminance, amount depending on input)
Code:
function hue2rgb(p, q, t)
(
	t < 0 ? t += 1:
	t > 1 ? t -= 1;
	t < 1/6 ? p + (q - p) * 6 * t:
	t < 1/2 ? q:
	t < 2/3 ? p + (q - p) * (2/3 - t) * 6:
	p;
);

trackcount = CountSelectedTracks(0);
trackindex = 0;

while (trackindex < trackcount) (
	int = GetTrackColor(GetSelectedTrack(0, trackindex));
	ShowConsoleMsg(sprintf(#,"int: %i\n",int));
	//int -= 16777216;
	r = int & 255;
	g = (int >> 8) & 255;
	b = (int >> 16) & 255;
	ShowConsoleMsg(sprintf(#,"RGB: %f,%f,%f\n",r,g,b));

	R = r/255;
	G =  g/255;
	B =  b/255;

	// convert rgb to hsl:

	min = min(min(R,G),B);
	max = max(max(R,G),B);
	deltaMax = max-min;

	H = (max == R ? (G - B) / deltaMax:
	  max == G ? 2 + (B - R) / deltaMax:
	  max == B ? 4 + (R - G) / deltaMax);

	H = H*60;
	H < 0 ? H+=360;

	L = (min + max)/2;

	S = deltaMax / (L < 0.5 ? (max + min) : 2 - max - min);
	ShowConsoleMsg(sprintf(#,"HSL: %f,%f,%f\n",H,S,L));

	//do some stuff
	H<345 ? H += 15 : H -= 345;
	ShowConsoleMsg(sprintf(#,"newHSL: %f,%f,%f\n",H,S,L));

	//convert back hsl to rgb:
	
	H/=360;
	s == 0 ? (
            r2=g2=b2=l;
	) : (
		q = l < 0.5 ? l * (1 + s) : l + s - l * s;
		p = 2 * l - q;
		r2 = hue2rgb(p, q, h + 1/3);
		g2 = hue2rgb(p, q, h);
		b2 = hue2rgb(p, q, h - 1/3);
	);
	
	r = r2*255;
	g = g2*255;
	b = b2*255;
	ShowConsoleMsg(sprintf(#,"newRGB: %f,%f,%f\n",r,g,b));

	newint = r + 256 * g + 65536 * b;	
	newint += 16777216;
	SetTrackColor(GetSelectedTrack(0, trackindex), newint);

	ShowConsoleMsg(sprintf(#,"newint: %i\n\n",newint));

	trackindex +=1
);
To see the error in numbers, run the script twice (ideally with one track selected which has a custom color, I didn't insert the "has custom color" test yet). Compare int and RGB of the second run with newint and newRGB of the first run. If I am not totally missing something, RGB and newRGB should be the same for these, but isn't.

Last edited by gofer; 11-16-2014 at 11:26 AM.
gofer is offline   Reply With Quote
Old 11-16-2014, 11:37 AM   #36
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

I think your main problem was that you were getting and setting the same track color. You needed i+1 for the next track. In other words:

FIRST LOOP i=0:
first track = i
second track = i+1
i+=1

SECOND LOOP i=1:
second track = i
third track = i+1
i+=1

etc.


Code:
function hue2rgb(p, q, t)
(
  t < 0 ? t += 1:
  t > 1 ? t -= 1;
  t < 1/6 ? p + (q - p) * 6 * t:
  t < 1/2 ? q:
  t < 2/3 ? p + (q - p) * (2/3 - t) * 6:
  p;
);

i=0;
loop(CountSelectedTracks(0)-1,
  int = GetTrackColor(GetSelectedTrack(0, i));
  ShowConsoleMsg(sprintf(#,"int: %i\n",int));
  //int -= 16777216;
  R = int & 255;
  G = (int >> 8) & 255;
  b = (int >> 16) & 255;
  ShowConsoleMsg(sprintf(#,"RGB: %f,%f,%f\n",R,G,B));

  R = R/255;
  G = G/255;
  B = b/255;

  //ShowConsoleMsg(sprintf(#,"RGB: %f,%f,%f\n",R,G,B));


  /*RGB to HSL*/
  min = min(min(R,G),B);
  max = max(max(R,G),B);
  deltaMax = max-min;

  H = (max == R ? (G - B) / deltaMax:
    max == G ? 2 + (B - R) / deltaMax:
    max == B ? 4 + (R - G) / deltaMax);
  H*=60;
  H < 0 ? H+=360;

  L = (min + max)/2;

  S = deltaMax / (L < 0.5 ? (max + min) : 2 - max - min);

  //do some stuff
  H<345 ? H += 15 : H -= 345;
  ShowConsoleMsg(sprintf(#,"newHSL: %f,%f,%f\n",H,S,L));

  /*HSL to RGB*/
  H/=360;
  S == 0 ? (
    R=G=B=L;
  ) : (
    q = L < 0.5 ? L * (1 + S) : L + S - L * S;
    p = 2 * L - q;
    R = hue2rgb(p, q, H + 1/3);
    G = hue2rgb(p, q, H);
    B = hue2rgb(p, q, H - 1/3);
  );
  

  ShowConsoleMsg(sprintf(#,"newRGB: %f,%f,%f\n",R,G,B));

  R*=255;G*=255;B*=255;
  newint = R + 256 * G + 65536 * B;
  SetTrackColor(GetSelectedTrack(0, i+1), newint);

  ShowConsoleMsg(sprintf(#,"newint: %i\n\n",newint));
  i+=1;
);
edit: You only need to boost the RGB number if you need to reserve 0 to be no color rather than black. feel free to add that back into your/my code.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
Argitoth is offline   Reply With Quote
Old 11-16-2014, 11:41 AM   #37
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Nope. I deliberately trigger the script twice on one single selected track, to compare output with next input. That's where things are odd.

The loop thing should run well, as I do
trackindex +=1
at the end

but I do run the loop only once so far (one selected track), so it doesn't even get into the picture.

I've got a different thing in mind for custom = black and custom = white... at least for scripts on hue and saturation. For luminance scripts, I of course need 16777216 = custom black, (not 0). That's all not necessary now. I first need to get this running as expected (which it doesn't).

(EDIT: yep, my loop is working as expected, but not (one of) the conversions

Last edited by gofer; 11-16-2014 at 11:53 AM.
gofer is offline   Reply With Quote
Old 11-16-2014, 11:41 AM   #38
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

You guys are awesome!!
Viente is offline   Reply With Quote
Old 11-16-2014, 11:44 AM   #39
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

Quote:
Originally Posted by gofer View Post
Nope. I deliberately trigger the script twice on one single selected track, to compare output with next input.
Soo.... did I fix your code or no?
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template
Argitoth is offline   Reply With Quote
Old 11-16-2014, 12:06 PM   #40
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Sorry... there seems to be a loop fault... doesn't do anything on a single selected track and if multiple tracks are selected it will change all but the first, but that only with the first trigger... does nothing on repeated trigger. That's something I never saw before

But thanks for staying with me here, much appreciated.


Looking at your licecap, I think I've got to make clear that I am not after creating a rainbow out of multiple tracks right now. Each selected track is supposed to undergo the exact same change (if they are the same color before, they are supposed to have the same (but altered) color after the process.

Here is my python version rotating hue in 15 degree steps. Note how it is at (more or less, there's rounding errors) the same color after 24 triggers and saturation/luminance is kept throughout the whole circle - that's what I'm after at this point:


it's basically the litmus test for the conversion. All other calculations are easy after this one does its thing properly.

Just for giggles, here`s the eel I posted earlier failing miserably at the same task (but as you can see it does the loop thing properly):

Last edited by gofer; 11-16-2014 at 12:49 PM.
gofer is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:40 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.