Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cuelist slider fix #1396

Merged
merged 8 commits into from
Dec 27, 2023
Merged

Cuelist slider fix #1396

merged 8 commits into from
Dec 27, 2023

Conversation

kpr0th
Copy link
Contributor

@kpr0th kpr0th commented Feb 18, 2023

Adjust CueList slider value calculation to fully align ValueChanged->Step# and Step#Changed->Value calculations.

Previously, clicking the PreviousStep button didn't always update the slider position, due to off-by-one issues near whole-numbered calculated values. Example: with a 6-step chaser, advance to the end, then click the Previous Cue button and note that the slider only jumps up every other click. Also, if you move the slider position with keystrokes up and down (or presumably also via a midi encoder wheel up/down), note that it jumps to the next step at slightly different values than the ones that are calculated when using next/previous step buttons -- and then the displayed value at the top of the slider "jumps" to the top end of the subset of values calculated to belong to the newly selected chaser step #, which causes the visual feedback to "jump".

@mcallegari
Copy link
Owner

mcallegari commented Feb 21, 2023

I'm not really convinced by those +/- 0.00001
Can you please share the workspace you were using to test this so I can have a look too? (you'll have to zip it to attach here)
Thanks

@kpr0th
Copy link
Contributor Author

kpr0th commented Feb 21, 2023

Yes, I'll try to pack it up tonight after work. And maybe throw a quick video together to walk through it. For now I'll try explaining with words, in case that's enough.

I was testing with a super-simple workspace - 1 scene dropped into a chaser 6 times, and attached to the cuelist. Also tested with it in the chaser 18 times. I watched the debug closely (I actually changed it to qWarning temporarily so I could ignore all the other debug output). And then I used the NextCue/PrevCue buttons and keyboard arrows (up/down) to move the steps and slider.

With 6 steps, each step gets 42 2/3 of the 256 DMX values (42.6666666667). First step starts at 255 and ends at 212.333333, so it "owns" the range from 255 down to 213; in other words, any value between 213 and 255 inclusive should equate to step # 1.
The second step's starting location gets truncated down to 212, and ends at 169.666666, so it "owns" the range from 212 down to 170.
Third step starts at 169, and the fourth step starts at exactly 127, so the third step "owns" the range from 169 down to 128. And this is where the problem comes in - without those +/-0.00001's, the calculation was deciding that the third step owns 169 down to 127, and the fourth step owned 127 down to 85, and if 2 steps share one DMX value then it was unclear which one really owned that value - and when I arrowed "up" toward the top of the slider, it would jump when it got to 127 (if i recall correctly).

I picked 0.00001 because floats keep 6-8 digits of precision, and the smallest # of DMX values assigned to one step is 256/255 = 1.00392. So the 0.00001 is large enough to affect the floating point numbers, but small enough to never push any one step's range over an integer boundary that it shouldn't (at least, that's my belief).

@kpr0th
Copy link
Contributor Author

kpr0th commented Feb 21, 2023

p.s. I was thinking I was dealing with floating point rounding errors when I was testing the code change. I thought the value that was supposed to be an exact integer was somehow looking like it was slightly less than the integer value. But after responding to your question above, I realize that the real issue I'm solving is that an integer value comes out as the same number if you apply qCeil or qFloor, but to make sure each step owns a specific range of DMX values I needed all the possible dividing lines to return one value after qCeil() and a different value after qFloor()... So, the comment in the code I checked-in is misleading; I'll try to fix that. I'll still get you a workspace and a few pictures or a video tonight.

@kpr0th
Copy link
Contributor Author

kpr0th commented Feb 23, 2023

I'm not really convinced by those +/- 0.00001 Can you please share the workspace you were using to test this so I can have a look too? (you'll have to zip it to attach here) Thanks

Attaching a zip, containing the test qxw plus a series of PNG's to try and illustrate what I was seeing.

cuelist-test.zip

@coveralls
Copy link

coveralls commented Dec 22, 2023

Coverage Status

coverage: 32.066% (-0.001%) from 32.067%
when pulling f13524c on kpr0th:cuelist-slider-fix
into b99c30e on mcallegari:master.

@kpr0th kpr0th force-pushed the cuelist-slider-fix branch 3 times, most recently from 98af807 to 0e2a37f Compare December 22, 2023 03:07
When the Step # changed, or the SliderValue changed, in Steps mode, the calculation to convert step# to value or vice versa had some off-by-one issues. The main visible symptom was that the slider position didn't always update when clicking the PreviousCue button (in a 6-step chaser, it would update the slider position every-other-click). Also, if moving the slider position using up/down arrows, the step # didn't change at the exact same slider positions as were jumped to using the Next-Cue button.

In v5 this is perhaps not necessary, because the slider position doesn't update if the Current Step changes; but if code is ever added to set the slider position on current step changing the same fix for the same reason is applicable here too.
When the Step # changed, or the SliderValue changed, in Steps mode, the calculation to convert step# to value or vice versa had some off-by-one issues. The main visible symptom was that the slider position didn't always update when clicking the PreviousCue button (in a 6-step chaser, it would update the slider position every-other-click). Also, if moving the slider position using up/down arrows, the step # didn't change at the exact same slider positions as were jumped to using the Next-Cue button.

