ADXTutorials

Track Color Variations with Robot API

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…) or how they are implemented (random, sequential…), etc.

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.

RGB and HSV conversions

The get_color and set_color functions of the Robot API can be used to access the colors of the objects in Atom Craft. The colors of the Cue Sheets, Cue Folders, Cues, and Tracks can be modified. A color is represented by its comma-separated RGB components (e.g., “255,0,0” for red). For example, to set the first selected Track’s color to red, we can write the following code:


# Get selected tracks:
selected_tracks = acproject.get_selected_objects("Track")["data"]

# Set first track color to red:
color = "255,0,0"
new_color = acproject.set_color(selected_tracks[0], color)

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…), and then convert back the colors to RGB to change an object’s color.

When converting from RGB to HSV, the steps are:

  • Import the colorsys Python module to handle the conversion.
  • Split the comma-separated string into three components: r, g, b.
  • Divide each component by 255 as the ranges of the arguments of the colorsys module functions are between 0 and 1.
  • Use the colorsys.rgb_to_hsv function to perform the conversion.

For the HSV to RGB conversion, simply reverse the steps above and call colorsys.hsv_to_rgb.

In our code, we defined two functions to handle these conversions:


import colorsys
import cri.atomcraft.debug as acdebug
import cri.atomcraft.project as acproject

# Convert RGB to HSV
def rgb_to_hsv(rgb):
	r, g, b = map(int, rgb.split(','))
	r, g, b = r / 255.0, g / 255.0, b / 255.0
	h, s, v = colorsys.rgb_to_hsv(r, g, b)
	return h, s, v

# Convert HSV to RGB
def hsv_to_rgb(hsv):
	h, s, v = hsv
	r, g, b = colorsys.hsv_to_rgb(h, s, v)
	r, g, b = int(r * 255), int(g * 255), int(b * 255)
	return f"{r},{g},{b}"

Color Gradient

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.

For instance, to generate a gradient by varying the saturation:

  • Two arguments are needed: the color of the first selected track (retrieved by calling get_color) and the number of selected tracks.
  • We start by converting the color of the first track to HSV.
  • We define a “step” variable that will determine the saturation variation between 2 tracks.
  • 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.

def generate_saturation_gradient(base_color, num_objects):
	base_hsv = rgb_to_hsv(base_color)
	step = 0.6 / num_objects

	colors = []
	for i in range(num_objects):
		# Increment the saturation component
		new_s = min(base_hsv[1] + step * i, 1.0)
		new_color = hsv_to_rgb((base_hsv[0], new_s, base_hsv[2]))
		colors.append(new_color)

	return colors
	

All we need now is to write a loop that assigns the new colors to the selected tracks.

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…).

Color Randomization

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.

To create a function that randomizes the saturation, we follow these steps:

  • In addition to the colorsys module, we also import the random module.
  • Our function will need an additional argument, “saturation_deviation” that we set to 0.5.
  • Again, we convert the color of the first track to HSV.
  • 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.
  • The new colors are then converted back to RGB and appended to a list.

def randomize_saturation(base_color, num_objects, saturation_deviation=0.5):
	base_hsv = rgb_to_hsv(base_color)

	colors = []
	for i in range(num_objects):
		# Skip randomization for the first selected track

		if i == 0:
			colors.append(base_color)
		continue
		
		# Generate random deviation for saturation
		s_deviation = random.uniform(-saturation_deviation, saturation_deviation)

		# Apply deviation to the base color
		new_s = max(0, min(1, base_hsv[1] + s_deviation))

		# Convert back to RGB
		new_color = hsv_to_rgb((base_hsv[0], new_s, base_hsv[2]))
		colors.append(new_color)

	return colors

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.

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…).