-
Notifications
You must be signed in to change notification settings - Fork 17
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
Timing drift caused by BPM changes #164
Comments
Thanks @Jumprocks1 for highlighting this issue. The time drift adds up to 0.04 seconds or 40 ms, with only bar length changes every bar, which is around 1 ms per change. Although the drift is quite small in this example, it will certainly add up to significant amount for very long songs with 100 or more bar length/BPM changes. The following table shows the Song Length shown in the Debug Info during gameplay for both Original and the Improved Compute methods (updated to 3 decimal places in seconds):
In practical terms, only Soflan-chan Long Version has audible desync near the last quarter of song when switched to using the Improved Compute Method. This is because its BPM and Bar Lengths were manually sync and adjusted using DTXCreator with audio cues from the DTXViewer (@approvedtx please correct me if I am wrong). For songs with well-known BPMs and Time-Signatures, the Improved Computed Method will resolve the de-sync issue and compatibility issue with external tools. SolutionAs mentioned by @Jumprocks1, fixing this issue will cause incompatibility with other DTXMania variants such AL since they all have the same issue and cause existing BPM/Time-signature varying charts timed using DTXViewer to not play accurately. As such, I have to decided to add a new config field in config.ini tentatively named The implementation can be found in the |
Thank you for looking at this @fisyher. I reviewed the changes for CDTX.cs in The measurements in your table also look correct. I would however recommend including another decimal place when discussing these changes, as the the difference between 10ms and 1ms is pretty large for audio. As an example, the default judgement window for a perfect is 34ms, so a 10ms drift reduces this window by a noticeable 29%. A 40ms drift completely destroys the window. For most basic simfiles though, the drift is closer to 1ms. One thing you did not mention in your comment is that the default is set to the new compute mode. I have no opinion on what the default should be, just mentioning that for anyone else who is curious. |
Thanks @Jumprocks1 for the feedback. I forgot to highlight that the measurements collected are limited to what the existing Debug Info on the UI, which always has the sound length round off to 2 decimal point in seconds. Therefore, the actual drift may not be as high as shown in the table. I will probably update Debug Info to show a few more decimals and update the comparison table to make it more accurate. As for the default value being set to the new compute mode, it is chosen as a way to encourage players & simfile authors to try out the fix as I believe it should be the way moving forward to improve authoring experience with external audio tools. Opting out of it is made easy as it is placed as the last configurable option in under System: |
Each BPM change chip (channel 08) causes all chips after it to drift by ~0.5ms. Normally this is negligible, but for charts with hundreds of BPM changes, it is a significant problem.
Here is an example chart that I put together to demonstrate the issue: issue.zip
good.dtx
has no BPM changes (just set to 137 BPM at the start). It stays in sync.bad.dtx
is the same asgood.dtx
, except it has 8 BPM changes per bar (all set to 137 BPM, so no real change). By the end of chart, it is off by ~300ms.This is caused by:
DTXmaniaNX/DTXMania/Code/Score,Song/CDTX.cs
Line 3776 in 6640a0f
That line calculates the position (in ms) of each chip. Unfortunately it uses an int cast since it stores the time in
CChip.nPlaybackTimeMs
. In my example, each BPM chip is 48 ticks apart, so the gap in ms is calculated as:Normally, the error caused by this cast isn't a problem, but for BPM chips, the casted value gets stored in
int ms
and is then added to all other chips. This causes the error to accumulate for each BPM chip. In my example, each BPM chip introduces 0.978ms of error. Across 312 BPM chips, the total error ends up being ~305ms.DTXmania AL has the exact same issue as far as I can tell.
Steps to recreate example charts
bgm.ogg
good.dtx
bad.dtx
Recommended solution
The final solution is up to whoever submits the pull request, but my recommendation is to calculate the playback time using a double instead of an int. This calculation can then be cast to an int and stored in
chip.nPlaybackTimeMs
. This would change the line I referenced above to be:int ms = 0;
would becomedouble ms = 0;
and whenever assigning to it, you would useplaybackTimeMs
instead ofchip.nPlaybackTimeMs
. For example, the case forEChannel.BPMEx
would usems = playbackTimeMs;
instead ofms = chip.nPlaybackTimeMs;
Overall I think this would only require changing ~10 lines.
Edit:
It's worth noting that we may not even want to change this. This behavior is definitely unexpected and it doesn't line up with the behavior of external tools, but changing it now would affect the timing for older simfiles. It would also create another difference between NX and AL. Simfiles timed for NX would be slightly off in AL and vice-versa.
The main reason we would want to fix this is for compatibility with other programs. If you time a song in a DAW or a MIDI editor, you would expect that timing to convert perfectly to DTXmania, but right now that is not the case as each BPM change will cause timing drift.
The text was updated successfully, but these errors were encountered: