Old 11-16-2014, 12:24 PM   #41
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

Thanks to everyone! What i need to change in order for lightness to be "120" not "64" ?
Viente is offline   Reply With Quote
Old 11-16-2014, 12:27 PM   #42
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
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.
The circular aspect of the hue parameter doesn't imply that you *need* to use degrees - you could use radians for all I care. Dividing or multiplying by 360 is easy enough... for your specific case, you'd just subtract 15/360 (= 1/24) from the current value, add 1 if it's smaller than 0. (Also, using 0-360 degrees may suggest a resolution which isn't related to the underlying r/g/b resolution, and would likely lead to conversion errors when using integers for degrees.)

But for a 'rainbow' hue range, I'd rather not calculate the amount of degrees needed, but just count the amount of steps needed. Then count to x steps in a loop and divide 1 by x: hue = i/x; i++.

<sips espresso, wondering what makes people here interpret "random" as "rainbow"...>
__________________
˙lɐd 'ʎɐʍ ƃuoɹʍ ǝɥʇ ǝɔıʌǝp ʇɐɥʇ ƃuıploɥ ǝɹ,noʎ
Banned is offline   Reply With Quote
Old 11-16-2014, 12:39 PM   #43
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

yep, im getting rounding errors. if you do +90 or +180 you get numbers like:

0 180 360 181 362 184
__________________
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:45 PM   #44
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

figured it out, try this, round before you turn float value to 0-255 int.

Code:
function round(value) local(pos up down rounded) (
    pos = abs(value);
    up = ceil(pos);
    down = floor(pos);
    rounded = up - pos <= pos - down ? up : down;   
    rounded*sign(value);
);
Code:
R=round(R)*255;
G=round(G)*255;
B=round(B)*255;
Edit: Wait, im doing something stupid here....
Edit: This won't work because im rounding floats to 0 or 1, so RGB will never be between 0 and 255, only 0 or 255.
__________________
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 01:04 PM.
Argitoth is offline   Reply With Quote
Old 11-16-2014, 01:00 PM   #45
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

I must be doing it wrong I get instant black now.

Edit: saw your edit waiting...

Dang, I had the rounding function done somewhere (not myself, got help from someone kind, as usual with da eel ) - if I only knew where... was some clever two liner with a bitwise or, or whatsitcalled.

Last edited by gofer; 11-16-2014 at 01:06 PM.
gofer is offline   Reply With Quote
Old 11-16-2014, 01:08 PM   #46
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 Argitoth View Post
yep, im getting rounding errors. [...]
Given for the OP's request for randomness, rounding issues don't really seem to matter very much here - you can't ask for a random number and then bitch about it when you get one you don't like - although gofer seems to have bigger plans in mind already.
__________________
˙lɐd 'ʎɐʍ ƃuoɹʍ ǝɥʇ ǝɔıʌǝp ʇɐɥʇ ƃuıploɥ ǝɹ,noʎ
Banned is offline   Reply With Quote
Old 11-16-2014, 01:10 PM   #47
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

I think this is practically impossible. Could you post your python code?

