1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 09:23:06 +08:00

Expose track from MusicController

This commit is contained in:
smoogipoo 2020-08-05 21:10:38 +09:00
parent 6e42b8219c
commit 5c05fe3988
39 changed files with 204 additions and 283 deletions

View File

@ -343,7 +343,7 @@ namespace osu.Game.Rulesets.Mania.Tests
judgementResults = new List<JudgementResult>();
});
AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrackTime == 0);
AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrack?.CurrentTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
}

View File

@ -385,7 +385,7 @@ namespace osu.Game.Rulesets.Osu.Tests
judgementResults = new List<JudgementResult>();
});
AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrackTime == 0);
AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrack?.CurrentTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
}

View File

@ -366,7 +366,7 @@ namespace osu.Game.Rulesets.Osu.Tests
judgementResults = new List<JudgementResult>();
});
AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrackTime == 0);
AddUntilStep("Beatmap at 0", () => MusicController.CurrentTrack?.CurrentTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
}

View File

@ -31,6 +31,6 @@ namespace osu.Game.Tests.Skins
public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => beatmap.Skin.GetSample(new SampleInfo("sample")) != null);
[Test]
public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => !MusicController.IsDummyDevice);
public void TestRetrieveOggTrack() => AddAssert("track is non-null", () => MusicController.CurrentTrack?.IsDummyDevice == false);
}
}

View File

@ -1,6 +1,7 @@
// 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 System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics;
@ -94,7 +95,10 @@ namespace osu.Game.Tests.Visual.Editing
base.Update();
if (musicController.TrackLoaded)
marker.X = (float)(editorClock.CurrentTime / musicController.TrackLength);
{
Debug.Assert(musicController.CurrentTrack != null);
marker.X = (float)(editorClock.CurrentTime / musicController.CurrentTrack.Length);
}
}
}

View File

@ -288,7 +288,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void confirmNoTrackAdjustments()
{
AddAssert("track has no adjustments", () => MusicController.AggregateFrequency.Value == 1);
AddAssert("track has no adjustments", () => MusicController.CurrentTrack?.AggregateFrequency.Value == 1);
}
private void restart() => AddStep("restart", () => Player.Restart());

View File

@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
mod.ApplyToTrack(MusicController);
mod.ApplyToTrack(MusicController.CurrentTrack);
InputManager.Child = container = new TestPlayerLoaderContainer(
loader = new TestPlayerLoader(() =>
@ -77,12 +77,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddStep("load dummy beatmap", () => ResetPlayer(false, () => SelectedMods.Value = new[] { new OsuModNightcore() }));
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
AddAssert("mod rate applied", () => MusicController.Rate != 1);
AddAssert("mod rate applied", () => MusicController.CurrentTrack?.Rate != 1);
AddStep("exit loader", () => loader.Exit());
AddUntilStep("wait for not current", () => !loader.IsCurrentScreen());
AddAssert("player did not load", () => !player.IsLoaded);
AddUntilStep("player disposed", () => loader.DisposalTask?.IsCompleted == true);
AddAssert("mod rate still applied", () => MusicController.Rate != 1);
AddAssert("mod rate still applied", () => MusicController.CurrentTrack?.Rate != 1);
}
[Test]

View File

@ -87,9 +87,9 @@ namespace osu.Game.Tests.Visual.Gameplay
private void restart()
{
MusicController.Reset();
MusicController.CurrentTrack?.Reset();
loadStoryboard(Beatmap.Value);
MusicController.Play(true);
MusicController.CurrentTrack?.Start();
}
private void loadStoryboard(WorkingBeatmap working)
@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual.Gameplay
storyboard.Passing = false;
storyboardContainer.Add(storyboard);
decoupledClock.ChangeSource(musicController.GetTrackClock());
decoupledClock.ChangeSource(musicController.CurrentTrack);
}
private void loadStoryboardNoVideo()
@ -127,7 +127,7 @@ namespace osu.Game.Tests.Visual.Gameplay
storyboard = sb.CreateDrawable(Beatmap.Value);
storyboardContainer.Add(storyboard);
decoupledClock.ChangeSource(musicController.GetTrackClock());
decoupledClock.ChangeSource(musicController.CurrentTrack);
}
}
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Menus
{
AddUntilStep("wait for load", () => MusicController.TrackLoaded);
AddAssert("check if menu music loops", () => MusicController.Looping);
AddAssert("check if menu music loops", () => MusicController.CurrentTrack?.Looping == true);
}
}
}

View File