In v5 this is perhaps not necessary, because the slider position doesn't update if the Current Step changes; but if code is ever added to set the slider position on current step changing the same fix for the same reason is applicable here too.
@kpr0th
Copy link
Contributor Author

kpr0th commented Dec 22, 2023

I'm not really convinced by those +/- 0.00001 Can you please share the workspace you were using to test this so I can have a look too? (you'll have to zip it to attach here) Thanks

@mcallegari: I finally took some time to get back to this. I setup a bit of quick test code to run all possible values and look for corner cases. In the process I realized there were a couple of other 255's that should have been 256's. And I found a few more corner cases that I wasn't looking at before. By rounding off the "stepSize" variable to 5 decimals I was able to eliminate all of them. So I removed the +/- 0.00001's, rebased on my feature branch, and now I'm confident this is a solid fix without the hack. Will you please re-consider this pull request?

(p.s. if I somehow messed up the re-basing, let me know and I can re-create my change on a clean branch instead -- I'm not all that experienced with git yet)

(p.p.s. sorry about the multiple "Checks" runs; I didn't realize I could take the PR back to a draft state until after I was done testing, re-testing etc and creating multiple commits along the way...)

@kpr0th
Copy link
Contributor Author

kpr0th commented Dec 26, 2023

@mcallegari : you had asked for info on the issue I was trying to fix. I posted a zip file back on Feb 22 with pics showing the issue in the upstream/master, along with how my fix adjusted it. I just checked, and the original issue still exists in the latest upstream codebase. My updated commit still fixes it. In case the pictures aren't making the issue obvious enough, you can reproduce the problem using the Feb 22 workspace in v4:

Go online with the virtual console
Press play on the cuelist widget
Press "Next Cue" twice - observe that the side slider moves each time, and the number at the top also changes
Press "Previous Cue" twice - observe that the side slider only moves on the second button press, and the number at the top also doesn't change until the second button press, even though the selected cue changes both times.

Expected behavior: side slider moves every time previous or next cue is pressed, and the number at the top of the slider also changes.

Another symptom of the issue:

Go online with the virtual console
Press play on the cuelist widget
Press "Next Cue" once - observe that the 2nd cue is selected, the side slider moves down, and the top number shows 42.
Click on the side slider with your mouse, and then press the down arrow on your keyboard (or, use an external input device to send a "43" to the cuelist widget) - observe that the number changes to 43.
Then press the up arrow on your keyboard (or send in a 42 from an external input device) - observe that the number changes back to 42, and the selected cue changes to Cue 1.

Expected behavior: since 42 is the top of the 2nd cue's range, sending a 42 should stay on cue 2.

float stepSize = 255 / float(ch->stepsCount());
if (level >= 255 - stepSize)
float stepSize = 256 / float(ch->stepsCount()); //divide up the full 0..255 range
stepSize = (float)qFloor((stepSize * 100000) + 0.5) / 100000; //round to 5 decimals to fix corner cases
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stepSize is already float, so no need to cast it to float again

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep -- but the result of calling qFloor is an int, and the resulting stepSize was getting truncated. But per your request below, I changed "100000" to "100000.0" and removed the now-unnecessary casts to float.

if (stepsCount < 256)
{
stepVal = 256.0 / (float)stepsCount; //divide up the full 0..255 range
stepVal = (float)qFloor((stepVal * 100000) + 0.5) / 100000; //round to 5 decimals to fix corner cases
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above. Cast not needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same fix as above.

int lowerBound = qFloor(upperBound - stepVal);
//qDebug() << "Slider value:" << m_slider1->value() << "Step range:" << (255 - slValue) << (255 - slValue - stepVal);
int upperBound = 255 - qCeil(slValue);
int lowerBound = qFloor((float)256.0 - slValue - stepVal);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think casting to float is not needed here too since you specified .0 which the compiler interprets as float

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested successfully without the (float). Removed in new commit.

float stepSize = 255.0 / (float)ch->stepsCount();
if (value >= 255.0 - stepSize)
float stepSize = 256.0 / (float)ch->stepsCount(); //divide up the full 0..255 range
stepSize = (float)qFloor((stepSize * 100000) + 0.5) / 100000; //round to 5 decimals to fix corner cases
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cast not needed. Explicitly use 100000.0

Copy link
Contributor Author

@kpr0th kpr0th Dec 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this as per your recommendation and it works fine that way. Cast removed.

Fixed another formatting issue (space after if).
Eliminated some casts to float by adding decimals to constants.
@mcallegari
Copy link
Owner

Looks good now. Thanks 👍

@mcallegari mcallegari merged commit d9071f5 into mcallegari:master Dec 27, 2023
7 checks passed
@kpr0th kpr0th deleted the cuelist-slider-fix branch December 27, 2023 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants