I am after a general function/procedure that would calculate me fade times and values based on data provided, something like this:
I have byte values saved in a byte array: these are the start values. Then I have some memorized values in some other array: these are to be the new values. Then I have time to be provided, which is time needed a start value to get to new value.
I need to get updates on the values each time they change (up to 0.1 seconds accurate). I know that if value A changes for 10 and value B changes for 100 in the same time, let's say 1 second, I'll get value A updated 10 times, while value B will be updated 100 times.
So far I have been planning on using a timer, with interval let's say 50ms, which would constantly be calculating the difference based on the value of the change and the time needed, something like: change step := (Difference between start and new value / {divided by} (fade time / timer interval) )
.
But given the fact that value changes are different, fade times as well, and that I could execute another value fading before the first fading has ended, is making all of this confusing and difficult for me.
So, what I would need is an option to, let's say, given values at index 1, 2, 3, 4, 5, 6 and 7 to be changed to their new values in 30 seconds, then at some point somewhere in between I could order the values at index 11, 13 and 17 to change to their new values in 9 seconds, etc...
Also, in case that value A would have a fading towards value B in progress, and another fade from A to C would be ordered, I would like it to be added to a queue list, to be executed right after the first fade is finished. And at that time, the B value from the first command would become the A value in the second command. This is due to these facts: The A in the example above should always be read at the very moment of the fade start. This way, it is a starting value no matter what was done before the fade or between the fade command and fade execution. Therefore, I could set Fade1 to Current -> B @ 10s and queue a Fade2 for Current -> C @ 10s, whereas the Current in the second case is actually value otherwise saved as B, and let's assume the Current in Fade1 is same as value saved as C. This way the value would be in a loopback, changing every 10 seconds. So basically, the command for adding a fade should only have something like SetNewFade: Dest:=B; Time:=10;.
So I could add ->B@10s, ->C@10s, ->B@10s, ->C@10s, and it would just loop from B to C and backwards until queue list is empty. I hope I managed to make this clear enough for you to understand. I really can't describe better what I need to achieve.
Also, as all of the fades would be provided in a Listbox, I would like to be able to delete fades in the queue as desired. But, if the currently running fade is deleted, the value should jump to a new value as if the fade would be already completed, and normally then start the new fade in queue list, if there's any.
How would that be the easiest to create? Is using Timer with fixed interval a good idea? Would it cause any delays if a lot of values would be pending for fade? Is using dynamic arrays for values and times (and populating them on StartFade event and release them after fading is complete) a shot in the dark or a good guess?
Here an example which I hope makes it clearer:
A: array [0..20] of Byte;
B: array [0..20] of Byte;
C: array [0..20] of Byte;
Current: array [0..20] of Byte;
Button1 applies the A values to the Current values, Button2 applies the B values, and Button3 applies the C values, and so on...
So I set time in an Edit box, let's say 5 seconds, and click on Button1. With that, I added the fade from Current towards values in array A with time 5 seconds. Since it's the first in queue, it starts to execute immediately. Before the fade is actually completed, I set time 20 seconds and press Button2. So I just added another fade in a queue list: from Current towards the values in array B. Since I'm changing the same values (index 0..20), this is starting to be executed right after the first fade completes. Note: the fading process is constantly updating the Current array, until it has the same values as the fade command's array! Therefore, the second fade will fade again from Current to B, with Current actually being same as A.
Now where things gets even more complicated is when I actually set just values indexed 0, 1, 2, 3 and 4 from the arrays to be faded @5sec to A, and then I apply the values indexed 5, 6, 7, 8 and 9 to be faded @10sec to B values: in that case, since the indexes I am fading are different ones, both fade commands should execute right away.
In case one value is in both fades (such as if I'd add value indexed 4 to the second fade), only this value would need to be added to a queue list. So the other fades right away, while the one that is already fading in the first fade, waits for it to finish, and then starts to fade as per the second command.
Some additional information:
Lengths of the arrays are not fixed at the moment, but could be set fixed if this is important. It is for sure a multiplier of 512 with a maximum of 2047.
The number of arrays is unknown and is to be modified in runtime as needed. They will probably be stored as records, (such as
StoredVals: array of record;
,Index: array of Integer
(index of the values; this is to tell which values are stored in this record), andValue: array of Byte;
(these are actual values that are faded, based onCurrent[StoredVals[0].Index[0]]
for example. Current is keeping data of all values, meanwhile the records of A, B, C etc... keeps only the values of those which are indexed inside that record).The lengths of the arrays are, based on the description above, not always equal since they aren't always changing the same amount of values.
The arrays are filled from the database at initialization. Since they can be created on runtime, they are filled from the Current values and stored as new array as well. But this is always also written in a database as well then. They are kind of memorized values, so that I can recall them with buttons. For that matter, I would like to have an option to recall those values immediately (as I do now already) or via the fading option. Now, to avoid the issues for a value in the queue, I was thinking of sending that immediate change through the fading process as well, only with time 0 seconds. That way, the values which are not in queue would be applied immediately, while if some value is currently fading, it will be applied after that fade is complete. That said, this fade process would be in the command flow all the time.
If there's any other extra clarification needed, please don't hesitate to ask!
I know this is really complicated, and that's why I'm looking for your help. Any partial help or suggestions would be appreciated.
Actually, you seem to be after a complete program. You are thinking about solving it as a whole, and that's clouding, which is why you have so many questions. You need to learn breaking this task up in smaller parts, and to summarize the requirements more clearly. The question in its current form is close to being off-topic, and it probably would fit better at SE Programmers. But since this fits right up my alley, I would like to step you through.
Requirements
I am pretty sure this is a correct summary of your question.
Transitions
Your proposal to use a Timer to perform a piece of the total transition on every interval is sound. Now, there are two ways to calculate those pieces:
The second solution is preferred, and this translates into the following general routine you are looking for. Let's start simple by assuming a single item:
With this approach, the Timer's interval does not affect the calculation: at any given time the result of
InBetweenValue
will be correct. The only thing the Timer is needed for is driving the progress. If you want a 67 Hz refresh rate then set its interval to 15 milliseconds. If you want a refresh rate of 20 Hz, then set the interval to 50 milliseconds.Performance
No, not for the implied reason. The time needed for all calculations may depend on the size of the queue, but that will for sure not be a significant factor. (If so, then you have problems of a much more troubling caliber). Possible "delays" will be manifested in a a lesser refresh rate due to missed or merged Windows Timer messages, depending on how busy the computer is with everything it's doing.
Data storage
Let's first analyze what data needs to be handled. There is a single set of in-between current values of arbitrary length, and each value has its own four attributes: begin value, end value, transition duration and transition start time. So you have the choice between:
The first solution requires trouble with keeping all five sets synchronized. The second requires another dimension. I would prefer the latter.
Whether you use arrays or something else is up to you. Choose what you are most comfortable with, what fits the purpose or what matches the input or required output best. Whether you choose static of dynamic arrays depends on the variability of the input and makes no measurable difference in performance. Dynamic arrays require runtime length management, where static arrays do not.
But since you need a dynamic solution anyway, then I suggest thinking outside the box. For example, the RTL offers no default built-in management tools for arrays, but it does have collection classes that do, e.g.
TList
.For the rest of this answer, I will assume the decision of using an Object for an element and a List for keeping track of them.
Design
Now that the two most pressing points have been addressed, the design can be worked out.
There is a List with items, and each item has its current value and four attributes: begin, end, duration and start time. Each item must be capable of getting new attribute values. There is a formula for calculating the current value, based on the attributes. And there is a Timer which should automate a multiple of these calculations.
Furthermore, a multiple of transition commands should be stored for an Item. Since we have an Item with members already, let's add those commands as member of the Item too.
Something missing? No. Let's go.
Implementation
We need:
This should help you set up the interface part of the code. Linger, and contain eagerness to start coding the implementation.
Hereby my try-out, originated as described above:
And a tiny plug-and-play demonstration program (note that the labels only show the last request):
Succes.