@ -4,6 +4,7 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
@ -61,12 +62,12 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for fail", () => player.HasFailed);
AddUntilStep("wait for track stop", () => !MusicController.IsPlaying);
AddAssert("Ensure time before preview point", () => MusicController.CurrentTrackTime < beatmap().Metadata.PreviewTime);
AddAssert("Ensure time before preview point", () => MusicController.CurrentTrack?.CurrentTime < beatmap().Metadata.PreviewTime);
pushEscape();
AddUntilStep("wait for track playing", () => MusicController.IsPlaying);
AddAssert("Ensure time wasn't reset to preview point", () => MusicController.CurrentTrackTime < beatmap().Metadata.PreviewTime);
AddAssert("Ensure time wasn't reset to preview point", () => MusicController.CurrentTrack?.CurrentTime < beatmap().Metadata.PreviewTime);
}
[Test]
@ -76,11 +77,11 @@ namespace osu.Game.Tests.Visual.Navigation
PushAndConfirm(() => songSelect = new TestSongSelect());
AddUntilStep("wait for no track", () => MusicController.IsDummyDevice);
AddUntilStep("wait for no track", () => MusicController.CurrentTrack?.IsDummyDevice == true);
AddStep("return to menu", () => songSelect.Exit());
AddUntilStep("wait for track", () => !MusicController.IsDummyDevice && MusicController.IsPlaying);
AddUntilStep("wait for track", () => MusicController.CurrentTrack?.IsDummyDevice == false && MusicController.IsPlaying);
}
[Test]
@ -135,8 +136,8 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded);
AddStep("Seek close to end", () =>
{
Game.MusicController.SeekTo(MusicController.TrackLength - 1000);
// MusicController.Completed += () => trackCompleted = true;
Game.MusicController.SeekTo(MusicController.CurrentTrack.AsNonNull().Length - 1000);
MusicController.CurrentTrack.AsNonNull().Completed += () => trackCompleted = true;
});
AddUntilStep("Track was completed", () => trackCompleted);

View File

@ -8,6 +8,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -168,7 +169,7 @@ namespace osu.Game.Tests.Visual.UserInterface
if (timingPoints.Count == 0) return 0;
if (timingPoints[^1] == current)
return (int)Math.Ceiling((musicController.TrackLength - current.Time) / current.BeatLength);
return (int)Math.Ceiling((musicController.CurrentTrack.AsNonNull().Length - current.Time) / current.BeatLength);
return (int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength);
}

View File

@ -80,12 +80,12 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("Store track", () => currentBeatmap = Beatmap.Value);
AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000));
AddUntilStep(@"Wait for current time to update", () => musicController.CurrentTrackTime > 5000);
AddUntilStep(@"Wait for current time to update", () => musicController.CurrentTrack?.CurrentTime > 5000);
AddStep(@"Set previous", () => musicController.PreviousTrack());
AddAssert(@"Check beatmap didn't change", () => currentBeatmap == Beatmap.Value);
AddUntilStep("Wait for current time to update", () => musicController.CurrentTrackTime < 5000);
AddUntilStep("Wait for current time to update", () => musicController.CurrentTrack?.CurrentTime < 5000);
AddStep(@"Set previous", () => musicController.PreviousTrack());
AddAssert(@"Check beatmap did change", () => currentBeatmap != Beatmap.Value);

View File

