diff --git a/osu.Game/Beatmaps/IBeatSyncProvider.cs b/osu.Game/Beatmaps/IBeatSyncProvider.cs
index 362f02f2dd..b0b265c228 100644
--- a/osu.Game/Beatmaps/IBeatSyncProvider.cs
+++ b/osu.Game/Beatmaps/IBeatSyncProvider.cs
@@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
-using osu.Framework.Audio.Track;
+using osu.Framework.Audio;
using osu.Framework.Timing;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.Containers;
@@ -14,12 +14,21 @@ namespace osu.Game.Beatmaps
/// Primarily intended for use with .
///
[Cached]
- public interface IBeatSyncProvider
+ public interface IBeatSyncProvider : IHasAmplitudes
{
+ ///
+ /// Check whether beat sync is currently available.
+ ///
+ public bool BeatSyncAvailable => Clock != null;
+
+ ///
+ /// Access any available control points from a beatmap providing beat sync. If null, no current provider is available.
+ ///
ControlPointInfo? ControlPoints { get; }
+ ///
+ /// Access a clock currently responsible for providing beat sync. If null, no current provider is available.
+ ///
IClock? Clock { get; }
-
- ChannelAmplitudes? Amplitudes { get; }
}
}
diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
index e1998a1d7f..774468c344 100644
--- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
+++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Diagnostics;
using osu.Framework.Allocation;
@@ -10,13 +8,12 @@ using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Screens.Play;
namespace osu.Game.Graphics.Containers
{
///
/// A container which fires a callback when a new beat is reached.
- /// Consumes a parent or (whichever is first available).
+ /// Consumes a parent .
///
///
/// This container does not set its own clock to the source used for beat matching.
@@ -28,8 +25,9 @@ namespace osu.Game.Graphics.Containers
public class BeatSyncedContainer : Container
{
private int lastBeat;
- protected TimingControlPoint LastTimingPoint { get; private set; }
- protected EffectControlPoint LastEffectPoint { get; private set; }
+
+ protected TimingControlPoint? LastTimingPoint { get; private set; }
+ protected EffectControlPoint? LastEffectPoint { get; private set; }
///
/// The amount of time before a beat we should fire .
@@ -71,12 +69,12 @@ namespace osu.Game.Graphics.Containers
public double MinimumBeatLength { get; set; }
///
- /// Whether this container is currently tracking a beatmap's timing data.
+ /// Whether this container is currently tracking a beat sync provider.
///
protected bool IsBeatSyncedWithTrack { get; private set; }
[Resolved]
- protected IBeatSyncProvider BeatSyncSource { get; private set; }
+ protected IBeatSyncProvider BeatSyncSource { get; private set; } = null!;
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
{
@@ -87,19 +85,18 @@ namespace osu.Game.Graphics.Containers
TimingControlPoint timingPoint;
EffectControlPoint effectPoint;
- IsBeatSyncedWithTrack = BeatSyncSource.Clock?.IsRunning == true && BeatSyncSource.ControlPoints != null;
+ IsBeatSyncedWithTrack = BeatSyncSource.BeatSyncAvailable && BeatSyncSource.Clock?.IsRunning == true;
double currentTrackTime;
if (IsBeatSyncedWithTrack)
{
- Debug.Assert(BeatSyncSource.ControlPoints != null);
Debug.Assert(BeatSyncSource.Clock != null);
currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds;
- timingPoint = BeatSyncSource.ControlPoints.TimingPointAt(currentTrackTime);
- effectPoint = BeatSyncSource.ControlPoints.EffectPointAt(currentTrackTime);
+ timingPoint = BeatSyncSource.ControlPoints?.TimingPointAt(currentTrackTime) ?? TimingControlPoint.DEFAULT;
+ effectPoint = BeatSyncSource.ControlPoints?.EffectPointAt(currentTrackTime) ?? EffectControlPoint.DEFAULT;
}
else
{
@@ -136,7 +133,7 @@ namespace osu.Game.Graphics.Containers
if (AllowMistimedEventFiring || Math.Abs(TimeSinceLastBeat) < MISTIMED_ALLOWANCE)
{
using (BeginDelayedSequence(-TimeSinceLastBeat))
- OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.Amplitudes ?? ChannelAmplitudes.Empty);
+ OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.CurrentAmplitudes);
}
lastBeat = beatIndex;
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 97d15ae6ad..f62349c447 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -588,6 +588,6 @@ namespace osu.Game
ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.BeatmapLoaded ? Beatmap.Value.Beatmap.ControlPointInfo : null;
IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)null;
- ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null;
+ ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
}
}
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 9e9cd8e3b7..89f9aec5ee 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -10,6 +10,7 @@ using System.Linq;
using JetBrains.Annotations;
using osu.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -949,7 +950,7 @@ namespace osu.Game.Screens.Edit
ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo;
IClock IBeatSyncProvider.Clock => clock;
- ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null;
+ ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
private class BeatmapEditorToast : Toast
{
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index c66bd3639a..c238bf8a21 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -1,10 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
-using osuTK;
-using osuTK.Graphics;
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Track;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Batches;
using osu.Framework.Graphics.Colour;
@@ -12,16 +14,10 @@ using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
-using osu.Game.Beatmaps;
-using System;
-using System.Collections.Generic;
-using JetBrains.Annotations;
-using osu.Framework.Allocation;
-using osu.Framework.Audio;
-using osu.Framework.Audio.Track;
-using osu.Framework.Bindables;
using osu.Framework.Utils;
-using osu.Framework.Extensions.Color4Extensions;
+using osu.Game.Beatmaps;
+using osuTK;
+using osuTK.Graphics;
namespace osu.Game.Screens.Menu
{
@@ -30,8 +26,6 @@ namespace osu.Game.Screens.Menu
///
public class LogoVisualisation : Drawable
{
- private readonly IBindable beatmap = new Bindable();
-
///
/// The number of bars to jump each update iteration.
///
@@ -76,7 +70,8 @@ namespace osu.Game.Screens.Menu
private readonly float[] frequencyAmplitudes = new float[256];
- private IShader shader;
+ private IShader shader = null!;
+
private readonly Texture texture;
public LogoVisualisation()
@@ -93,32 +88,35 @@ namespace osu.Game.Screens.Menu
}
[BackgroundDependencyLoader]
- private void load(ShaderManager shaders, IBindable beatmap)
+ private void load(ShaderManager shaders)
{
- this.beatmap.BindTo(beatmap);
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
}
private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE];
+ [Resolved]
+ private IBeatSyncProvider beatSyncProvider { get; set; } = null!;
+
private void updateAmplitudes()
{
- var effect = beatmap.Value.BeatmapLoaded && beatmap.Value.TrackLoaded
- ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(beatmap.Value.Track.CurrentTime)
- : null;
+ bool isKiaiTime = false;
for (int i = 0; i < temporalAmplitudes.Length; i++)
temporalAmplitudes[i] = 0;
- if (beatmap.Value.TrackLoaded)
- addAmplitudesFromSource(beatmap.Value.Track);
+ if (beatSyncProvider.Clock != null)
+ {
+ isKiaiTime = beatSyncProvider.ControlPoints?.EffectPointAt(beatSyncProvider.Clock.CurrentTime).KiaiMode ?? false;
+ addAmplitudesFromSource(beatSyncProvider);
+ }
foreach (var source in amplitudeSources)
addAmplitudesFromSource(source);
for (int i = 0; i < bars_per_visualiser; i++)
{
- float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (effect?.KiaiMode == true ? 1 : 0.5f);
+ float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (isKiaiTime ? 1 : 0.5f);
if (targetAmplitude > frequencyAmplitudes[i])
frequencyAmplitudes[i] = targetAmplitude;
}
@@ -153,7 +151,7 @@ namespace osu.Game.Screens.Menu
protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(this);
- private void addAmplitudesFromSource([NotNull] IHasAmplitudes source)
+ private void addAmplitudesFromSource(IHasAmplitudes source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
@@ -170,8 +168,8 @@ namespace osu.Game.Screens.Menu
{
protected new LogoVisualisation Source => (LogoVisualisation)base.Source;
- private IShader shader;
- private Texture texture;
+ private IShader shader = null!;
+ private Texture texture = null!;
// Assuming the logo is a circle, we don't need a second dimension.
private float size;
@@ -209,43 +207,40 @@ namespace osu.Game.Screens.Menu
ColourInfo colourInfo = DrawColourInfo.Colour;
colourInfo.ApplyChild(transparent_white);
- if (audioData != null)
+ for (int j = 0; j < visualiser_rounds; j++)
{
- for (int j = 0; j < visualiser_rounds; j++)
+ for (int i = 0; i < bars_per_visualiser; i++)
{
- for (int i = 0; i < bars_per_visualiser; i++)
- {
- if (audioData[i] < amplitude_dead_zone)
- continue;
+ if (audioData[i] < amplitude_dead_zone)
+ continue;
- float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
- float rotationCos = MathF.Cos(rotation);
- float rotationSin = MathF.Sin(rotation);
- // taking the cos and sin to the 0..1 range
- var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
+ float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
+ float rotationCos = MathF.Cos(rotation);
+ float rotationSin = MathF.Sin(rotation);
+ // taking the cos and sin to the 0..1 range
+ var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
- var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
- // The distance between the position and the sides of the bar.
- var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
- // The distance between the bottom side of the bar and the top side.
- var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);
+ var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
+ // The distance between the position and the sides of the bar.
+ var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
+ // The distance between the bottom side of the bar and the top side.
+ var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);
- var rectangle = new Quad(
- Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
- Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
- Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
- Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
- );
+ var rectangle = new Quad(
+ Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
+ Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
+ Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
+ Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
+ );
- DrawQuad(
- texture,
- rectangle,
- colourInfo,
- null,
- vertexBatch.AddAction,
- // barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
- Vector2.Divide(inflation, barSize.Yx));
- }
+ DrawQuad(
+ texture,
+ rectangle,
+ colourInfo,
+ null,
+ vertexBatch.AddAction,
+ // barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
+ Vector2.Divide(inflation, barSize.Yx));
}
}
diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs
index cd37c541ec..d7f6992fee 100644
--- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs
+++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Linq;
@@ -53,21 +51,21 @@ namespace osu.Game.Screens.Play
private readonly WorkingBeatmap beatmap;
- private HardwareCorrectionOffsetClock userGlobalOffsetClock;
- private HardwareCorrectionOffsetClock userBeatmapOffsetClock;
- private HardwareCorrectionOffsetClock platformOffsetClock;
- private MasterGameplayClock masterGameplayClock;
- private Bindable userAudioOffset;
+ private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!;
+ private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!;
+ private HardwareCorrectionOffsetClock platformOffsetClock = null!;
+ private MasterGameplayClock masterGameplayClock = null!;
+ private Bindable userAudioOffset = null!;
- private IDisposable beatmapOffsetSubscription;
+ private IDisposable? beatmapOffsetSubscription;
private readonly double skipTargetTime;
[Resolved]
- private RealmAccess realm { get; set; }
+ private RealmAccess realm { get; set; } = null!;
[Resolved]
- private OsuConfigManager config { get; set; }
+ private OsuConfigManager config { get; set; } = null!;
///
/// Create a new master gameplay clock container.
@@ -255,7 +253,7 @@ namespace osu.Game.Screens.Play
ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo;
IClock IBeatSyncProvider.Clock => GameplayClock;
- ChannelAmplitudes? IBeatSyncProvider.Amplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : null;
+ ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty;
private class HardwareCorrectionOffsetClock : FramedOffsetClock
{