Timing based transition code between variable numbers

I’m hoping someone out there might have an idea on how I could better solve this problem I’ve created for myself :slight_smile: I’m currently looking for a way to program this logic: Imagine I have a control slider, that a user controls and goes from 0 to 255, and imagine I have a timing slider, from 0 milliseconds to 20,000 milliseconds.

Now, if I set the timing slider to 20,000, and move the control slider from 0 to 255, I would expect that the code will output a transition point between 0 to 255 over 20 seconds. I have code that does this fine, and it will be attached below.

However, lets say 10 seconds into that transition period the user moves the control slider from the 255 back to 0. At 10 seconds in, the transition point, x, should be at 127. What I want to happen is for the x value to move over the remaining 10 seconds to the new control slider point, in this case, 0. Ideally this should work for any number of movements over that 20 second period.

Once the x reaches the control slider point, the transitioning code deactivates until the next movement.

Here’s the code that handles the first part of the problem I’m trying to solve:

class Fader {

public:

float newFaderValueSetTime;

float newFaderValue;

bool transitionInMotion;

float lastReturnedValueWhenNewFaderValueWasSet;

bool newFaderValueSet;

float lastOutputValue;

Fader(void) {
    lastReturnedValueWhenNewFaderValueWasSet = 0;
    newFaderValue = 0;
    lastOutputValue = 0;
    transitionInMotion = false;
}

int getValue(float delayAmount) {
    float currentTime = ofGetElapsedTimeMillis() ;
    float timePassedSinceNewFaderValue = currentTime - newFaderValueSetTime;        

    if(timePassedSinceNewFaderValue >= delayAmount) {
        transitionInMotion = false;
    }

    if(transitionInMotion) {
        lastOutputValue =  ofMap(timePassedSinceNewFaderValue, 0, delayAmount, lastReturnedValueWhenNewFaderValueWasSet, newFaderValue);
    } else {
        lastOutputValue = newFaderValue;
    }

    return lastOutputValue;
}   


void setFaderValue(int val, float delayAmount) {

    if(delayAmount > 0 && !transitionInMotion) {
        transitionInMotion = true;
        newFaderValueSetTime = ofGetElapsedTimeMillis();
        lastReturnedValueWhenNewFaderValueWasSet = lastOutputValue;         
    }   
    newFaderValue = val;    
}
};

The main point of code that is at issue, I think is the way the mapping of value ranges functions - for example, take this line: lastOutputValue = ofMap(timePassedSinceNewFaderValue, 0, delayAmount, lastReturnedValueWhenNewFaderValueWasSet, newFaderValue);

This line takes the amount of time passed as the temporal position, makes it relative to delay amount, then remaps its the value from the lastReturnedValueWhenNewFaderValueWasSet to the newFaderValue… e.g.,

If at time of transition, the fader value was at 0, and moves to 255, then lastReturnedValueWhenNewFaderValueWasSet = 0, and newFaderValue = 255;

However, at the 10 second mark, the lastOutputValue will be 127, and if I then move the newFaderValue from 255 to 0, then lastReturnedValueWhenNewFaderValueWasSet will still be 0, and the mapping will be from 0 to 0, rather than from the current position of the transition point, x.

I hope this explains the logic a bit better. Cheers!

I’ve solved the problem I set out. Here is a rundown of the logic and the code for those looking for a solution to this sort of problem.

x will increase if the destination is greater than x

x will decrease if the destination is less than x

x is defined as the value set before the timer is initiated

if the timer has started:
Defined as:
timer is greater than zero
The destination is greater than or less than x

The increase amount is defined as the distance between x, the destination, divided by the time left to reach the destination multiplied by the difference since the last time x was set.

e.g.
lets say x is 127, and destination is 200. The time remaining is 10,000 milliseconds

positive difference = 200-127 = 73 over 10,000

divided by the time remaining, multiplied by the time change since last update.

(200-127 / 10,000) * 60 (miliseconds since last update)

= amount to increment…

lets say x = 200 and the destination is 90. The time remaining is 10,000 milliseconds

positive difference is 200-90 = 110.

(110 / 10,000) * 60 (milliseconds since last update) = 0.66… which is to be removed from x…

and because x is decreasing in this case, an additional calculation of (0.66 * -1) to produce the negative value.

And the code:

class Fader {

public:


float newFaderValueSetTime;
float destination;
float lastUpdateTime;
float x;

bool transitionInMotion;

Fader(void) {

	transitionInMotion = false;
	lastUpdateTime = -1;

	x= 0;
	destination = 0;

}

float positiveDifference(float x1, float y1) {
	if(x1>y1) {
		return x1-y1;
	} else {
		return y1-x1;
	}
}

int getValue(float delayAmount) {
	float currentTime = ofGetElapsedTimeMillis();		

	float timePassedSinceNewFaderValue = currentTime - newFaderValueSetTime;	

	if(timePassedSinceNewFaderValue >= delayAmount) {
		transitionInMotion = false;
	}
	
	if(transitionInMotion) {
		float timeRemaining = delayAmount - timePassedSinceNewFaderValue;

		float diff = positiveDifference(x, destination);

		float tempX = (diff / timeRemaining);

		if(lastUpdateTime == -1) {
			lastUpdateTime = currentTime;
		} else {
			tempX = tempX * (currentTime - lastUpdateTime);
		}			

		if(destination > x) {
			x = x + tempX;
		} else if (destination < x) {
			x = x + (tempX*-1); 
		} 
	} else {
		x = destination;
	}
	

	if(x > 0) {
		ofLogNotice("Output Value of fader is: " + ofToString(x));
	}
			
	lastUpdateTime = currentTime;
	
	return x;
}	


void setFaderValue(int val, float delayAmount) {

	if(delayAmount > 0 && !transitionInMotion) {
		transitionInMotion = true;
		newFaderValueSetTime = ofGetElapsedTimeMillis();
		lastUpdateTime = -1;
	}	
	destination = val;	
}
};
1 Like