@ -51,6 +51,7 @@ namespace osu.Game.Graphics.Containers
protected override void Update()
{
ITrack track = null;
IBeatmap beatmap = null;
double currentTrackTime = 0;
@ -58,11 +59,14 @@ namespace osu.Game.Graphics.Containers
EffectControlPoint effectPoint = null;
if (musicController.TrackLoaded && Beatmap.Value.BeatmapLoaded)
beatmap = Beatmap.Value.Beatmap;
if (beatmap != null && musicController.IsPlaying && musicController.TrackLength > 0)
{
currentTrackTime = musicController.CurrentTrackTime + EarlyActivationMilliseconds;
track = musicController.CurrentTrack;
beatmap = Beatmap.Value.Beatmap;
}
if (track != null && beatmap != null && musicController.IsPlaying && track.Length > 0)
{
currentTrackTime = track.CurrentTime + EarlyActivationMilliseconds;
timingPoint = beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
effectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
@ -98,7 +102,7 @@ namespace osu.Game.Graphics.Containers
return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true))
OnNewBeat(beatIndex, timingPoint, effectPoint, musicController.CurrentAmplitudes);
OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? ChannelAmplitudes.Empty);
lastBeat = beatIndex;
lastTimingPoint = timingPoint;

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -15,7 +14,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Utils;
using osu.Framework.Threading;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Input.Bindings;
using osu.Game.Overlays.OSD;
@ -26,7 +24,7 @@ namespace osu.Game.Overlays
/// <summary>
/// Handles playback of the global music track.
/// </summary>
public class MusicController : CompositeDrawable, IKeyBindingHandler<GlobalAction>, ITrack
public class MusicController : CompositeDrawable, IKeyBindingHandler<GlobalAction>
{
[Resolved]
private BeatmapManager beatmaps { get; set; }
@ -70,10 +68,7 @@ namespace osu.Game.Overlays
private readonly TrackContainer trackContainer;
[CanBeNull]
private DrawableTrack drawableTrack;
[CanBeNull]
private Track track;
public DrawableTrack CurrentTrack { get; private set; }
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
private IBindable<WeakReference<BeatmapSetInfo>> managerRemoved;
@ -116,33 +111,12 @@ namespace osu.Game.Overlays
/// <summary>
/// Returns whether the beatmap track is playing.
/// </summary>
public bool IsPlaying => drawableTrack?.IsRunning ?? false;
public bool IsPlaying => CurrentTrack?.IsRunning ?? false;
/// <summary>
/// Returns whether the beatmap track is loaded.
/// </summary>
public bool TrackLoaded => drawableTrack?.IsLoaded == true;
/// <summary>
/// Returns the current time of the beatmap track.
/// </summary>
public double CurrentTrackTime => drawableTrack?.CurrentTime ?? 0;
/// <summary>
/// Returns the length of the beatmap track.
/// </summary>
public double TrackLength => drawableTrack?.Length ?? 0;
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
=> trackContainer.AddAdjustment(type, adjustBindable);
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
=> trackContainer.RemoveAdjustment(type, adjustBindable);
public void Reset() => drawableTrack?.Reset();
[CanBeNull]
public IAdjustableClock GetTrackClock() => track;
public bool TrackLoaded => CurrentTrack?.IsLoaded == true;
private void beatmapUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakSet)
{
@ -175,7 +149,7 @@ namespace osu.Game.Overlays
seekDelegate = Schedule(() =>
{
if (!beatmap.Disabled)
drawableTrack?.Seek(position);
CurrentTrack?.Seek(position);
});
}
@ -187,7 +161,7 @@ namespace osu.Game.Overlays
{
if (IsUserPaused) return;
if (drawableTrack == null || drawableTrack.IsDummyDevice)
if (CurrentTrack == null || CurrentTrack.IsDummyDevice)
{
if (beatmap.Disabled)
return;
@ -208,13 +182,13 @@ namespace osu.Game.Overlays
{
IsUserPaused = false;
if (drawableTrack == null)
if (CurrentTrack == null)
return false;
if (restart)
drawableTrack.Restart();
CurrentTrack.Restart();
else if (!IsPlaying)
drawableTrack.Start();
CurrentTrack.Start();
return true;
}
@ -225,8 +199,8 @@ namespace osu.Game.Overlays
public void Stop()
{
IsUserPaused = true;
if (drawableTrack?.IsRunning == true)
drawableTrack.Stop();
if (CurrentTrack?.IsRunning == true)
CurrentTrack.Stop();
}
/// <summary>
@ -235,7 +209,7 @@ namespace osu.Game.Overlays
/// <returns>Whether the operation was successful.</returns>
public bool TogglePause()
{
if (drawableTrack?.IsRunning == true)
if (CurrentTrack?.IsRunning == true)
Stop();
else
Play();
@ -257,7 +231,7 @@ namespace osu.Game.Overlays
if (beatmap.Disabled)
return PreviousTrackResult.None;
var currentTrackPosition = drawableTrack?.CurrentTime;
var currentTrackPosition = CurrentTrack?.CurrentTime;
if (currentTrackPosition >= restart_cutoff_point)
{
@ -311,7 +285,7 @@ namespace osu.Game.Overlays
{
// if not scheduled, the previously track will be stopped one frame later (see ScheduleAfterChildren logic in GameBase).
// we probably want to move this to a central method for switching to a new working beatmap in the future.
Schedule(() => drawableTrack?.Restart());
Schedule(() => CurrentTrack?.Restart());
}
private WorkingBeatmap current;
@ -345,12 +319,11 @@ namespace osu.Game.Overlays
current = beatmap.NewValue;
drawableTrack?.Expire();
drawableTrack = null;
track = null;
CurrentTrack?.Expire();
CurrentTrack = null;
if (current != null)
trackContainer.Add(drawableTrack = new DrawableTrack(track = current.GetRealTrack()));
trackContainer.Add(CurrentTrack = new DrawableTrack(current.GetRealTrack()));
TrackChanged?.Invoke(current, direction);
@ -379,15 +352,15 @@ namespace osu.Game.Overlays
public void ResetTrackAdjustments()
{
if (drawableTrack == null)
if (CurrentTrack == null)
return;
drawableTrack.ResetSpeedAdjustments();
CurrentTrack.ResetSpeedAdjustments();
if (allowRateAdjustments)
{
foreach (var mod in mods.Value.OfType<IApplicableToTrack>())
mod.ApplyToTrack(drawableTrack);
mod.ApplyToTrack(CurrentTrack);
}
}
@ -442,129 +415,6 @@ namespace osu.Game.Overlays
private class TrackContainer : AudioContainer<DrawableTrack>
{
}
#region ITrack
/// <summary>
/// The volume of this component.
/// </summary>
public BindableNumber<double> Volume => drawableTrack?.Volume; // Todo: Bad
/// <summary>
/// The playback balance of this sample (-1 .. 1 where 0 is centered)
/// </summary>
public BindableNumber<double> Balance => drawableTrack?.Balance; // Todo: Bad
/// <summary>
/// Rate at which the component is played back (affects pitch). 1 is 100% playback speed, or default frequency.
/// </summary>
public BindableNumber<double> Frequency => drawableTrack?.Frequency; // Todo: Bad
/// <summary>
/// Rate at which the component is played back (does not affect pitch). 1 is 100% playback speed.
/// </summary>
public BindableNumber<double> Tempo => drawableTrack?.Tempo; // Todo: Bad
public IBindable<double> AggregateVolume => drawableTrack?.AggregateVolume; // Todo: Bad
public IBindable<double> AggregateBalance => drawableTrack?.AggregateBalance; // Todo: Bad
public IBindable<double> AggregateFrequency => drawableTrack?.AggregateFrequency; // Todo: Bad
public IBindable<double> AggregateTempo => drawableTrack?.AggregateTempo; // Todo: Bad
/// <summary>
/// Overall playback rate (1 is 100%, -1 is reversed at 100%).
/// </summary>
public double Rate => AggregateFrequency.Value * AggregateTempo.Value;
event Action ITrack.Completed
{
add
{
if (drawableTrack != null)
drawableTrack.Completed += value;
}
remove
{
if (drawableTrack != null)
drawableTrack.Completed -= value;
}
}
event Action ITrack.Failed
{
add
{
if (drawableTrack != null)
drawableTrack.Failed += value;
}
remove
{
if (drawableTrack != null)
drawableTrack.Failed -= value;
}
}
public bool Looping
{
get => drawableTrack?.Looping ?? false;
set
{
if (drawableTrack != null)
drawableTrack.Looping = value;
}
}
public bool IsDummyDevice => drawableTrack?.IsDummyDevice ?? true;
public double RestartPoint
{
get => drawableTrack?.RestartPoint ?? 0;
set
{
if (drawableTrack != null)
drawableTrack.RestartPoint = value;
}
}
double ITrack.CurrentTime => CurrentTrackTime;
double ITrack.Length
{
get => TrackLength;
set
{
if (drawableTrack != null)
drawableTrack.Length = value;
}
}
public int? Bitrate => drawableTrack?.Bitrate;
bool ITrack.IsRunning => IsPlaying;
public bool IsReversed => drawableTrack?.IsReversed ?? false;
public bool HasCompleted => drawableTrack?.HasCompleted ?? false;
void ITrack.Reset() => drawableTrack?.Reset();
void ITrack.Restart() => Play(true);
void ITrack.ResetSpeedAdjustments() => ResetTrackAdjustments();
bool ITrack.Seek(double seek)
{
SeekTo(seek);
return true;
}
void ITrack.Start() => Play();
public ChannelAmplitudes CurrentAmplitudes => drawableTrack?.CurrentAmplitudes ?? ChannelAmplitudes.Empty;
#endregion
}
public enum TrackChangeDirection

View File

@ -234,12 +234,14 @@ namespace osu.Game.Overlays
pendingBeatmapSwitch = null;
}
if (musicController.IsDummyDevice == false)
{
progressBar.EndTime = musicController.TrackLength;
progressBar.CurrentTime = musicController.CurrentTrackTime;
var track = musicController.TrackLoaded ? musicController.CurrentTrack : null;
playButton.Icon = musicController.IsPlaying ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle;
if (track?.IsDummyDevice == false)
{
progressBar.EndTime = track.Length;
progressBar.CurrentTime = track.CurrentTime;
playButton.Icon = track.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle;
}
else
{

View File

@ -1,6 +1,7 @@
// 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.Audio;
using osu.Framework.Audio.Track;
namespace osu.Game.Rulesets.Mods
@ -10,6 +11,6 @@ namespace osu.Game.Rulesets.Mods
/// </summary>
public interface IApplicableToTrack : IApplicableMod
{
void ApplyToTrack(ITrack track);
void ApplyToTrack<T>(T track) where T : ITrack, IAdjustableAudioComponent;
}
}

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
@ -27,11 +26,11 @@ namespace osu.Game.Rulesets.Mods
}, true);
}
public override void ApplyToTrack(ITrack track)
public override void ApplyToTrack<T>(T track)
{
// base.ApplyToTrack() intentionally not called (different tempo adjustment is applied)
(track as Track)?.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
(track as Track)?.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
track.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
track.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
}
}
}