The reason I think this is not possible is because we are converting back and forth over and over again via two incompatible color systems, when what you should probably be doing is saving the HSL values and converting to RGB. DONT refer to the RGB value to get the old HSL value, but update the ORIGINAL HSL value (+15 hue for example), then convert to RGB. In other words, you'd have to save the original HSL value somewhere and never conver from RGB to HSL, only convert HSL to RGB.
__________________
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 01:15 PM.
Argitoth is offline   Reply With Quote
Old 11-16-2014, 01:14 PM   #48
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 Argitoth View Post
[...] never conver from RGB to HSL, only convert HSL to RGB.
Well, if you'd intend to preserve the saturation and lightness of track/item colours, and only randomize their hue values, you'd have to convert from rgb to hsl at least once, since the original colours are stored in some rgb format. (And check if it's already a shade of grey, in which case rotating the hue will have no effect.)
__________________
˙lɐd 'ʎɐʍ ƃuoɹʍ ǝɥʇ ǝɔıʌǝp ʇɐɥʇ ƃuıploɥ ǝɹ,noʎ
Banned is offline   Reply With Quote
Old 11-16-2014, 01:18 PM   #49
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Banned, I'm neither going for rainbow nor random I'll do a fake random (using eels rand(), I think). But I figure it's better to test the overall structure with something more predictable.

I'm hearing you on rather doing the hue shift in the 0 to 1 domain. Testing that as well - but it's unlikely the culprit to my current woes. I do get inconsistencies even when doing nothing between the conversions.
Hopefully its rounding errors when going from float rgb values to the integer Reaper uses, as Argitoth suspects, that sounds pretty reasonable.
gofer is offline   Reply With Quote
Old 11-16-2014, 01:29 PM   #50
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

I totally expect rounding errors to happen when converting back and forth, as long as they are within a reasonable range. And I don't expect wonderful output with grays. I just catered for pure black and white by giving those some usable default colors to go from
Here's the python Hue increase:
Code:
# Track Color: Cycle selected tracks color hue aspect - leave saturation and brightness untouched
# 2011 11 20 by gofer

import colorsys # need this module for RGB <-> HSL conversion

# anyone haz mo betta functions for the conversions? These work alright, but seem unnecesarily winded :) Please PM me gofer
def RGBToHTMLColor(rgb_tuple):
    # convert an (R, G, B) tuple to #RRGGBB """
    colorstring = '#%02x%02x%02x' % rgb_tuple
    # that's it! '%02x' means zero-padded, 2-digit hex values
    return colorstring

def HTMLColorToPILColor(colorstring):
    # converts #RRGGBB to PIL-compatible integers"""
    colorstring = colorstring.strip()
    while colorstring[0] == '#': colorstring = colorstring[1:]
    # get bytes in reverse order to deal with PIL quirk
    colorstring = colorstring[-2:] + colorstring[2:4] + colorstring[:2]
    # finally, make it numeric
    color = int(colorstring, 16)
    return color	
	
def PILColorToRGB(pil_color):
    # convert a PIL-compatible integer into an (r, g, b) tuple """
    hexstr = '%06x' % pil_color
    # reverse byte order
    r, g, b = hexstr[4:], hexstr[2:4], hexstr[:2]
    r, g, b = [int(n, 16) for n in (r, g, b)]
    return (r, g, b)
	
def RGBToPILColor(rgb_tuple):
    return HTMLColorToPILColor(RGBToHTMLColor(rgb_tuple))

trackcount = RPR_CountSelectedTracks(0)	
trackindex = 0

while trackindex < trackcount: 
	
	TRACK = RPR_GetSelectedTrack(0, trackindex)
	PILColor = RPR_GetTrackColor(TRACK)	

	if PILColor < 16777216: #track has no custom color. Set it to some half saturated, half bright red (just to have some defaults to work from).
		h, s, l = 1.0, 0.5, 0.5
		
	elif PILColor == 16777216: #track is pure black. Set to some dark saturated red (need some color, otherwise changing hue does nothing)
		h, s, l = 1.0, 1.0, 0.15

	elif PILColor == 33554431: # track is pure white. Set it to some bright, very desaturated red (need some color, otherwise changing hue does nothing)
		h, s, l = 1.0, 0.1, 0.9
		
	else: #track has custom color other than pure black or white
		PILColor = PILColor - 16777216 # substract the leading bit (which differentiates between "no color" and "color assigned").

		r,g,b = PILColorToRGB(PILColor) #convert to rgb integers (just to convert again to HSV color space in the next step. Guess I could find something more direct)
		R, G, B = r/255, g/255, b/255 # colorsys module expects values range from 0.0 to 1.0 rather than the 0 to 255 I get from the PILColorToRGB function
		(h, l, s) = colorsys.rgb_to_hls(R, G, B)	
		
		# increment hue value: Note that the routine needs to start over from zero, when the full 360 degrees are reached...
		step = 15 # stepsize (in degrees). Change this value to make bigger or smaller steps.
		h = h * 360	
		if h >= 360 - step:
			h = h + step - 360
		else:
			h += step	
		h = h / 360

	# converting back
	r, g, b = colorsys.hls_to_rgb(h, l, s)
	r, g, b = r*255,g*255,b*255 # Yeah... need to go back up to the 0 to 255 range before converting, because RGBToPILColor wants them like that ;).
	
	New_rgb_tuple = (r, g, b)
	New_Color = RGBToPILColor(New_rgb_tuple)
	# apply the new value
	RPR_SetTrackColor(TRACK, New_Color)
	
	trackindex +=1 # next loop iteration does the next track
gofer is offline   Reply With Quote
Old 11-16-2014, 01:43 PM   #51
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Quote:
Originally Posted by Banned View Post
Given for the OP's request for randomness, rounding issues don't really seem to matter very much here - you can't ask for a random number and then bitch about it when you get one you don't like - although gofer seems to have bigger plans in mind already.
The OP requests "random" only in the hue aspect and likes to (more or less, negligible rounding errors are hopefully allowed ) preserve saturation and luminance. As of now our eel efforts do "random" in all aspects, however (and that even when I don't strive for any randomness right now).

My bigger plan is just to replace some python scripts I use pretty often by comfy eels, so I can take them with me on my USB - and in the process get rid of the ugly code I wrote back then (so I can share them without blushing too much)

Here's my color toolbar which I want to de-pythonize (as well as a bunch of key triggered actions, which I actually am using more often than the toolbar (but the toolbar is better for "showing off"):
gofer is offline   Reply With Quote
Old 11-16-2014, 01:51 PM   #52
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

from https://hg.python.org/cpython/file/2.7/Lib/colorsys.py
is it doing anything special to get less rounding errors?

Code:
def rgb_to_hls(r, g, b):
    maxc = max(r, g, b)
    minc = min(r, g, b)
    # XXX Can optimize (maxc+minc) and (maxc-minc)
    l = (minc+maxc)/2.0
    if minc == maxc:
        return 0.0, l, 0.0
    if l <= 0.5:
        s = (maxc-minc) / (maxc+minc)
    else:
        s = (maxc-minc) / (2.0-maxc-minc)
    rc = (maxc-r) / (maxc-minc)
    gc = (maxc-g) / (maxc-minc)
    bc = (maxc-b) / (maxc-minc)
    if r == maxc:
        h = bc-gc
    elif g == maxc:
        h = 2.0+rc-bc
    else:
        h = 4.0+gc-rc
    h = (h/6.0) % 1.0
    return h, l, s

def hls_to_rgb(h, l, s):
    if s == 0.0:
        return l, l, l
    if l <= 0.5:
        m2 = l * (1.0+s)
    else:
        m2 = l+ks-(l*s)
    m1 = 2.0*l - m2
    return (_v(m1, m2, h+ONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))

def _v(m1, m2, hue):
    hue = hue % 1.0
    if hue < ONE_SIXTH:
        return m1 + (m2-m1)*hue*6.0
    if hue < 0.5:
        return m2
    if hue < TWO_THIRD:
        return m1 + (m2-m1)*(TWO_THIRD-hue)*6.0
    return m1
__________________
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, 01:54 PM   #53
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Why didn't I ever think about looking into the library myself? Another forehead slapper is due here

That said, our rgb<=>hue conversion seems reasonably good. I get the exact same r,g,b values back when I go to hsl and then back to rgb without changing anything in-between. And doing some comparisons with other converters, I always found I get reasonable rgb results when I do a change in the hsl domain (only tried hue changes, so far. I suspect the problem in the rgb (float) to integer Reaper colornumber (or the int to rgb) conversion.

But I've really got enough of this for today . checking out

Thanks for all the help

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

wtf did the original poster want? oh.. OH OH YEAHH ok okokok.



Code:
// Set color of selected tracks to random hue
// by Elan Hickler, Gofer, Banned

function round(value)     (floor(value + 0.5));
function roundto(value,to)(round(value/to)*to);
function mod(val,mod)     (abs(roundto(val,mod) - val));

Undo_BeginBlock();

i=0;
loop(CountSelectedTracks(0),

  /*Track color to RGB*/
  track = GetSelectedTrack(0, i);
  RGB = GetTrackColor(track);
  R = RGB & 255;
  G = (RGB >> 8) & 255;
  B = (RGB >> 16) & 255;
  R/=255; G/=255; B/=255;

  /*RGB to HSL*/
  min = min(min(R,G),B);
  max = max(max(R,G),B);
  delta = max-min;
  L = (min + max)/2;
  S = delta / (L < 0.5 ? (max + min) : 2 - max - min);
  // H = 60 * (
  //   R == max ?     (R-B)/delta - (R-G)/delta: 
  //   G == max ? 2 + (G-R)/delta - (G-B)/delta: 
  //              4 + (B-G)/delta - (B-R)/delta;
  // );
  //H=round(H);
  //H > 360 ? H-=360 : H < 0 ? H+=360;

  //DO STUFF
  H=rand(360);
  

  /*HSL to RGB*/
  S == 0 ? (
    R=G=B=L;
  ):(
    C = (1 - abs(2*L -1)) * S;
    X = C * (1 - abs( mod((H/60),2) - 1));
    m = L - C/2;    
    H <=60  ? (R=C; G=X; B=0):
    H <=120 ? (R=X; G=C; B=0):
    H <=180 ? (R=0; G=C; B=X):
    H <=240 ? (R=0; G=X; B=C):
    H <=300 ? (R=X; G=0; B=C):
              (R=C; G=0; B=X);    
    R+=m; G+=m; B+=m;
  );
  R=round(R*255);
  G=round(G*255);
  B=round(B*255);

  /*RGB to Track color*/
  newint = R + 256 * G + 65536 * B; 
  SetTrackColor(GetSelectedTrack(0, i), newint);

  i+=1;
);

Undo_EndBlock("Set color of selected tracks to random hue", -1);
done. byatches. it's messy, I don't care!

ended up having to use round and min to get it to work. whenever I removed those functions, it stopped working, saturation/lightness would go all over the place.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

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

Hurray!!!!! Partytime, excellent! I'm so glad I looked here once more before nap

You certainly earned this huge cigar I normally share with Jeffos exclusively.


It seems to accurately do the trick with my hue thing, too, all readouts to utmost satisfaction (slightly off after the full circle, but not more than my python version). Right now looks like the perfect framework for all the rest of my color script eel bundle.

Thanks so much for making my day at last.
gofer is offline   Reply With Quote
Old 11-16-2014, 04:44 PM   #56
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

SEE LATER POST for code.

translated from: http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
learned how to read math symbols, yay! This new way of writing the formula makes wayyyy more sense. No need for that crazy hue to RGB function.
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

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

Haha! How small the internet is... I was using this exact site (not the exact page, the one that does rgb to hsl) as the online converter I mentioned several times .

But I never would get these formulars into my head (still don't), so I'll just bow with deep respect. Would I still need the round(min(bla,blah)) when I incorporate that method?
gofer is offline   Reply With Quote
Old 11-16-2014, 05:06 PM   #58
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
Would I still need the round(min(bla,blah)) when I incorporate that method?
I'm attempting to use it now, will get back to you.
__________________
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, 05:10 PM   #59
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Nice work!

I'm using this function for "rounding to nearest integer":
Code:
function round(value)
(
  floor(value + 0.5);
);
spk77 is offline   Reply With Quote
Old 11-16-2014, 06:05 PM   #60
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

ill 1up that. the description of the function indicates what happens at .5 (except for the round and rounto functions)

Code:
//round toward positive
function rndpos(value)(
  floor(value + 0.5);
);

//round toward negative
function rndneg(value)(
  ceil(value - 0.5);
);

//round away from zero
function rndawy(value) (
  value > 0 ? rndpos(value) : rndneg(value)  
);

//round toward zero
function rndtow(value) (
  value < 0 ? rndpos(value) : rndneg(value)  
);

//round to a multiple of 'to'
function roundto(val,to)(
  rndpos(val/to)*to;
);

//more complex, round to specific number of decimal places
function round(value,digits) 
(
  floor(value * pow(10, digits) + 0.5) / pow(10, digits);
);
__________________
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 08:49 PM.
Argitoth is offline   Reply With Quote
Old 11-17-2014, 05:42 AM   #61
spk77
Human being with feelings
 
Join Date: Aug 2012
Location: Finland
Posts: 2,668
Default

Quote:
Originally Posted by Argitoth View Post
I COULD NOT GET THIS TO WORK, use earlier code.

translated from: http://www.rapidtables.com/convert/color/hsl-to-rgb.htm
learned how to read math symbols, yay! This new way of writing the formula makes wayyyy more sense. No need for that crazy hue to RGB function.

HSL to RGB:
Code:
S == 0 ? (
  R=G=B=L;
):(
  C = (1 - abs(2*L -1)) * S;
  X = C * (1 - abs( mod((H/60),2) - 1));
  m = L - C/2;
  
  H <=60  ? (R=C; G=X; B=0):
  H <=120 ? (R=X; G=C; B=0):
  H <=180 ? (R=0; G=C; B=X):
  H <=240 ? (R=0; G=X; B=C):
  H <=300 ? (R=X; G=0; B=C):
            (R=C; G=0; B=X);
  
  R+=m; G+=m; B+=m;
);
]
Does this work?
Code:
S == 0 ? (
  R=G=B=L;
):(
  C = (1 - abs(2*L -1)) * S;
  X = C * (1 - abs( mod((H/60),2) - 1));
  m = L - C/2;
  
  H >= 0 && H < 60 ? (R=C; G=X; B=0):
  H >= 60 && H < 120 ? (R=X; G=C; B=0):
  H >= 120 && H < 180 ? (R=0; G=C; B=X):
  H >= 180 && H < 240 ? (R=0; G=X; B=C):
  H >= 240 && H < 300 ? (R=X; G=0; B=C):
  H >= 300 && H < 360 ? (R=C; G=0; B=X);
  
  R+=m; G+=m; B+=m;
);
spk77 is offline   Reply With Quote
Old 11-17-2014, 10:03 AM   #62
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

WORKS:
Code:
rc = (max-r) / delta;
gc = (max-g) / delta;
bc = (max-b) / delta;
H = 60 * (R == max ? bc-gc : G == max ? 2+rc-bc : 4+gc-rc);
H < 0 ? H+=360;
vs

DOES NOT WORK:
edit: figured out the problem, remove red code, add blue code.
Code:
H = 60 * (
R == max ? ((G - B)/delta)%6: 
G == max ? ((B - R)/delta)+2: 
B == max ? ((R - G)/delta)+4);
H < 0 ? H+=360
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

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

I FIGURED IT OUT

go here: http://www.rapidtables.com/convert/color/hsl-to-rgb.htm

notice that when you change hue, RGB values never jump more than 1. That means we can get away with rounding hue to the nearest degree. Once you do that, hue will always be correct when you convert RGB-->HSL-->RGB over and over again. Saturation can also be rounded to the nearest percentage, but it does not cause a problem not to round it. Lastly, lightness should not be rounded. Lastly lastly, I also had to round RGB values when converting from float to 255, not sure why. PS: I updated the previous random hue script to include (but commented out) the new code.

Code:
// Rotate color of selected tracks by +15 degrees of hue
// by Elan Hickler, Gofer, Banned

function round(value)     (floor(value + 0.5));
function roundto(value,to)(round(value/to)*to);
function mod(val,mod)     (abs(roundto(val,mod) - val));

Undo_BeginBlock();

i=0;
loop(CountSelectedTracks(0),

  /*Track color to RGB*/
  track = GetSelectedTrack(0, i);
  RGB = GetTrackColor(track);
  R = RGB & 255;
  G = (RGB >> 8) & 255;
  B = (RGB >> 16) & 255;

  /*RGB to HSL*/
  R/=255; G/=255; B/=255;
  min = min(min(R,G),B);
  max = max(max(R,G),B);
  C = max-min;
  L = (min+max)*0.5;
  S = C / (L < 0.5 ? max+min : 2-max-min);
  H = R == max ?   (G-B)/C: 
      G == max ? 2+(B-R)/C: 
                 4+(R-G)/C;             
  H < 0 ? H+=6;   

  //DO STUFF
  H=round(H*60); //multiply up to degrees
  H+=15; //rotate by 15 degrees
  H > 360 ? H-=360 : H < 0 ? H+=360; // keep degrees between 0 and 360
  H/=60; //divide back down to 0-6

  /*HSL to RGB*/  
  S == 0 ? R=G=B=L : (
    C = S * (1 - abs(2*L-1));
    X = C * (1 - abs(mod(H,2) - 1));  
    m = L - C*0.5;
    H < 1 ? (R=C; G=X; B=0):
    H < 2 ? (R=X; G=C; B=0):
    H < 3 ? (R=0; G=C; B=X):
    H < 4 ? (R=0; G=X; B=C):
    H < 5 ? (R=X; G=0; B=C):
            (R=C; G=0; B=X);    
    R+=m; B+=m; G+=m;
  );
  R=round(R*255);
  G=round(G*255);
  B=round(B*255);

  /*RGB to Track color*/
  RGB = R + G<<8 + B<<16; 
  SetTrackColor(GetSelectedTrack(0, i), RGB);

  i+=1;
);

Undo_EndBlock("Rotate color of selected tracks by +15 degrees of hue", -1);
BONUS: Here is my perfected JSFX to demonstrate the math behind RGB/HSL, math and code simplified as much as possible.

Code:
slider1:255<0,255,1>Red
slider2:0<0,255,1>Green
slider3:0<0,255,1>Blue

slider11:0<0,360,1>H
slider12:1<0,1,.001>S
slider13:0.5<0,1,.001>L

slider21:255<0,255,1>R
slider22:0<0,255,1>G
slider23:0.5<0,255,1>B
slider24:0<0,16777215,1>RGB

@init
function round(value)(
  floor(value + 0.5);
);
function roundto(val,to)(
  round(val/to)*to;
);
function mod(val,mod)(
  abs(roundto(val,mod) - val);
);

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

/****RGB to HSL****/
min = min(min(R,G),B);
max = max(max(R,G),B);
C = max-min;
L = (min+max)*0.5;
S = C / (L < 0.5 ? max+min : 2-max-min);
H = R == max ?   (G-B)/C: 
    G == max ? 2+(B-R)/C: 
               4+(R-G)/C;             
H < 0 ? H+=6;
/******************/

slider11=round(H*60);
slider12=S;
slider13=L;

/****HSL to RGB****/
S == 0 ? R2=G2=B2=L : (
  C = S * (1 - abs(2*L-1));
  X = C * (1 - abs(mod(H,2) - 1));  
  H < 1 ? (R2=C; G2=X; B2=0):
  H < 2 ? (R2=X; G2=C; B2=0):
  H < 3 ? (R2=0; G2=C; B2=X):
  H < 4 ? (R2=0; G2=X; B2=C):
  H < 5 ? (R2=X; G2=0; B2=C):
          (R2=C; G2=0; B2=X);
  m = L - C*0.5;
  R2+=m; B2+=m; G2+=m;
);
/******************/

slider21=round(R2*255);
slider22=round(G2*255);
slider23=round(B2*255);
slider24=slider21 + slider22<<8 + slider23<<16;

@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);
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 11-17-2014 at 03:56 PM.
Argitoth is offline   Reply With Quote
Old 11-17-2014, 02:28 PM   #64
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

It's awesome to see that you're so well on fire with this

Not to say I can follow you, but I can confirm that the color survives the full hue circle better when going through it in 15 degree steps. I got a derivation of 1 in the G aspect with the initial color I chose for the quick test, compared to a derivation of 6 using the former method. That was absolutely good enough for my purpose already, but better can only be better, that's clear.

I suspect this optimization is catered for hue change, and things may turn out different when changing luminance or saturation.
Changing those is a lot more error prone in my Pythons as well, for example I ended up subtracting a slight bit of saturation in the script that adds luminance, or the S would slowly crawl upwards with each trigger (I also had some special case scenario in the add-luminance which I couldn't explain myself and worked around in a way that I for the life of me can't understand looking at it now ).
But maybe that's all a thing of the past... let's see.

Going to test all that later on (alas, weekend is over and it'll be more lurking than doing for some days)


Tell you what, I am silently hoping that spk77 does one of his nifty slider-window-eels out of this, he already did an RGB sliders teaser in some other thread lately .
gofer is offline   Reply With Quote
Old 11-17-2014, 02:31 PM   #65
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

Its amazing what you guys just did. Sitting here and watching your brainstorm is great experience! Thank you!

I'll try to convert it to color item by myself.
Viente is offline   Reply With Quote
Old 11-17-2014, 02:42 PM   #66
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Quote:
Originally Posted by Viente View Post
Its amazing what you guys just did. Sitting here and watching your brainstorm is great experience! Thank you!

I'll try to convert it to color item by myself.
From some point onward it was more like brain-meltdown on my side . So glad Argitoth caught fire, I'd still be stumped.
gofer is offline   Reply With Quote
Old 11-17-2014, 02:59 PM   #67
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
I suspect this optimization is catered for hue change, and things may turn out different when changing luminance or saturation.
Saturation could be rounded to the closest 0.01. Lightness could probably be rounded to the closest 0.005. I think the more rounding you use before converting to RGB, the less loss you will have, and you are sacrificing none to a small amount of possible colors. I guess it's all about what you can get away with.


Quote:
Originally Posted by gofer View Post
I am silently hoping that spk77 does one of his nifty slider-window-eels out of this, he already did an RGB sliders teaser in some other thread lately .
Yep, spk77 is awesome at that.
__________________
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-17-2014, 03:52 PM   #68
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

Mine are all (deliberately) stepped anyway, I don't care at all for the in-betweens. My original saturation ended up to be in 0.1 size steps, the luminance 0.07, and I use a coarse (15 degrees) and a fine (8 degrees) hue. There are still more than enough variations.

With sliders it's a bit different, of course. But I wouldn't complain at all when they step along. Probably I'd even appreciate it.

As of now, the last version of the script works really good for saturation and luminance as well. I obviously do need to keep saturation away from zero, as well as keep luminosity away from both extremes - after all, they don't make much sense to me - I don't need neither black nor white for this purpose. I did the same in the original scripts.
gofer is offline   Reply With Quote
Old 11-17-2014, 05:43 PM   #69
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

I'm trying to convert it to color items, but it won't work...no errors, just nothing happens

What am i doing wrong?

Code:
function round(value)     (floor(value + 0.5));
function roundto(value,to)(round(value/to)*to);
function mod(val,mod)     (abs(roundto(val,mod) - val));

Undo_BeginBlock();

i=0;
loop(CountSelectedMediaItems(0),

  /*Track color to RGB*/
  item = GetSelectedMediaItem(0, i);
  RGB = GetMediaItemInfo_Value(item, "I_CUSTOMCOLOR");
  R = RGB & 255;
  G = (RGB >> 8) & 255;
  B = (RGB >> 16) & 255;
  R/=255; G/=255; B/=255;

  /*RGB to HSL*/
  min = min(min(R,G),B);
  max = max(max(R,G),B);
  delta = max-min;
  L = (min + max)/2;
  S = delta / (L < 0.5 ? (max + min) : 2 - max - min);
  H = 60 * (
    R == max ?     (R-B)/delta - (R-G)/delta: 
    G == max ? 2 + (G-R)/delta - (G-B)/delta: 
               4 + (B-G)/delta - (B-R)/delta;
  );
  H=round(H); 

  //DO STUFF
  H+=15;
  H > 360 ? H-=360 : H < 0 ? H+=360;

  /*HSL to RGB*/
  S == 0 ? (
    R=G=B=L;
  ):(
    C = (1 - abs(2*L -1)) * S;
    X = C * (1 - abs( mod((H/60),2) - 1));
    m = L - C/2;    
    H <=60  ? (R=C; G=X; B=0):
    H <=120 ? (R=X; G=C; B=0):
    H <=180 ? (R=0; G=C; B=X):
    H <=240 ? (R=0; G=X; B=C):
    H <=300 ? (R=X; G=0; B=C):
              (R=C; G=0; B=X);    
    R+=m; G+=m; B+=m;
  );
  R=round(R*255);
  G=round(G*255);
  B=round(B*255);

  /*RGB to Track color*/
  newint = R + 256 * G + 65536 * B; 
  SetMediaItemInfo_Value(GetSelectedMediaItem(0, i), "I_CUSTOMCOLOR", newint);

  i+=1;
);
Viente is offline   Reply With Quote
Old 11-17-2014, 06:23 PM   #70
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

item must actually be a color first. I could set item to default color when no color exists, but still figuring out the details of the difference between marker color, track color, item color, etc.

SEE CODE CHANGES IN RED
Code:
  SetMediaItemInfo_Value(GetSelectedMediaItem(0, i), "I_CUSTOMCOLOR", newint|0x1000000);

  i+=1;
);
UpdateArrange();
__________________
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-17-2014, 06:28 PM   #71
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

Thanks!
Viente is offline   Reply With Quote
Old 11-17-2014, 06:44 PM   #72
Viente
Human being with feelings
 
Viente's Avatar
 
Join Date: Feb 2012
Posts: 1,972
Default

Dream came true. No more lifeless media items


Luv you guys
Viente is offline   Reply With Quote
Old 11-18-2014, 02:49 AM   #73
gofer
-blänk-
 
gofer's Avatar
 
Join Date: Jun 2008
Posts: 11,359
Default

In my item color scripts I first check whether the item has an item color assigned. You know that when the return of your color query is > 16777216.
a) If yes (item color >=16777216), all is well -> process that color. (well, almost... see below).
b) If not, I check whether the track it's on has a track color assigned.
a2) If yes (track color >=16777216), process the track color and hand the processed track color over to the item as new item color.
b2) If neither track nor item color exist I fall back to giving the item an arbitrary color, to have something to go from. You want random hue, in that case I'd probably default saturation and luminance to some comfortable value and randomize hue.


If there is a color assigned, it could still be pure black ( =16777216) (converts to H=0, S= 0, L=0) , pure white ( =33554431) (H=0, S=0, L=100%) or a perfect grey (R=G=B) (H=0, S=0, L= anything). All of these don't play so nice with HSL processing. In those cases just pull S and L away from the extremes a bit to something you can bear to look at and randomize Hue.
gofer is offline   Reply With Quote
Old 03-11-2015, 09:58 AM   #74
Argitoth
Human being with feelings
 
Argitoth's Avatar
 
Join Date: Feb 2008
Location: Mesa, AZ
Posts: 2,057
Default

bump.

Code:
function RGB_HSL(R,G,B,H*,S*,L*) local(C) (
  min = min(min(R,G),B);
  max = max(max(R,G),B);
  C = max-min;
  L = (min+max)*0.5;
  S = C / (L < 0.5 ? max+min : 2-max-min);
  H = R == max ? (G-B) / C: 
      G == max ? 2+(B-R)/C: 
                 4+(R-G)/C;             
  H < 0 ? H+=6;
);

function HSL_RGB(H,S,L,R*,G*,B*) local(C,X,G,m) (
  !S ? R=G=B=L : (
    C = S * (1 - abs(2*L-1));
    X = C * (1 - abs(mod(H,2) - 1));  
    H < 1 ? (R=C; G=X; B=0):
    H < 2 ? (R=X; G=C; B=0):
    H < 3 ? (R=0; G=C; B=X):
    H < 4 ? (R=0; G=X; B=C):
    H < 5 ? (R=X; G=0; B=C):
            (R=C; G=0; B=X);
    m = L - C*0.5;
    R+=m; B+=m; G+=m;
  );
);
__________________
Soundemote - Home of the chaosfly and pretty oscilloscope.
MyReaperPlugin - Easy-to-use cross-platform C++ REAPER extension template

Last edited by Argitoth; 03-11-2015 at 10:08 AM.
Argitoth 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:09 PM.


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