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

Split OffsetCorrectionClock out of MasterGameplayClockContainer #19836

Merged
merged 2 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 12 additions & 55 deletions osu.Game/Screens/Play/MasterGameplayClockContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncPro

private readonly WorkingBeatmap beatmap;

private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!;
private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!;
private HardwareCorrectionOffsetClock platformOffsetClock = null!;
private OffsetCorrectionClock userGlobalOffsetClock = null!;
private OffsetCorrectionClock userBeatmapOffsetClock = null!;
private OffsetCorrectionClock platformOffsetClock = null!;

private Bindable<double> userAudioOffset = null!;

private IDisposable? beatmapOffsetSubscription;
Expand All @@ -64,6 +65,10 @@ public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncPro
[Resolved]
private OsuConfigManager config { get; set; } = null!;

private readonly List<Bindable<double>> nonGameplayAdjustments = new List<Bindable<double>>();

public override IEnumerable<double> NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value);

/// <summary>
/// Create a new master gameplay clock container.
/// </summary>
Expand Down Expand Up @@ -192,11 +197,11 @@ protected override IFrameBasedClock CreateGameplayClock(IFrameBasedClock source)
{
// Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited.
// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck.
platformOffsetClock = new HardwareCorrectionOffsetClock(source, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 };
platformOffsetClock = new OffsetCorrectionClock(source, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 };

// the final usable gameplay clock with user-set offsets applied.
userGlobalOffsetClock = new HardwareCorrectionOffsetClock(platformOffsetClock, pauseFreqAdjust);
return userBeatmapOffsetClock = new HardwareCorrectionOffsetClock(userGlobalOffsetClock, pauseFreqAdjust);
userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock, pauseFreqAdjust);
return userBeatmapOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock, pauseFreqAdjust);
}

/// <summary>
Expand Down Expand Up @@ -254,55 +259,7 @@ protected override void Dispose(bool isDisposing)

ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo;
IClock IBeatSyncProvider.Clock => this;
ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;

private class HardwareCorrectionOffsetClock : FramedOffsetClock
{
private readonly BindableDouble pauseRateAdjust;

private double offset;

public new double Offset
{
get => offset;
set
{
if (value == offset)
return;

offset = value;

updateOffset();
}
}

public double RateAdjustedOffset => base.Offset;

public HardwareCorrectionOffsetClock(IClock source, BindableDouble pauseRateAdjust)
: base(source)
{
this.pauseRateAdjust = pauseRateAdjust;
}

public override void ProcessFrame()
{
base.ProcessFrame();
updateOffset();
}

private void updateOffset()
{
// changing this during the pause transform effect will cause a potentially large offset to be suddenly applied as we approach zero rate.
if (pauseRateAdjust.Value == 1)
{
// we always want to apply the same real-time offset, so it should be adjusted by the difference in playback rate (from realtime) to achieve this.
base.Offset = Offset * Rate;
}
}
}

private readonly List<Bindable<double>> nonGameplayAdjustments = new List<Bindable<double>>();

public override IEnumerable<double> NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value);
ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
}
}
53 changes: 53 additions & 0 deletions osu.Game/Screens/Play/OffsetCorrectionClock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Bindables;
using osu.Framework.Timing;

namespace osu.Game.Screens.Play
{
public class OffsetCorrectionClock : FramedOffsetClock
{
private readonly BindableDouble pauseRateAdjust;

private double offset;

public new double Offset
{
get => offset;
set
{
if (value == offset)
return;

offset = value;

updateOffset();
}
}

public double RateAdjustedOffset => base.Offset;

public OffsetCorrectionClock(IClock source, BindableDouble pauseRateAdjust)
: base(source)
{
this.pauseRateAdjust = pauseRateAdjust;
}

public override void ProcessFrame()
{
base.ProcessFrame();
updateOffset();
}

private void updateOffset()
{
// changing this during the pause transform effect will cause a potentially large offset to be suddenly applied as we approach zero rate.
if (pauseRateAdjust.Value == 1)
{
// we always want to apply the same real-time offset, so it should be adjusted by the difference in playback rate (from realtime) to achieve this.
base.Offset = Offset * Rate;
}
}
}
}