View File

@ -38,11 +38,11 @@ namespace osu.Game.Rulesets.Mods
}, true);
}
public override void ApplyToTrack(ITrack track)
public override void ApplyToTrack<T>(T track)
{
// base.ApplyToTrack() intentionally not called (different tempo adjustment is applied)
(track as Track)?.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
(track as Track)?.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
track.AddAdjustment(AdjustableProperty.Frequency, freqAdjust);
track.AddAdjustment(AdjustableProperty.Tempo, tempoAdjust);
}
public void ApplyToDrawableRuleset(DrawableRuleset<TObject> drawableRuleset)

View File

@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Mods
{
public abstract BindableNumber<double> SpeedChange { get; }
public virtual void ApplyToTrack(ITrack track)
public virtual void ApplyToTrack<T>(T track) where T : ITrack, IAdjustableAudioComponent
{
(track as Track)?.AddAdjustment(AdjustableProperty.Tempo, SpeedChange);
track.AddAdjustment(AdjustableProperty.Tempo, SpeedChange);
}
public virtual void ApplyToSample(SampleChannel sample)

View File

@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mods
Precision = 0.01,
};
private Track track;
private ITrack track;
protected ModTimeRamp()
{
@ -51,9 +51,9 @@ namespace osu.Game.Rulesets.Mods
AdjustPitch.BindValueChanged(applyPitchAdjustment);
}
public void ApplyToTrack(ITrack track)
public void ApplyToTrack<T>(T track) where T : ITrack, IAdjustableAudioComponent
{
this.track = track as Track;
this.track = track;
FinalRate.TriggerChange();
AdjustPitch.TriggerChange();
@ -89,9 +89,9 @@ namespace osu.Game.Rulesets.Mods
private void applyPitchAdjustment(ValueChangedEvent<bool> adjustPitchSetting)
{
// remove existing old adjustment
track?.RemoveAdjustment(adjustmentForPitchSetting(adjustPitchSetting.OldValue), SpeedChange);
(track as IAdjustableAudioComponent)?.RemoveAdjustment(adjustmentForPitchSetting(adjustPitchSetting.OldValue), SpeedChange);
track?.AddAdjustment(adjustmentForPitchSetting(adjustPitchSetting.NewValue), SpeedChange);
(track as IAdjustableAudioComponent)?.AddAdjustment(adjustmentForPitchSetting(adjustPitchSetting.NewValue), SpeedChange);
}
private AdjustableProperty adjustmentForPitchSetting(bool adjustPitchSettingValue)

View File

@ -66,12 +66,12 @@ namespace osu.Game.Screens.Edit.Components
}
};
musicController.AddAdjustment(AdjustableProperty.Tempo, tempo);
musicController.CurrentTrack?.AddAdjustment(AdjustableProperty.Tempo, tempo);
}
protected override void Dispose(bool isDisposing)
{
musicController?.RemoveAdjustment(AdjustableProperty.Tempo, tempo);
musicController?.CurrentTrack?.RemoveAdjustment(AdjustableProperty.Tempo, tempo);
base.Dispose(isDisposing);
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osuTK;
@ -57,7 +58,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
return;
}
content.RelativeChildSize = new Vector2((float)Math.Max(1, musicController.TrackLength), 1);
Debug.Assert(musicController.CurrentTrack != null);
content.RelativeChildSize = new Vector2((float)Math.Max(1, musicController.CurrentTrack.Length), 1);
}
protected virtual void LoadBeatmap(WorkingBeatmap beatmap)

