1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-29 05:52:56 +08:00

Reverse inheritance order of SkinnableSound's pause logic

This commit is contained in:
Dean Herbert 2020-09-30 15:45:14 +09:00
parent 59ce9fcab9
commit 414c40d298
10 changed files with 91 additions and 79 deletions

View File

@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Tracking.BindValueChanged(updateSlidingSample); Tracking.BindValueChanged(updateSlidingSample);
} }
private SkinnableSound slidingSample; private PausableSkinnableSound slidingSample;
protected override void LoadSamples() protected override void LoadSamples()
{ {
@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample); var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
clone.Name = "sliderslide"; clone.Name = "sliderslide";
AddInternal(slidingSample = new SkinnableSound(clone) AddInternal(slidingSample = new PausableSkinnableSound(clone)
{ {
Looping = true Looping = true
}); });

View File

@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
isSpinning.BindValueChanged(updateSpinningSample); isSpinning.BindValueChanged(updateSpinningSample);
} }
private SkinnableSound spinningSample; private PausableSkinnableSound spinningSample;
private const float spinning_sample_initial_frequency = 1.0f; private const float spinning_sample_initial_frequency = 1.0f;
private const float spinning_sample_modulated_base_frequency = 0.5f; private const float spinning_sample_modulated_base_frequency = 0.5f;
@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample); var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
clone.Name = "spinnerspin"; clone.Name = "spinnerspin";
AddInternal(spinningSample = new SkinnableSound(clone) AddInternal(spinningSample = new PausableSkinnableSound(clone)
{ {
Volume = { Value = 0 }, Volume = { Value = 0 },
Looping = true, Looping = true,

View File

@ -42,9 +42,9 @@ namespace osu.Game.Rulesets.Taiko.Audio
} }
} }
private SkinnableSound addSound(HitSampleInfo hitSampleInfo, double lifetimeStart, double lifetimeEnd) private PausableSkinnableSound addSound(HitSampleInfo hitSampleInfo, double lifetimeStart, double lifetimeEnd)
{ {
var drawable = new SkinnableSound(hitSampleInfo) var drawable = new PausableSkinnableSound(hitSampleInfo)
{ {
LifetimeStart = lifetimeStart, LifetimeStart = lifetimeStart,
LifetimeEnd = lifetimeEnd LifetimeEnd = lifetimeEnd
@ -57,8 +57,8 @@ namespace osu.Game.Rulesets.Taiko.Audio
public class DrumSample public class DrumSample
{ {
public SkinnableSound Centre; public PausableSkinnableSound Centre;
public SkinnableSound Rim; public PausableSkinnableSound Rim;
} }
} }
} }

View File

@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private GameplayClock gameplayClock = new GameplayClock(new FramedClock()); private GameplayClock gameplayClock = new GameplayClock(new FramedClock());
private TestSkinSourceContainer skinSource; private TestSkinSourceContainer skinSource;
private SkinnableSound skinnableSound; private PausableSkinnableSound skinnableSound;
[SetUp] [SetUp]
public void SetUp() => Schedule(() => public void SetUp() => Schedule(() =>
@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
Clock = gameplayClock, Clock = gameplayClock,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = skinnableSound = new SkinnableSound(new SampleInfo("normal-sliderslide")) Child = skinnableSound = new PausableSkinnableSound(new SampleInfo("normal-sliderslide"))
}, },
}; };
}); });

View File

@ -52,10 +52,10 @@ namespace osu.Game.Rulesets.Mods
public class NightcoreBeatContainer : BeatSyncedContainer public class NightcoreBeatContainer : BeatSyncedContainer
{ {
private SkinnableSound hatSample; private PausableSkinnableSound hatSample;
private SkinnableSound clapSample; private PausableSkinnableSound clapSample;
private SkinnableSound kickSample; private PausableSkinnableSound kickSample;
private SkinnableSound finishSample; private PausableSkinnableSound finishSample;
private int? firstBeat; private int? firstBeat;
@ -69,10 +69,10 @@ namespace osu.Game.Rulesets.Mods
{ {
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
hatSample = new SkinnableSound(new SampleInfo("nightcore-hat")), hatSample = new PausableSkinnableSound(new SampleInfo("nightcore-hat")),
clapSample = new SkinnableSound(new SampleInfo("nightcore-clap")), clapSample = new PausableSkinnableSound(new SampleInfo("nightcore-clap")),
kickSample = new SkinnableSound(new SampleInfo("nightcore-kick")), kickSample = new PausableSkinnableSound(new SampleInfo("nightcore-kick")),
finishSample = new SkinnableSound(new SampleInfo("nightcore-finish")), finishSample = new PausableSkinnableSound(new SampleInfo("nightcore-finish")),
}; };
} }

View File

@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// </summary> /// </summary>
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>(Color4.Gray); public readonly Bindable<Color4> AccentColour = new Bindable<Color4>(Color4.Gray);
protected SkinnableSound Samples { get; private set; } protected PausableSkinnableSound Samples { get; private set; }
public virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples; public virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples;
@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
} }
Samples = new SkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s))); Samples = new PausableSkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)));
AddInternal(Samples); AddInternal(Samples);
} }

View File

@ -8,7 +8,7 @@ namespace osu.Game.Screens.Play
{ {
/// <summary> /// <summary>
/// Allows a component to disable sample playback dynamically as required. /// Allows a component to disable sample playback dynamically as required.
/// Handled by <see cref="SkinnableSound"/>. /// Handled by <see cref="PausableSkinnableSound"/>.
/// </summary> /// </summary>
public interface ISamplePlaybackDisabler public interface ISamplePlaybackDisabler
{ {

View File

@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke()); AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke()); AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
AddInternal(pauseLoop = new UnpausableSkinnableSound(new SampleInfo("pause-loop")) AddInternal(pauseLoop = new SkinnableSound(new SampleInfo("pause-loop"))
{ {
Looping = true, Looping = true,
Volume = { Value = 0 } Volume = { Value = 0 }
@ -54,15 +54,5 @@ namespace osu.Game.Screens.Play
pauseLoop.VolumeTo(0, TRANSITION_DURATION, Easing.OutQuad).Finally(_ => pauseLoop.Stop()); pauseLoop.VolumeTo(0, TRANSITION_DURATION, Easing.OutQuad).Finally(_ => pauseLoop.Stop());
} }
private class UnpausableSkinnableSound : SkinnableSound
{
protected override bool PlayWhenPaused => true;
public UnpausableSkinnableSound(SampleInfo sampleInfo)
: base(sampleInfo)
{
}
}
} }
} }

View File

@ -0,0 +1,66 @@
// 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.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Audio;
using osu.Game.Screens.Play;
namespace osu.Game.Skinning
{
public class PausableSkinnableSound : SkinnableSound
{
protected bool RequestedPlaying { get; private set; }
public PausableSkinnableSound(ISampleInfo hitSamples)
: base(hitSamples)
{
}
public PausableSkinnableSound(IEnumerable<ISampleInfo> hitSamples)
: base(hitSamples)
{
}
private readonly IBindable<bool> samplePlaybackDisabled = new Bindable<bool>();
[BackgroundDependencyLoader(true)]
private void load(ISamplePlaybackDisabler samplePlaybackDisabler)
{
// if in a gameplay context, pause sample playback when gameplay is paused.
if (samplePlaybackDisabler != null)
{
samplePlaybackDisabled.BindTo(samplePlaybackDisabler.SamplePlaybackDisabled);
samplePlaybackDisabled.BindValueChanged(disabled =>
{
if (RequestedPlaying)
{
if (disabled.NewValue)
base.Stop();
// it's not easy to know if a sample has finished playing (to end).
// to keep things simple only resume playing looping samples.
else if (Looping)
base.Play();
}
});
}
}
public override void Play()
{
RequestedPlaying = true;
if (samplePlaybackDisabled.Value)
return;
base.Play();
}
public override void Stop()
{
RequestedPlaying = false;
base.Stop();
}
}
}

View File

@ -11,7 +11,6 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Screens.Play;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
@ -22,8 +21,6 @@ namespace osu.Game.Skinning
[Resolved] [Resolved]
private ISampleStore samples { get; set; } private ISampleStore samples { get; set; }
private bool requestedPlaying;
public override bool RemoveWhenNotAlive => false; public override bool RemoveWhenNotAlive => false;
public override bool RemoveCompletedTransforms => false; public override bool RemoveCompletedTransforms => false;
@ -37,8 +34,6 @@ namespace osu.Game.Skinning
/// </remarks> /// </remarks>
protected bool PlayWhenZeroVolume => Looping; protected bool PlayWhenZeroVolume => Looping;
protected virtual bool PlayWhenPaused => false;
private readonly AudioContainer<DrawableSample> samplesContainer; private readonly AudioContainer<DrawableSample> samplesContainer;
public SkinnableSound(ISampleInfo hitSamples) public SkinnableSound(ISampleInfo hitSamples)
@ -52,30 +47,6 @@ namespace osu.Game.Skinning
InternalChild = samplesContainer = new AudioContainer<DrawableSample>(); InternalChild = samplesContainer = new AudioContainer<DrawableSample>();
} }
private readonly IBindable<bool> samplePlaybackDisabled = new Bindable<bool>();
[BackgroundDependencyLoader(true)]
private void load(ISamplePlaybackDisabler samplePlaybackDisabler)
{
// if in a gameplay context, pause sample playback when gameplay is paused.
if (samplePlaybackDisabler != null)
{
samplePlaybackDisabled.BindTo(samplePlaybackDisabler.SamplePlaybackDisabled);
samplePlaybackDisabled.BindValueChanged(disabled =>
{
if (requestedPlaying)
{
if (disabled.NewValue && !PlayWhenPaused)
stop();
// it's not easy to know if a sample has finished playing (to end).
// to keep things simple only resume playing looping samples.
else if (Looping)
play();
}
});
}
}
private bool looping; private bool looping;
public bool Looping public bool Looping
@ -91,17 +62,8 @@ namespace osu.Game.Skinning
} }
} }
public void Play() public virtual void Play()
{ {
requestedPlaying = true;
play();
}
private void play()
{
if (samplePlaybackDisabled.Value && !PlayWhenPaused)
return;
samplesContainer.ForEach(c => samplesContainer.ForEach(c =>
{ {
if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0) if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0)
@ -109,13 +71,7 @@ namespace osu.Game.Skinning
}); });
} }
public void Stop() public virtual void Stop()
{
requestedPlaying = false;
stop();
}
private void stop()
{ {
samplesContainer.ForEach(c => c.Stop()); samplesContainer.ForEach(c => c.Stop());
} }
@ -150,7 +106,7 @@ namespace osu.Game.Skinning
// Start playback internally for the new samples if the previous ones were playing beforehand. // Start playback internally for the new samples if the previous ones were playing beforehand.
if (wasPlaying) if (wasPlaying)
play(); Play();
} }
#region Re-expose AudioContainer #region Re-expose AudioContainer