I’m writing a basic DMX controller which has a few simple colour animations. One animation I’m working on currently uses a sin() function to oscillate the brightness value. When the brightness is 0 I want the hue to increment or decrement by certain amount (basically just creating a pulsing colour change).
The code is almost working fine, although my if statement which tries to trigger when brightness == 0 isn’t reliable. It seems as it doesn’t register sin() reaching the minimum every time. I’ve tried the value being set to float or int and it doesn’t make a difference.
Here’s the relevant code with comments:
// Use sin to cycle brightness from min-max with variable speed
int x = int(map(sin(a), -1, 1, 0, 100));
a = a + speed;
Bright = x;
// Switch to increment or decrement
if (Bright == 0){
if (swaphue == true) {
Hue += HUE_SWAP_AMT; // adjust by controlP5 specified amount
swaphue = false;
}
else if (swaphue == false){
Hue -= HUE_SWAP_AMT;
swaphue = true;
}
}
//Wrap around Hue value.. Keep in range 0-255
if (Hue > 255) {
Hue = 0 + HUE_SWAP_AMT;
}
else if (Hue < 0) {
Hue = 255 - HUE_SWAP_AMT;
}
I feel like I’m probably missing something quite obvious… but please let me know how I might be able to make the switch trigger consistently.
Thanks for your response - sorry it’s not that clear!
the if (Bright == 0){ is the ‘switch’ I’m talking about… that value is taken from the int x in the section above which is mapped using sin().
I’ve combined your code with mine into a working example to demonstrate better. You’ll notice that while it oscillates it doesn’t just go red-green-red-green etc… but sometime’s it’ll go red-red-green-red-green-green for example.
color cb;
float a;
boolean swaphue = true;
float HUE_SWAP_AMT = 75;
float speed = 0.09;
float hue = 0;
void setup() {
size(200,200);
colorMode(HSB, 255, 100, 100);
}
void draw() {
mycolor();
background(cb);
}
void mycolor() {
// Use sin to cycle brightness from min-max with variable speed
int bright = int(map(sin(a), -1, 1, 0, 100));
a = a + speed;
// Switch to incrememnt or decrememnt
if (bright == 0){
if (swaphue == true) {
hue += HUE_SWAP_AMT; // adjust by controlP5 amount
swaphue = false;
}
else if (swaphue == false){
hue -= HUE_SWAP_AMT;
swaphue = true;
}
}
//Wrap around Hue value.. Keep in range 0-255
if (hue > 255) {
hue = 0 + HUE_SWAP_AMT;
}
else if (hue < 0) {
hue = 255 - HUE_SWAP_AMT;
}
cb = color(hue,100,bright);
}
Please let me know if there is a better way to achieve a reliable red/green oscillation.
Floating-point numbers are only very rarely exactly equal to a given value or to each other. It’s safe to compare < or > for floats, but almost never safe to compare ==.
sin(a) is only exactly equal to -1.0 when a is exactly equal to pi*3/2 (plus multiples of 2pi). If you are feeding in values of a that you are computing by adding up floating-point numbers, it’s extremely unlikely that you would ever hit the precise value that the computer would store for pi*3/2. Your speed step is more likely to go from just less than that amount to just greater than it, so your map(sin()) will never hit 0 exactly. The only reason you’re hitting 0 at all is that you are mapping to integers and occasionally a sufficiently small value rounds down to 0.
A better approach would be to look at the value a and consider when it will be near multiples of pi*3/2. Again, though, you can’t exactly compare floats, but you CAN compare integers. So increment an integer instead or just use the built-in frameCount. Decide how many frames you want per cycle. Set a as a multiple of the frameCount and swap your hue when the integer frameCount hits the exact values for which your map(sin()) would hit 0.