View File

@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@ -60,21 +62,20 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
Beatmap.BindValueChanged(b =>
{
waveform.Waveform = b.NewValue.Waveform;
track = musicController.CurrentTrack;
// Todo: Wrong.
Schedule(() =>
Debug.Assert(track != null);
if (track.Length > 0)
{
if (musicController.TrackLength > 0)
{
MaxZoom = getZoomLevelForVisibleMilliseconds(500);
MinZoom = getZoomLevelForVisibleMilliseconds(10000);
Zoom = getZoomLevelForVisibleMilliseconds(2000);
}
});
MaxZoom = getZoomLevelForVisibleMilliseconds(500);
MinZoom = getZoomLevelForVisibleMilliseconds(10000);
Zoom = getZoomLevelForVisibleMilliseconds(2000);
}
}, true);
}
private float getZoomLevelForVisibleMilliseconds(double milliseconds) => (float)(musicController.TrackLength / milliseconds);
private float getZoomLevelForVisibleMilliseconds(double milliseconds) => (float)(track.Length / milliseconds);
/// <summary>
/// The timeline's scroll position in the last frame.
@ -96,6 +97,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
/// </summary>
private bool trackWasPlaying;
private ITrack track;
protected override void Update()
{
base.Update();
@ -136,15 +139,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
if (!musicController.TrackLoaded)
return;
editorClock.Seek(Current / Content.DrawWidth * musicController.TrackLength);
editorClock.Seek(Current / Content.DrawWidth * track.Length);
}
private void scrollToTrackTime()
{
if (!musicController.TrackLoaded || musicController.TrackLength == 0)
if (!musicController.TrackLoaded || track.Length == 0)
return;
ScrollTo((float)(editorClock.CurrentTime / musicController.TrackLength) * Content.DrawWidth, false);
ScrollTo((float)(editorClock.CurrentTime / track.Length) * Content.DrawWidth, false);
}
protected override bool OnMouseDown(MouseDownEvent e)
@ -188,7 +191,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition))));
private double getTimeFromPosition(Vector2 localPosition) =>
(localPosition.X / Content.DrawWidth) * musicController.TrackLength;
(localPosition.X / Content.DrawWidth) * track.Length;
public float GetBeatSnapDistanceAt(double referenceTime) => throw new NotImplementedException();

