Skip to content

upstream (complexlogic): Refactor SungToEnd Logic - #243

Merged
dgruss merged 3 commits into
mainfrom
fix/separate-lyric-scoring-end
Oct 28, 2026
Merged

dgruss merged 3 commits into
mainfrom
fix/separate-lyric-scoring-end

Conversation

@dgruss

@dgruss dgruss commented Oct 28, 2026 •

Copy link
Copy Markdown

Adapt UltraStar-Deluxe#1467 by @complexlogic. Trailing freestyle lyrics now use the actual final lyric line for fading, while scoring completion uses a cached final scored beat.

USCE keeps its assigned-voice handling from #181. Unassigned voices do not block completion; excluded and zero-weight notes do not extend it. Positive freestyle weights still count. The cache is rebuilt after medley trimming, and negative beats and overlapping lines are handled.

The original commit retains its author and message. USCE adaptations are a separate commit by Daniel Gruss.

Native parser regression fixtures pass for freestyle tails, eight voices, scoring weights, no-score tracks, negative beats, overlapping lines and medley exclusions. Actual game playback with an isolated synthetic song confirms completion stays false during the scored note, becomes true while the freestyle tail is still visible, and the tail then fades out. Temporary capture hooks are removed.

Main / PR comparison

Rechecked main 21bd3d5d against runtime commit 528d33e5 with synthetic PCM through the actual pitch detector, normal scoring and separate SQLite databases. Scores were earned by detection, not assigned by the harness.

Case Main This PR
Solo, Escape during freestyle tail 1 score, 10000 Identical
Duet, Escape before the second voice finishes No saved scores despite earned points Identical
Duet, Escape after both scored parts finish 2 scores, 10000 each Identical
Duet, natural audio ending 2 scores, 10000 each Identical
Eight voices, singers assigned to voices 1 and 8; other voices finish later Only the 2 assigned scores saved, correct track masks Identical

The separate #244 clipping reproduction was also run on both versions: 12-second audio excludes the note and earns zero; 30-second audio retains it and earns 10000. That failure predates this PR.

All 14 runs exited normally. The previously captured freestyle-tail fade is unchanged. Temporary PCM/input hooks are removed; normal executables were rebuilt. These are controlled synthetic-input checks, not a claim of human microphone testing.

Configurable scoring weights

Completion follows the scoring weights from #57. A freestyle note with positive weight counts; a normal note with zero weight does not. Excluded notes stay excluded even when freestyle has positive weight.

14 additional controlled game runs compared main and this PR using actual pitch detection and saved highscores:

Final notes Result in both versions
Freestyle, weight 0 Completion after the earlier scored part; 10000 saved
Freestyle, positive weight, aborted before its end No highscore saved
Freestyle, positive weight, finished 10000 saved
Normal or rap, weight 0 Completion after the earlier scored part; 10000 saved
Duet with a zero-weight tail on one voice and positive-weight freestyle on the other Waits for both assigned scoring parts; early abort saves nothing, finishing saves both scores

The regression test additionally covers every note type at zero and positive weight, mixed scored/unscored notes in the final line, multiple non-scoring final lines, and medley-excluded freestyle with positive weight. All passed. Saved score results matched main in every game case. The additional commit only extends tests; runtime code is unchanged.

Original description

The logic that determines whether a song was sung to the end is unnecessarily complicated and is proving to be a maintenance burden. At least two recent attempts to modify it have resulted in bugs (UltraStar-Deluxe#1060, UltraStar-Deluxe#1466).

This PR simplifies the logic significantly. A new variable in TLines stores the highest beat that is scored during a song. It is calculated once during the song load, as opposed to the current method of recalculating it on every single draw call.

The new SungToEnd logic is harmonized so that it works for both duets and non-duets alike. This is an improvement over the current code where there is separate logic for duets and non-duets.

The behavior of the TLine.LastLine variable is reverted back to how it was before UltraStar-Deluxe#1003, so that it is always set on the actual last line of the song regardless of whether it contains scored notes or not. The current variable name is misleading with respect to its behavior, which was the root cause of UltraStar-Deluxe#1466. This also fixes a small bug where the lyric display doesn't fade out at the end of the song if the last line is all freestyle notes.

Fixes UltraStar-Deluxe#1466

@dgruss
dgruss marked this pull request as ready for review October 28, 2026 20:40
@dgruss
dgruss merged commit d7b8e53 into main Oct 28, 2026
7 checks passed
@dgruss
dgruss deleted the fix/separate-lyric-scoring-end branch October 28, 2026 21:20
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.

Duet High Scores Not Saving On Some Songs

2 participants