{"id":4848,"date":"2024-01-11T12:11:35","date_gmt":"2024-01-11T03:11:35","guid":{"rendered":"https:\/\/blog.criware.com\/?p=4848"},"modified":"2024-05-17T16:51:36","modified_gmt":"2024-05-17T07:51:36","slug":"track-color-variations-with-robot-api","status":"publish","type":"post","link":"https:\/\/blog.criware.com\/index.php\/2024\/01\/11\/track-color-variations-with-robot-api\/","title":{"rendered":"Track Color Variations with Robot API"},"content":{"rendered":"<p>On large projects, it can be difficult to navigate between Cues and tell them apart. Especially if they contain nested Sequences. For example, you may have a Switch Cue that includes several Random SubSequences that may also contain their own SubSequences. Besides having a good naming convention, using colors can be very helpful to quickly locate your assets when browsing your project. Colors can be used in various ways, for example to differentiate Cues based on the type of sounds they play (footsteps, weapons etc\u2026) or how they are implemented (random, sequential&#8230;), etc.<\/p>\n<p>However, should you need color variations across a set of tracks, such as a gradient, it can be cumbersome to select a different color for each track, especially when a Cue can easily contain more than a dozen tracks. Fortunately, the Robot API makes it easy to automatically set a gradient or randomize colors for multiple tracks at once in AtomCraft.<\/p>\n<h1 style=\"font-size: 150%; font-weight: bold; margin-top: 40px;\">RGB and HSV conversions<\/h1>\n<p>The <em>get_color<\/em> and <em>set_color<\/em> functions of the Robot API can be used to access the colors of the objects in Atom Craft. The colors of the <em>Cue Sheets, Cue Folders, Cues,<\/em> and <em>Tracks<\/em> can be modified. A color is represented by its comma-separated RGB components (e.g., &#8220;255,0,0&#8221; for red). For example, to set the first selected Track\u2019s color to red, we can write the following code:<\/p>\n<pre><code>\r\n# Get selected tracks:\r\nselected_tracks = acproject.get_selected_objects(\"Track\")[\"data\"]\r\n\r\n# Set first track color to red:\r\ncolor = \"255,0,0\"\r\nnew_color = acproject.set_color(selected_tracks[0], color)\r\n\r\n<\/code><\/pre>\n<p>However, when creating a color gradient, it is easier to work in the HSV color space. So, we first need to convert the RGB values to HSV, create our color variations (gradient, randomization&#8230;), and then convert back the colors to RGB to change an object\u2019s color.<\/p>\n<p>When converting from RGB to HSV, the steps are:<\/p>\n<ul>\n<li>Import the <em>colorsys<\/em> Python module to handle the conversion.<\/li>\n<li>Split the comma-separated string into three components: r, g, b.<\/li>\n<li>Divide each component by 255 as the ranges of the arguments of the <em>colorsys<\/em> module functions are between 0 and 1.<\/li>\n<li>Use the <em>colorsys.rgb_to_hsv<\/em> function to perform the conversion.<\/li>\n<\/ul>\n<p>For the HSV to RGB conversion, simply reverse the steps above and call <em>colorsys.hsv_to_rgb<\/em>.<\/p>\n<p>In our code, we defined two functions to handle these conversions:<\/p>\n<pre><code>\r\nimport colorsys\r\nimport cri.atomcraft.debug as acdebug\r\nimport cri.atomcraft.project as acproject\r\n\r\n# Convert RGB to HSV\r\ndef rgb_to_hsv(rgb):\r\n\tr, g, b = map(int, rgb.split(','))\r\n\tr, g, b = r \/ 255.0, g \/ 255.0, b \/ 255.0\r\n\th, s, v = colorsys.rgb_to_hsv(r, g, b)\r\n\treturn h, s, v\r\n\r\n# Convert HSV to RGB\r\ndef hsv_to_rgb(hsv):\r\n\th, s, v = hsv\r\n\tr, g, b = colorsys.hsv_to_rgb(h, s, v)\r\n\tr, g, b = int(r * 255), int(g * 255), int(b * 255)\r\n\treturn f\"{r},{g},{b}\"\r\n\r\n<\/code><\/pre>\n<h1 style=\"font-size: 150%; font-weight: bold; margin-top: 40px;\">Color Gradient<\/h1>\n<p>Now that we can manipulate our colors, we can define a function to create a simple gradient from the color of the first selected track. A gradient can be easily generated by varying a single component such as S (saturation) or V (value or brightness) in the HSV space.<\/p>\n<p>For instance, to generate a gradient by varying the saturation:<\/p>\n<ul>\n<li>Two arguments are needed: the color of the first selected track (retrieved by calling <em>get_color<\/em>) and the number of selected tracks.<\/li>\n<li>We start by converting the color of the first track to HSV.<\/li>\n<li>We define a \u201cstep\u201d variable that will determine the saturation variation between 2 tracks.<\/li>\n<li>Finally, we write a loop that increase the saturation for each track, converts the value back to RGB, and adds the new color to a list.<\/li>\n<\/ul>\n<pre><code>\r\ndef generate_saturation_gradient(base_color, num_objects):\r\n\tbase_hsv = rgb_to_hsv(base_color)\r\n\tstep = 0.6 \/ num_objects\r\n\r\n\tcolors = []\r\n\tfor i in range(num_objects):\r\n\t\t# Increment the saturation component\r\n\t\tnew_s = min(base_hsv[1] + step * i, 1.0)\r\n\t\tnew_color = hsv_to_rgb((base_hsv[0], new_s, base_hsv[2]))\r\n\t\tcolors.append(new_color)\r\n\r\n\treturn colors\r\n\t\r\n<\/code><\/pre>\n<p>All we need now is to write a loop that assigns the new colors to the selected tracks.<\/p>\n<p>Assigning a color gradient across Tracks is especially useful for Sequential Cues, or Cues that play different sounds based on intensity (car engine, wind, rain&#8230;).<\/p>\n<div style=\"max-width: 700px; margin: 0 auto; margin-bottom: 20px; border: 1px solid #aaa;\">\n<div style=\"width: 800px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-4848-1\" width=\"800\" height=\"423\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Video_01_Gradient.mp4?_=1\" \/><a href=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Video_01_Gradient.mp4\">https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Video_01_Gradient.mp4<\/a><\/video><\/div>\n<\/div>\n<h1 style=\"font-size: 150%; font-weight: bold; margin-top: 40px;\">Color Randomization<\/h1>\n<p>Generating random color variations based on the color of the first selected track is also a good way to visualize Cues of type Random, Random no Repeat, or Shuffle.<\/p>\n<p>To create a function that randomizes the saturation, we follow these steps:<\/p>\n<ul>\n<li>In addition to the <em>colorsys<\/em> module, we also import the <em>random<\/em> module.<\/li>\n<li>Our function will need an additional argument, \u201csaturation_deviation\u201d that we set to 0.5.<\/li>\n<li>Again, we convert the color of the first track to HSV.<\/li>\n<li>The color of the first selected track is used as the base color (and is not changed). We add random deviations to its saturation to produce the colors of all the other tracks.<\/li>\n<li>The new colors are then converted back to RGB and appended to a list.<\/li>\n<\/ul>\n<pre><code>\r\ndef randomize_saturation(base_color, num_objects, saturation_deviation=0.5):\r\n\tbase_hsv = rgb_to_hsv(base_color)\r\n\r\n\tcolors = []\r\n\tfor i in range(num_objects):\r\n\t\t# Skip randomization for the first selected track\r\n\r\n\t\tif i == 0:\r\n\t\t\tcolors.append(base_color)\r\n\t\tcontinue\r\n\t\t\r\n\t\t# Generate random deviation for saturation\r\n\t\ts_deviation = random.uniform(-saturation_deviation, saturation_deviation)\r\n\r\n\t\t# Apply deviation to the base color\r\n\t\tnew_s = max(0, min(1, base_hsv[1] + s_deviation))\r\n\r\n\t\t# Convert back to RGB\r\n\t\tnew_color = hsv_to_rgb((base_hsv[0], new_s, base_hsv[2]))\r\n\t\tcolors.append(new_color)\r\n\r\n\treturn colors\r\n\r\n<\/code><\/pre>\n<div style=\"max-width: 700px; margin: 0 auto; margin-bottom: 20px; border: 1px solid #aaa;\">\n<div style=\"width: 800px;\" class=\"wp-video\"><video class=\"wp-video-shortcode\" id=\"video-4848-2\" width=\"800\" height=\"423\" preload=\"metadata\" controls=\"controls\"><source type=\"video\/mp4\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Video_02_Random.mp4?_=2\" \/><a href=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Video_02_Random.mp4\">https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Video_02_Random.mp4<\/a><\/video><\/div>\n<\/div>\n<p>The advantage of using saturation to create color variations is that it preserves the tint of the original color. However, you can, of course, customize these scripts to create variations in hue and\/or brightness.<\/p>\n<p>In the archive below, we have included scripts that create gradients by increasing or decreasing the saturation, by decreasing the brightness, or by randomizing the saturation. They are configured to work on Tracks but can easily be adapted to other objects (Cue, Cue Sheets&#8230;).<\/p>\n<div style=\"max-width: 800px; margin: 0 auto; margin-bottom: 20px; text-align: center;\"><a style=\"display: block; border: 1px solid #ccc; padding: 20px; max-width: 100%; margin: 0 auto;\" href=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2024\/01\/Scripts_RobotAPI_ColorVariations.zip\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1813\" style=\"display: block; margin: 0 auto;\" src=\"https:\/\/blog.criware.com\/wp-content\/uploads\/2018\/06\/zip.png\" alt=\"zip\" width=\"80\" height=\"78\">Scripts_RobotAPI_ColorVariations.zip<\/a><\/div>\n","protected":false},"excerpt":{"rendered":"<p>On large projects, it can be difficult to navigate between Cues and tell them apart. Especially if they contain nested<\/p>\n","protected":false},"author":2,"featured_media":5379,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[5,7],"tags":[],"class_list":["post-4848","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-adx","category-tutorials"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts\/4848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/comments?post=4848"}],"version-history":[{"count":8,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts\/4848\/revisions"}],"predecessor-version":[{"id":5378,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/posts\/4848\/revisions\/5378"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/media\/5379"}],"wp:attachment":[{"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/media?parent=4848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/categories?post=4848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.criware.com\/index.php\/wp-json\/wp\/v2\/tags?post=4848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}