View File

@ -3,6 +3,7 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Overlays;
@ -43,7 +44,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
for (var i = 0; i < beatmap.ControlPointInfo.TimingPoints.Count; i++)
{
var point = beatmap.ControlPointInfo.TimingPoints[i];
var until = i + 1 < beatmap.ControlPointInfo.TimingPoints.Count ? beatmap.ControlPointInfo.TimingPoints[i + 1].Time : musicController.TrackLength;
var until = i + 1 < beatmap.ControlPointInfo.TimingPoints.Count ? beatmap.ControlPointInfo.TimingPoints[i + 1].Time : musicController.CurrentTrack.AsNonNull().Length;
int beat = 0;

View File

@ -83,7 +83,7 @@ namespace osu.Game.Screens.Edit
beatDivisor.BindValueChanged(divisor => Beatmap.Value.BeatmapInfo.BeatDivisor = divisor.NewValue);
// Todo: should probably be done at a DrawableRuleset level to share logic with Player.
var sourceClock = musicController.GetTrackClock() ?? new StopwatchClock();
var sourceClock = (IAdjustableClock)musicController.CurrentTrack ?? new StopwatchClock();
clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
clock.ChangeSource(sourceClock);

View File

@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit
private void load()
{
// Todo: What.
TrackLength ??= musicController.TrackLength;
TrackLength ??= musicController.CurrentTrack?.Length ?? 0;
}
/// <summary>

View File

@ -113,7 +113,9 @@ namespace osu.Game.Screens.Menu
if (setInfo != null)
{
initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
UsingThemedIntro = !MusicController.IsDummyDevice;
// Todo: Wrong.
UsingThemedIntro = MusicController.CurrentTrack?.IsDummyDevice == false;
}
return UsingThemedIntro;

View File

@ -59,7 +59,7 @@ namespace osu.Game.Screens.Menu
LoadComponentAsync(new TrianglesIntroSequence(logo, background)
{
RelativeSizeAxes = Axes.Both,
Clock = new FramedClock(UsingThemedIntro ? MusicController.GetTrackClock() : null),
Clock = new FramedClock(UsingThemedIntro ? MusicController.CurrentTrack : null),
LoadMenu = LoadMenu
}, t =>
{

View File

@ -44,7 +44,8 @@ namespace osu.Game.Screens.Menu
pianoReverb = audio.Samples.Get(@"Intro/Welcome/welcome_piano");
musicController.Looping = true;
if (musicController.CurrentTrack != null)
musicController.CurrentTrack.Looping = true;
}
protected override void LogoArriving(OsuLogo logo, bool resuming)

View File

@ -19,6 +19,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Utils;
using osu.Game.Overlays;
@ -108,14 +109,14 @@ namespace osu.Game.Screens.Menu
private void updateAmplitudes()
{
var effect = beatmap.Value.BeatmapLoaded && musicController.TrackLoaded
? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(musicController.CurrentTrackTime)
? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(musicController.CurrentTrack.AsNonNull().CurrentTime)
: null;
for (int i = 0; i < temporalAmplitudes.Length; i++)
temporalAmplitudes[i] = 0;
if (musicController.TrackLoaded)
addAmplitudesFromSource(musicController);
addAmplitudesFromSource(musicController.CurrentTrack.AsNonNull());
foreach (var source in amplitudeSources)
addAmplitudesFromSource(source);

View File

@ -1,6 +1,7 @@
// 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 System.Diagnostics;
using System.Linq;
using osuTK;
using osuTK.Graphics;
@ -181,11 +182,12 @@ namespace osu.Game.Screens.Menu
if (last is IntroScreen && musicController.TrackLoaded)
{
// Todo: Wrong.
if (!musicController.IsPlaying)
Debug.Assert(musicController.CurrentTrack != null);
if (!musicController.CurrentTrack.IsRunning)
{
musicController.SeekTo(metadata.PreviewTime != -1 ? metadata.PreviewTime : 0.4f * musicController.TrackLength);
musicController.Play();
musicController.CurrentTrack.Seek(metadata.PreviewTime != -1 ? metadata.PreviewTime : 0.4f * musicController.CurrentTrack.Length);
musicController.CurrentTrack.Start();
}
}

View File

@ -330,9 +330,9 @@ namespace osu.Game.Screens.Menu
const float velocity_adjust_cutoff = 0.98f;
const float paused_velocity = 0.5f;
if (musicController.IsPlaying)
if (musicController.CurrentTrack?.IsRunning == true)
{
var maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentAmplitudes.Maximum : 0;
var maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentTrack.CurrentAmplitudes.Maximum : 0;
logoAmplitudeContainer.Scale = new Vector2((float)Interpolation.Damp(logoAmplitudeContainer.Scale.X, 1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 0.9f, Time.Elapsed));
if (maxAmplitude > velocity_adjust_cutoff)

View File

@ -104,7 +104,7 @@ namespace osu.Game.Screens.Multi.Match.Components
return;
}
bool hasEnoughTime = DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(musicController.TrackLength) < endDate.Value;
bool hasEnoughTime = musicController.CurrentTrack != null && DateTimeOffset.UtcNow.AddSeconds(30).AddMilliseconds(musicController.CurrentTrack.Length) < endDate.Value;
Enabled.Value = hasBeatmap && hasEnoughTime;
}

View File

@ -343,9 +343,13 @@ namespace osu.Game.Screens.Multi
{
if (screenStack.CurrentScreen is MatchSubScreen)
{
musicController.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
musicController.Looping = true;
musicController.EnsurePlayingSomething();
if (musicController.CurrentTrack != null)
{
musicController.CurrentTrack.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
musicController.CurrentTrack.Looping = true;
musicController.EnsurePlayingSomething();
}
}
else
{
@ -355,8 +359,11 @@ namespace osu.Game.Screens.Multi
private void cancelLooping()
{
musicController.Looping = false;
musicController.RestartPoint = 0;
if (musicController.CurrentTrack != null)
{
musicController.CurrentTrack.Looping = false;
musicController.CurrentTrack.RestartPoint = 0;
}
}
protected override void Dispose(bool isDisposing)

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
@ -30,21 +31,21 @@ namespace osu.Game.Screens.Play
private readonly BindableDouble trackFreq = new BindableDouble(1);
private DrawableTrack track;
private const float duration = 2500;
private SampleChannel failSample;
[Resolved]
private MusicController musicController { get; set; }
public FailAnimation(DrawableRuleset drawableRuleset)
{
this.drawableRuleset = drawableRuleset;
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap)
private void load(AudioManager audio, IBindable<WorkingBeatmap> beatmap, MusicController musicController)
{
track = musicController.CurrentTrack;
failSample = audio.Samples.Get(@"Gameplay/failsound");
}
@ -68,7 +69,7 @@ namespace osu.Game.Screens.Play
Expire();
});
musicController.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
track.AddAdjustment(AdjustableProperty.Frequency, trackFreq);
applyToPlayfield(drawableRuleset.Playfield);
drawableRuleset.Playfield.HitObjectContainer.FlashColour(Color4.Red, 500);
@ -107,7 +108,7 @@ namespace osu.Game.Screens.Play
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
musicController?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);
track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq);
}
}
}

