Fix skipped notes at tempos above 20 ticks per second - #130
Open
zishounekonanoda wants to merge 5 commits into
Open
Fix skipped notes at tempos above 20 ticks per second#130zishounekonanoda wants to merge 5 commits into
zishounekonanoda wants to merge 5 commits into
Conversation
zishounekonanoda
marked this pull request as ready for review
August 11, 2026 17:14
This was referenced Aug 11, 2026
|
Author
Before/after playback comparisonThis video compares the same NBS playback before and after #130 in my own test environments. Order:
The full playback is included for each recording. The audio volume and timing were not edited. These results are specific to my environments and are not intended to claim that every Paper or Purpur server will reproduce the same behavior. NoteBlockAPI-PR130-full-comparison.mp4 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
doSyncimmediately when already on the primary thread so cancellable playback events are observed before playback control flow continuesRoot cause
The previous implementation advanced the mutable
tickfield in an asynchronous loop and then queued playback on the server thread:At song tempos above the server's 20 ticks per second, the asynchronous loop could advance
tickmultiple times before the server thread processed the queued callbacks. Those callbacks then read the same newer field value instead of the value from the iteration that scheduled them. Intermediate song ticks, including their notes and tick notifications, were therefore skipped.An intermediate version used measured wall-clock time in the synchronous scheduler callback. That preserved song ticks, but normal callback jitter around the 50 ms boundary could turn a 20 TPS cadence into zero song ticks in one callback and two in the next. This sounded like a brief stall followed by a catch-up burst even while average TPS and MSPT were healthy.
The final playback clock advances by
songTicksPerSecond / 20for each logical server tick. This makes 20 TPS playback exactly one song tick per server tick and avoids converting scheduler timing jitter into audible stalls. Fractional and high tempos retain their accumulated remainder, so no due song tick is discarded.Extended-octave regression
Moving note playback directly onto the synchronous playback task also exposed an existing fine-pitch arithmetic bug in the 10-octave path. Java's truncating division represented a note such as key 33 with a -30 cent offset as key 33 and remainder -30, causing
getPitchInOctaveto accesspitches[-30]. The exception aborted the remaining notes in that song tick and sounded like random cutting out even at ordinary tempos.Using
Math.floorDivandMath.floorModrepresents the same note as key 32 with a +70 cent offset. This selects the previous octave sample and preserves the intended absolute pitch.Observed behavior in the reporter's environments
The following observations come from the reporter's own servers and should not be read as a claim that every Paper- or Purpur-based server will show the same symptom:
enable10octave: trueconfiguration consistently exposedArrayIndexOutOfBoundsException: Index -30at octave sample boundaries. The pitch arithmetic itself was not introduced by this pull request, but the failure became observable after the playback path changed, so the fine-pitch normalization is included here as a regression companion to the scheduler change.These are environment-specific reproduction results. Server load, implementation, configuration, and scheduler timing may change how the underlying problem sounds.
Timing behavior
Bukkit schedules synchronous tasks in server ticks and cannot provide sub-tick sound spacing. Songs above 20 ticks per second therefore dispatch multiple ordered song ticks during some server ticks. If the server itself falls below 20 TPS, playback follows server time instead of emitting a wall-clock catch-up burst after the delay.
Related reports
Spliterash/MusicBox#27 reports choppy playback and sounds randomly cutting out with NoteBlockAPI 1.x, especially with the extended octave range. The negative fine-pitch fix addresses one concrete cause of that symptom. The broader NoteBlockAPI 2.0 migration topics in that issue remain separate.
Compatibility
The public API and Java 8 source target remain unchanged. Bukkit playback calls stay on the primary thread.
Validation
./mvnw.cmd clean packageon JDK 21 with the project's Java 8 source/target settingsFixes #116