View File

@ -8,8 +8,10 @@ using System.Threading.Tasks;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
@ -27,8 +29,7 @@ namespace osu.Game.Screens.Play
private readonly WorkingBeatmap beatmap;
private readonly IReadOnlyList<Mod> mods;
[Resolved]
private MusicController musicController { get; set; }
private DrawableTrack track;
public readonly BindableBool IsPaused = new BindableBool();
@ -95,8 +96,10 @@ namespace osu.Game.Screens.Play
private readonly BindableDouble pauseFreqAdjust = new BindableDouble(1);
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
private void load(OsuConfigManager config, MusicController musicController)
{
track = musicController.CurrentTrack;
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
userAudioOffset.BindValueChanged(offset => userOffsetClock.Offset = offset.NewValue, true);
@ -121,15 +124,15 @@ namespace osu.Game.Screens.Play
{
// The Reset() call below causes speed adjustments to be reset in an async context, leading to deadlocks.
// The deadlock can be prevented by resetting the track synchronously before entering the async context.
musicController.Reset();
track.ResetSpeedAdjustments();
Task.Run(() =>
{
musicController.Reset();
track.Reset();
Schedule(() =>
{
adjustableClock.ChangeSource(musicController.GetTrackClock());
adjustableClock.ChangeSource(track);
updateRate();
if (!IsPaused.Value)
@ -190,6 +193,20 @@ namespace osu.Game.Screens.Play
IsPaused.Value = true;
}
/// <summary>
/// Changes the backing clock to avoid using the originally provided track.
/// </summary>
public void StopUsingBeatmapClock()
{
if (track == null)
return;
removeSourceClockAdjustments();
track = new DrawableTrack(new TrackVirtual(track.Length));
adjustableClock.ChangeSource(track);
}
protected override void Update()
{
if (!IsPaused.Value)
@ -202,23 +219,30 @@ namespace osu.Game.Screens.Play
private void updateRate()
{
if (track == null) return;
speedAdjustmentsApplied = true;
musicController.ResetTrackAdjustments();
musicController.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
musicController.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate);
track.ResetSpeedAdjustments();
track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate);
foreach (var mod in mods.OfType<IApplicableToTrack>())
mod.ApplyToTrack(track);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
removeSourceClockAdjustments();
track = null;
}
private void removeSourceClockAdjustments()
{
if (speedAdjustmentsApplied)
{
musicController.ResetTrackAdjustments();
track.ResetSpeedAdjustments();
speedAdjustmentsApplied = false;
}
}

View File

@ -31,6 +31,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Bindings;
using osu.Game.Graphics.UserInterface;
@ -560,9 +561,9 @@ namespace osu.Game.Screens.Select
BeatmapDetails.Refresh();
if (music != null)
if (music?.CurrentTrack != null)
{
music.Looping = true;
music.CurrentTrack.Looping = true;
music.ResetTrackAdjustments();
}
@ -588,8 +589,8 @@ namespace osu.Game.Screens.Select
BeatmapOptions.Hide();
if (music != null)
music.Looping = false;
if (music?.CurrentTrack != null)
music.CurrentTrack.Looping = false;
this.ScaleTo(1.1f, 250, Easing.InSine);
@ -610,8 +611,8 @@ namespace osu.Game.Screens.Select
FilterControl.Deactivate();
if (music != null)
music.Looping = false;
if (music?.CurrentTrack != null)
music.CurrentTrack.Looping = false;
return false;
}
@ -652,18 +653,30 @@ namespace osu.Game.Screens.Select
BeatmapDetails.Beatmap = beatmap;
if (music != null)
music.Looping = false;
if (music?.CurrentTrack != null)
music.CurrentTrack.Looping = false;
}
private readonly WeakReference<ITrack> lastTrack = new WeakReference<ITrack>(null);
/// <summary>
/// Ensures some music is playing for the current track.
/// Will resume playback from a manual user pause if the track has changed.
/// </summary>
private void ensurePlayingSelected()
{
music.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
music.EnsurePlayingSomething();
ITrack track = music?.CurrentTrack;
if (track == null)
return;
bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track;
track.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
if (!track.IsRunning && (music?.IsUserPaused != true || isNewTrack))
music?.Play(true);
lastTrack.SetTarget(track);
}
private void carouselBeatmapsLoaded()

View File

@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> e)
{
Clock.ControlPointInfo = e.NewValue.Beatmap.ControlPointInfo;
Clock.ChangeSource(MusicController.GetTrackClock() ?? new StopwatchClock());
Clock.ChangeSource((IAdjustableClock)MusicController.CurrentTrack ?? new StopwatchClock());
Clock.ProcessFrame();
}

View File

@ -1,6 +1,8 @@
// 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.Extensions.ObjectExtensions;
namespace osu.Game.Tests.Visual
{
/// <summary>
@ -13,7 +15,7 @@ namespace osu.Game.Tests.Visual
base.Update();
// note that this will override any mod rate application
MusicController.Tempo.Value = Clock.Rate;
MusicController.CurrentTrack.AsNonNull().Tempo.Value = Clock.Rate;
}
}
}