Initial sample + samplechannel rework

This commit is contained in:
smoogipoo
2021-01-19 17:11:40 +09:00
parent e74ecebfd6
commit de9d075f94
52 changed files with 131 additions and 138 deletions

View File

@ -140,11 +140,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
return animation == null ? null : new LegacyManiaJudgementPiece(result, animation); return animation == null ? null : new LegacyManiaJudgementPiece(result, animation);
} }
public override SampleChannel GetSample(ISampleInfo sampleInfo) public override Sample GetSample(ISampleInfo sampleInfo)
{ {
// layered hit sounds never play in mania // layered hit sounds never play in mania
if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample && legacySample.IsLayered) if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample && legacySample.IsLayered)
return new SampleChannelVirtual(); return new SampleVirtual();
return Source.GetSample(sampleInfo); return Source.GetSample(sampleInfo);
} }

View File

@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests
return null; return null;
} }
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException(); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();

View File

@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null;
public SampleChannel GetSample(ISampleInfo sampleInfo) => null; public Sample GetSample(ISampleInfo sampleInfo) => null;
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => default; public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => default;
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => null; public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => null;

View File

@ -130,7 +130,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
if (tracking.NewValue) if (tracking.NewValue)
{ {
spinningSample?.Play(!spinningSample.IsPlaying); if (!spinningSample.IsPlaying)
spinningSample?.Play();
spinningSample?.VolumeTo(1, 300); spinningSample?.VolumeTo(1, 300);
} }
else else

View File

@ -152,7 +152,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}"); throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}");
} }
public override SampleChannel GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo)); public override Sample GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => Source.GetConfig<TLookup, TValue>(lookup); public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => Source.GetConfig<TLookup, TValue>(lookup);

View File

@ -121,7 +121,7 @@ namespace osu.Game.Tests.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{ {

View File

@ -35,7 +35,7 @@ namespace osu.Game.Tests.Gameplay
public void TestRetrieveTopLevelSample() public void TestRetrieveTopLevelSample()
{ {
ISkin skin = null; ISkin skin = null;
SampleChannel channel = null; Sample channel = null;
AddStep("create skin", () => skin = new TestSkin("test-sample", this)); AddStep("create skin", () => skin = new TestSkin("test-sample", this));
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample"))); AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample")));
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Gameplay
public void TestRetrieveSampleInSubFolder() public void TestRetrieveSampleInSubFolder()
{ {
ISkin skin = null; ISkin skin = null;
SampleChannel channel = null; Sample channel = null;
AddStep("create skin", () => skin = new TestSkin("folder/test-sample", this)); AddStep("create skin", () => skin = new TestSkin("folder/test-sample", this));
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample"))); AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample")));

View File

@ -59,7 +59,7 @@ namespace osu.Game.Tests.NonVisual.Skinning
} }
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException(); public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException(); public Sample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException(); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
} }

View File

@ -105,9 +105,9 @@ namespace osu.Game.Tests.Rulesets
IsDisposed = true; IsDisposed = true;
} }
public SampleChannel Get(string name) => null; public Sample Get(string name) => null;
public Task<SampleChannel> GetAsync(string name) => null; public Task<Sample> GetAsync(string name) => null;
public Stream GetStream(string name) => null; public Stream GetStream(string name) => null;

View File

@ -219,7 +219,7 @@ namespace osu.Game.Tests.Skins
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT);
public SampleChannel GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo); public Sample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
} }

View File

@ -3,11 +3,11 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics.Audio;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Skinning;
namespace osu.Game.Tests.Visual.Editing namespace osu.Game.Tests.Visual.Editing
{ {
@ -19,14 +19,14 @@ namespace osu.Game.Tests.Visual.Editing
public void TestSlidingSampleStopsOnSeek() public void TestSlidingSampleStopsOnSeek()
{ {
DrawableSlider slider = null; DrawableSlider slider = null;
DrawableSample[] loopingSamples = null; SkinnableSound[] loopingSamples = null;
DrawableSample[] onceOffSamples = null; SkinnableSound[] onceOffSamples = null;
AddStep("get first slider", () => AddStep("get first slider", () =>
{ {
slider = Editor.ChildrenOfType<DrawableSlider>().OrderBy(s => s.HitObject.StartTime).First(); slider = Editor.ChildrenOfType<DrawableSlider>().OrderBy(s => s.HitObject.StartTime).First();
onceOffSamples = slider.ChildrenOfType<DrawableSample>().Where(s => !s.Looping).ToArray(); onceOffSamples = slider.ChildrenOfType<SkinnableSound>().Where(s => !s.Looping).ToArray();
loopingSamples = slider.ChildrenOfType<DrawableSample>().Where(s => s.Looping).ToArray(); loopingSamples = slider.ChildrenOfType<SkinnableSound>().Where(s => s.Looping).ToArray();
}); });
AddStep("start playback", () => EditorClock.Start()); AddStep("start playback", () => EditorClock.Start());
@ -36,15 +36,15 @@ namespace osu.Game.Tests.Visual.Editing
if (!slider.Tracking.Value) if (!slider.Tracking.Value)
return false; return false;
if (!loopingSamples.Any(s => s.Playing)) if (!loopingSamples.Any(s => s.IsPlaying))
return false; return false;
EditorClock.Seek(20000); EditorClock.Seek(20000);
return true; return true;
}); });
AddAssert("non-looping samples are playing", () => onceOffSamples.Length == 4 && loopingSamples.All(s => s.Played || s.Playing)); AddAssert("non-looping samples are playing", () => onceOffSamples.Length == 4 && loopingSamples.All(s => s.IsPlayed || s.IsPlaying));
AddAssert("looping samples are not playing", () => loopingSamples.Length == 1 && loopingSamples.All(s => s.Played && !s.Playing)); AddAssert("looping samples are not playing", () => loopingSamples.Length == 1 && loopingSamples.All(s => s.IsPlayed && !s.IsPlaying));
} }
} }
} }

View File

@ -4,7 +4,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics.Audio;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu;
@ -20,14 +19,14 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestAllSamplesStopDuringSeek() public void TestAllSamplesStopDuringSeek()
{ {
DrawableSlider slider = null; DrawableSlider slider = null;
DrawableSample[] samples = null; SkinnableSound[] samples = null;
ISamplePlaybackDisabler sampleDisabler = null; ISamplePlaybackDisabler sampleDisabler = null;
AddUntilStep("get variables", () => AddUntilStep("get variables", () =>
{ {
sampleDisabler = Player; sampleDisabler = Player;
slider = Player.ChildrenOfType<DrawableSlider>().OrderBy(s => s.HitObject.StartTime).FirstOrDefault(); slider = Player.ChildrenOfType<DrawableSlider>().OrderBy(s => s.HitObject.StartTime).FirstOrDefault();
samples = slider?.ChildrenOfType<DrawableSample>().ToArray(); samples = slider?.ChildrenOfType<SkinnableSound>().ToArray();
return slider != null; return slider != null;
}); });
@ -37,7 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay
if (!slider.Tracking.Value) if (!slider.Tracking.Value)
return false; return false;
if (!samples.Any(s => s.Playing)) if (!samples.Any(s => s.IsPlaying))
return false; return false;
Player.ChildrenOfType<GameplayClockContainer>().First().Seek(40000); Player.ChildrenOfType<GameplayClockContainer>().First().Seek(40000);

View File

@ -298,7 +298,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException(); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
} }
@ -309,7 +309,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException(); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
} }
@ -321,7 +321,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException(); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();

View File

@ -43,70 +43,52 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test] [Test]
public void TestStoppedSoundDoesntResumeAfterPause() public void TestStoppedSoundDoesntResumeAfterPause()
{ {
DrawableSample sample = null; AddStep("start sample with looping", () => skinnableSound.Looping = true);
AddStep("start sample with looping", () =>
{
sample = skinnableSound.ChildrenOfType<DrawableSample>().First();
skinnableSound.Looping = true; AddUntilStep("wait for sample to start playing", () => skinnableSound.IsPlaying);
skinnableSound.Play();
});
AddUntilStep("wait for sample to start playing", () => sample.Playing);
AddStep("stop sample", () => skinnableSound.Stop()); AddStep("stop sample", () => skinnableSound.Stop());
AddUntilStep("wait for sample to stop playing", () => !sample.Playing); AddUntilStep("wait for sample to stop playing", () => !skinnableSound.IsPlaying);
AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true); AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true);
AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false); AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false);
AddWaitStep("wait a bit", 5); AddWaitStep("wait a bit", 5);
AddAssert("sample not playing", () => !sample.Playing); AddAssert("sample not playing", () => !skinnableSound.IsPlaying);
} }
[Test] [Test]
public void TestLoopingSoundResumesAfterPause() public void TestLoopingSoundResumesAfterPause()
{ {
DrawableSample sample = null; AddStep("start sample with looping", () => skinnableSound.Looping = true);
AddStep("start sample with looping", () =>
{
skinnableSound.Looping = true;
skinnableSound.Play();
sample = skinnableSound.ChildrenOfType<DrawableSample>().First();
});
AddUntilStep("wait for sample to start playing", () => sample.Playing); AddUntilStep("wait for sample to start playing", () => skinnableSound.IsPlaying);
AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true); AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true);
AddUntilStep("wait for sample to stop playing", () => !sample.Playing); AddUntilStep("wait for sample to stop playing", () => !skinnableSound.IsPlaying);
AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false); AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false);
AddUntilStep("wait for sample to start playing", () => sample.Playing); AddUntilStep("wait for sample to start playing", () => skinnableSound.IsPlaying);
} }
[Test] [Test]
public void TestNonLoopingStopsWithPause() public void TestNonLoopingStopsWithPause()
{ {
DrawableSample sample = null; AddStep("start sample", () => skinnableSound.Play());
AddStep("start sample", () =>
{
skinnableSound.Play();
sample = skinnableSound.ChildrenOfType<DrawableSample>().First();
});
AddAssert("sample playing", () => sample.Playing); AddAssert("sample playing", () => skinnableSound.IsPlaying);
AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true); AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true);
AddUntilStep("sample not playing", () => !sample.Playing); AddUntilStep("sample not playing", () => !skinnableSound.IsPlaying);
AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false); AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false);
AddAssert("sample not playing", () => !sample.Playing); AddAssert("sample not playing", () => !skinnableSound.IsPlaying);
AddAssert("sample not playing", () => !sample.Playing); AddAssert("sample not playing", () => !skinnableSound.IsPlaying);
AddAssert("sample not playing", () => !sample.Playing); AddAssert("sample not playing", () => !skinnableSound.IsPlaying);
} }
[Test] [Test]
@ -119,10 +101,10 @@ namespace osu.Game.Tests.Visual.Gameplay
sample = skinnableSound.ChildrenOfType<DrawableSample>().Single(); sample = skinnableSound.ChildrenOfType<DrawableSample>().Single();
}); });
AddAssert("sample playing", () => sample.Playing); AddAssert("sample playing", () => skinnableSound.IsPlaying);
AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true); AddStep("disable sample playback", () => skinSource.SamplePlaybackDisabled.Value = true);
AddUntilStep("wait for sample to stop playing", () => !sample.Playing); AddUntilStep("wait for sample to stop playing", () => !skinnableSound.IsPlaying);
AddStep("trigger skin change", () => skinSource.TriggerSourceChanged()); AddStep("trigger skin change", () => skinSource.TriggerSourceChanged());
@ -133,11 +115,11 @@ namespace osu.Game.Tests.Visual.Gameplay
return sample != oldSample; return sample != oldSample;
}); });
AddAssert("new sample stopped", () => !sample.Playing); AddAssert("new sample stopped", () => !skinnableSound.IsPlaying);
AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false); AddStep("enable sample playback", () => skinSource.SamplePlaybackDisabled.Value = false);
AddWaitStep("wait a bit", 5); AddWaitStep("wait a bit", 5);
AddAssert("new sample not played", () => !sample.Playing); AddAssert("new sample not played", () => !skinnableSound.IsPlaying);
} }
[Cached(typeof(ISkinSource))] [Cached(typeof(ISkinSource))]
@ -155,7 +137,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Drawable GetDrawableComponent(ISkinComponent component) => source?.GetDrawableComponent(component); public Drawable GetDrawableComponent(ISkinComponent component) => source?.GetDrawableComponent(component);
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT);
public SampleChannel GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo); public Sample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => source?.GetConfig<TLookup, TValue>(lookup); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => source?.GetConfig<TLookup, TValue>(lookup);
public void TriggerSourceChanged() public void TriggerSourceChanged()

View File

@ -18,8 +18,8 @@ namespace osu.Game.Graphics.Containers
[Cached(typeof(IPreviewTrackOwner))] [Cached(typeof(IPreviewTrackOwner))]
public abstract class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction> public abstract class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction>
{ {
private SampleChannel samplePopIn; private Sample samplePopIn;
private SampleChannel samplePopOut; private Sample samplePopOut;
protected override bool BlockNonPositionalInput => true; protected override bool BlockNonPositionalInput => true;

View File

@ -44,7 +44,7 @@ namespace osu.Game.Graphics
[Resolved] [Resolved]
private NotificationOverlay notificationOverlay { get; set; } private NotificationOverlay notificationOverlay { get; set; }
private SampleChannel shutter; private Sample shutter;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuConfigManager config, Storage storage, AudioManager audio) private void load(OsuConfigManager config, Storage storage, AudioManager audio)

View File

@ -22,8 +22,8 @@ namespace osu.Game.Graphics.UserInterface
private const int text_size = 17; private const int text_size = 17;
private const int transition_length = 80; private const int transition_length = 80;
private SampleChannel sampleClick; private Sample sampleClick;
private SampleChannel sampleHover; private Sample sampleHover;
private TextContainer text; private TextContainer text;

View File

@ -17,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface
/// </summary> /// </summary>
public class HoverClickSounds : HoverSounds public class HoverClickSounds : HoverSounds
{ {
private SampleChannel sampleClick; private Sample sampleClick;
private readonly MouseButton[] buttons; private readonly MouseButton[] buttons;
/// <summary> /// <summary>

View File

@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface
/// </summary> /// </summary>
public class HoverSounds : CompositeDrawable public class HoverSounds : CompositeDrawable
{ {
private SampleChannel sampleHover; private Sample sampleHover;
/// <summary> /// <summary>
/// Length of debounce for hover sound playback, in milliseconds. /// Length of debounce for hover sound playback, in milliseconds.

View File

@ -40,8 +40,8 @@ namespace osu.Game.Graphics.UserInterface
protected readonly Nub Nub; protected readonly Nub Nub;
private readonly OsuTextFlowContainer labelText; private readonly OsuTextFlowContainer labelText;
private SampleChannel sampleChecked; private Sample sampleChecked;
private SampleChannel sampleUnchecked; private Sample sampleUnchecked;
public OsuCheckbox() public OsuCheckbox()
{ {

View File

@ -25,7 +25,7 @@ namespace osu.Game.Graphics.UserInterface
/// </summary> /// </summary>
private const int max_decimal_digits = 5; private const int max_decimal_digits = 5;
private SampleChannel sample; private Sample sample;
private double lastSampleTime; private double lastSampleTime;
private T lastSampleValue; private T lastSampleValue;
@ -157,14 +157,14 @@ namespace osu.Game.Graphics.UserInterface
lastSampleValue = value; lastSampleValue = value;
lastSampleTime = Clock.CurrentTime; lastSampleTime = Clock.CurrentTime;
sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
var channel = sample.Play();
channel.Frequency.Value = 1 + NormalizedValue * 0.2f;
if (NormalizedValue == 0) if (NormalizedValue == 0)
sample.Frequency.Value -= 0.4f; channel.Frequency.Value -= 0.4f;
else if (NormalizedValue == 1) else if (NormalizedValue == 1)
sample.Frequency.Value += 0.4f; channel.Frequency.Value += 0.4f;
sample.Play();
} }
private void updateTooltipText(T value) private void updateTooltipText(T value)

View File

@ -23,11 +23,11 @@ namespace osu.Game.Graphics.UserInterface
{ {
public class OsuTextBox : BasicTextBox public class OsuTextBox : BasicTextBox
{ {
private readonly SampleChannel[] textAddedSamples = new SampleChannel[4]; private readonly Sample[] textAddedSamples = new Sample[4];
private SampleChannel capsTextAddedSample; private Sample capsTextAddedSample;
private SampleChannel textRemovedSample; private Sample textRemovedSample;
private SampleChannel textCommittedSample; private Sample textCommittedSample;
private SampleChannel caretMovedSample; private Sample caretMovedSample;
/// <summary> /// <summary>
/// Whether to allow playing a different samples based on the type of character. /// Whether to allow playing a different samples based on the type of character.

View File

@ -27,7 +27,7 @@ namespace osu.Game.Overlays
private Container<ChangelogContent> content; private Container<ChangelogContent> content;
private SampleChannel sampleBack; private Sample sampleBack;
private List<APIChangelogBuild> builds; private List<APIChangelogBuild> builds;

View File

@ -39,7 +39,7 @@ namespace osu.Game.Overlays
private readonly Sprite innerSpin, outerSpin; private readonly Sprite innerSpin, outerSpin;
private DrawableMedal drawableMedal; private DrawableMedal drawableMedal;
private SampleChannel getSample; private Sample getSample;
private readonly Container content; private readonly Container content;

View File

@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Mods
private readonly FillFlowContainer footerContainer; private readonly FillFlowContainer footerContainer;
private SampleChannel sampleOn, sampleOff; private Sample sampleOn, sampleOff;
public ModSelectOverlay() public ModSelectOverlay()
{ {

View File

@ -102,9 +102,9 @@ namespace osu.Game.Rulesets.UI
this.fallback = fallback; this.fallback = fallback;
} }
public SampleChannel Get(string name) => primary.Get(name) ?? fallback.Get(name); public Sample Get(string name) => primary.Get(name) ?? fallback.Get(name);
public Task<SampleChannel> GetAsync(string name) => primary.GetAsync(name) ?? fallback.GetAsync(name); public Task<Sample> GetAsync(string name) => primary.GetAsync(name) ?? fallback.GetAsync(name);
public Stream GetStream(string name) => primary.GetStream(name) ?? fallback.GetStream(name); public Stream GetStream(string name) => primary.GetStream(name) ?? fallback.GetStream(name);

View File

@ -45,8 +45,8 @@ namespace osu.Game.Screens.Menu
public ButtonSystemState VisibleState = ButtonSystemState.TopLevel; public ButtonSystemState VisibleState = ButtonSystemState.TopLevel;
private readonly Action clickAction; private readonly Action clickAction;
private SampleChannel sampleClick; private Sample sampleClick;
private SampleChannel sampleHover; private Sample sampleHover;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos);

View File

@ -81,7 +81,7 @@ namespace osu.Game.Screens.Menu
private readonly List<Button> buttonsTopLevel = new List<Button>(); private readonly List<Button> buttonsTopLevel = new List<Button>();
private readonly List<Button> buttonsPlay = new List<Button>(); private readonly List<Button> buttonsPlay = new List<Button>();
private SampleChannel sampleBack; private Sample sampleBack;
private readonly LogoTrackingContainer logoTrackingContainer; private readonly LogoTrackingContainer logoTrackingContainer;

View File

@ -18,7 +18,7 @@ namespace osu.Game.Screens.Menu
private const double delay_step_one = 2300; private const double delay_step_one = 2300;
private const double delay_step_two = 600; private const double delay_step_two = 600;
private SampleChannel welcome; private Sample welcome;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)

View File

@ -48,7 +48,7 @@ namespace osu.Game.Screens.Menu
private const int exit_delay = 3000; private const int exit_delay = 3000;
private SampleChannel seeya; private Sample seeya;
protected virtual string SeeyaSampleName => "Intro/seeya"; protected virtual string SeeyaSampleName => "Intro/seeya";

View File

@ -39,7 +39,7 @@ namespace osu.Game.Screens.Menu
private BackgroundScreenDefault background; private BackgroundScreenDefault background;
private SampleChannel welcome; private Sample welcome;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()

View File

@ -21,8 +21,8 @@ namespace osu.Game.Screens.Menu
protected override string BeatmapHash => "64e00d7022195959bfa3109d09c2e2276c8f12f486b91fcf6175583e973b48f2"; protected override string BeatmapHash => "64e00d7022195959bfa3109d09c2e2276c8f12f486b91fcf6175583e973b48f2";
protected override string BeatmapFile => "welcome.osz"; protected override string BeatmapFile => "welcome.osz";
private const double delay_step_two = 2142; private const double delay_step_two = 2142;
private SampleChannel welcome; private Sample welcome;
private SampleChannel pianoReverb; private Sample pianoReverb;
protected override string SeeyaSampleName => "Intro/Welcome/seeya"; protected override string SeeyaSampleName => "Intro/Welcome/seeya";
protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false) protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false)
@ -56,12 +56,13 @@ namespace osu.Game.Screens.Menu
{ {
PrepareMenuLoad(); PrepareMenuLoad();
intro.LogoVisualisation.AddAmplitudeSource(pianoReverb);
AddInternal(intro); AddInternal(intro);
welcome?.Play(); welcome?.Play();
pianoReverb?.Play();
var reverbChannel = pianoReverb?.Play();
if (reverbChannel != null)
intro.LogoVisualisation.AddAmplitudeSource(reverbChannel);
Scheduler.AddDelayed(() => Scheduler.AddDelayed(() =>
{ {

View File

@ -43,8 +43,8 @@ namespace osu.Game.Screens.Menu
private readonly IntroSequence intro; private readonly IntroSequence intro;
private SampleChannel sampleClick; private Sample sampleClick;
private SampleChannel sampleBeat; private Sample sampleBeat;
private readonly Container colourAndTriangles; private readonly Container colourAndTriangles;
private readonly Triangles triangles; private readonly Triangles triangles;

View File

@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
public override bool DisallowExternalBeatmapRulesetChanges => true; public override bool DisallowExternalBeatmapRulesetChanges => true;
private SampleChannel sampleStart; private Sample sampleStart;
[Resolved(typeof(Room), nameof(Room.Playlist))] [Resolved(typeof(Room), nameof(Room.Playlist))]
protected BindableList<PlaylistItem> Playlist { get; private set; } protected BindableList<PlaylistItem> Playlist { get; private set; }

View File

@ -39,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
private IBindable<bool> operationInProgress; private IBindable<bool> operationInProgress;
private SampleChannel sampleReadyCount; private Sample sampleReadyCount;
private readonly ButtonWithTrianglesExposed button; private readonly ButtonWithTrianglesExposed button;
@ -120,8 +120,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
if (sampleReadyCount == null) if (sampleReadyCount == null)
return; return;
sampleReadyCount.Frequency.Value = 0.77f + countReady * 0.06f; var channel = sampleReadyCount.Play();
sampleReadyCount.Play(); channel.Frequency.Value = 0.77f + countReady * 0.06f;
} }
private void updateButtonColour(bool green) private void updateButtonColour(bool green)

View File

@ -75,7 +75,7 @@ namespace osu.Game.Screens
/// </summary> /// </summary>
public virtual bool DisallowExternalBeatmapRulesetChanges => false; public virtual bool DisallowExternalBeatmapRulesetChanges => false;
private SampleChannel sampleExit; private Sample sampleExit;
protected virtual bool PlayResumeSound => true; protected virtual bool PlayResumeSound => true;

View File

@ -34,7 +34,7 @@ namespace osu.Game.Screens.Play
private const float duration = 2500; private const float duration = 2500;
private SampleChannel failSample; private Sample failSample;
public FailAnimation(DrawableRuleset drawableRuleset) public FailAnimation(DrawableRuleset drawableRuleset)
{ {

View File

@ -91,7 +91,7 @@ namespace osu.Game.Screens.Play
[Resolved] [Resolved]
private MusicController musicController { get; set; } private MusicController musicController { get; set; }
private SampleChannel sampleRestart; private Sample sampleRestart;
public BreakOverlay BreakOverlay; public BreakOverlay BreakOverlay;

View File

@ -230,7 +230,7 @@ namespace osu.Game.Screens.Play
private Box background; private Box background;
private AspectContainer aspect; private AspectContainer aspect;
private SampleChannel sampleConfirm; private Sample sampleConfirm;
public Button() public Button()
{ {

View File

@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select.Carousel
{ {
public class CarouselHeader : Container public class CarouselHeader : Container
{ {
private SampleChannel sampleHover; private Sample sampleHover;
private readonly Box hoverLayer; private readonly Box hoverLayer;

View File

@ -86,10 +86,10 @@ namespace osu.Game.Screens.Select
protected ModSelectOverlay ModSelect { get; private set; } protected ModSelectOverlay ModSelect { get; private set; }
protected SampleChannel SampleConfirm { get; private set; } protected Sample SampleConfirm { get; private set; }
private SampleChannel sampleChangeDifficulty; private Sample sampleChangeDifficulty;
private SampleChannel sampleChangeBeatmap; private Sample sampleChangeBeatmap;
private Container carouselContainer; private Container carouselContainer;

View File

@ -24,7 +24,7 @@ namespace osu.Game.Skinning
public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null;
public override SampleChannel GetSample(ISampleInfo sampleInfo) => null; public override Sample GetSample(ISampleInfo sampleInfo) => null;
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{ {

View File

@ -48,7 +48,7 @@ namespace osu.Game.Skinning
/// <param name="sampleInfo">The requested sample.</param> /// <param name="sampleInfo">The requested sample.</param>
/// <returns>A matching sample channel, or null if unavailable.</returns> /// <returns>A matching sample channel, or null if unavailable.</returns>
[CanBeNull] [CanBeNull]
SampleChannel GetSample(ISampleInfo sampleInfo); Sample GetSample(ISampleInfo sampleInfo);
/// <summary> /// <summary>
/// Retrieve a configuration value. /// Retrieve a configuration value.

View File

@ -39,7 +39,7 @@ namespace osu.Game.Skinning
return base.GetConfig<TLookup, TValue>(lookup); return base.GetConfig<TLookup, TValue>(lookup);
} }
public override SampleChannel GetSample(ISampleInfo sampleInfo) public override Sample GetSample(ISampleInfo sampleInfo)
{ {
if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy && legacy.CustomSampleBank == 0) if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy && legacy.CustomSampleBank == 0)
{ {

View File

@ -29,7 +29,7 @@ namespace osu.Game.Skinning
protected TextureStore Textures; protected TextureStore Textures;
[CanBeNull] [CanBeNull]
protected IResourceStore<SampleChannel> Samples; protected ISampleStore Samples;
/// <summary> /// <summary>
/// Whether texture for the keys exists. /// Whether texture for the keys exists.
@ -452,7 +452,7 @@ namespace osu.Game.Skinning
return null; return null;
} }
public override SampleChannel GetSample(ISampleInfo sampleInfo) public override Sample GetSample(ISampleInfo sampleInfo)
{ {
IEnumerable<string> lookupNames; IEnumerable<string> lookupNames;

View File

@ -34,14 +34,14 @@ namespace osu.Game.Skinning
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
=> Source.GetTexture(componentName, wrapModeS, wrapModeT); => Source.GetTexture(componentName, wrapModeS, wrapModeT);
public virtual SampleChannel GetSample(ISampleInfo sampleInfo) public virtual Sample GetSample(ISampleInfo sampleInfo)
{ {
if (!(sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample)) if (!(sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample))
return Source.GetSample(sampleInfo); return Source.GetSample(sampleInfo);
var playLayeredHitSounds = GetConfig<LegacySetting, bool>(LegacySetting.LayeredHitSounds); var playLayeredHitSounds = GetConfig<LegacySetting, bool>(LegacySetting.LayeredHitSounds);
if (legacySample.IsLayered && playLayeredHitSounds?.Value == false) if (legacySample.IsLayered && playLayeredHitSounds?.Value == false)
return new SampleChannelVirtual(); return new SampleVirtual();
return Source.GetSample(sampleInfo); return Source.GetSample(sampleInfo);
} }

View File

@ -67,7 +67,7 @@ namespace osu.Game.Skinning
} }
} }
public override void Play(bool restart = true) public override void Play()
{ {
cancelPendingStart(); cancelPendingStart();
RequestedPlaying = true; RequestedPlaying = true;
@ -75,7 +75,7 @@ namespace osu.Game.Skinning
if (samplePlaybackDisabled.Value) if (samplePlaybackDisabled.Value)
return; return;
base.Play(restart); base.Play();
} }
public override void Stop() public override void Stop()

View File

@ -27,6 +27,7 @@ namespace osu.Game.Skinning
private readonly AudioContainer<DrawableSample> sampleContainer; private readonly AudioContainer<DrawableSample> sampleContainer;
private ISampleInfo sampleInfo; private ISampleInfo sampleInfo;
private SampleChannel activeChannel;
[Resolved] [Resolved]
private ISampleStore sampleStore { get; set; } private ISampleStore sampleStore { get; set; }
@ -99,7 +100,7 @@ namespace osu.Game.Skinning
if (ch == null) if (ch == null)
return; return;
sampleContainer.Add(Sample = new DrawableSample(ch) { Looping = Looping }); sampleContainer.Add(Sample = new DrawableSample(ch));
// Start playback internally for the new sample if the previous one was playing beforehand. // Start playback internally for the new sample if the previous one was playing beforehand.
if (wasPlaying && Looping) if (wasPlaying && Looping)
@ -109,18 +110,26 @@ namespace osu.Game.Skinning
/// <summary> /// <summary>
/// Plays the sample. /// Plays the sample.
/// </summary> /// </summary>
/// <param name="restart">Whether to play the sample from the beginning.</param> public void Play()
public void Play(bool restart = true) => Sample?.Play(restart); {
if (Sample == null)
return;
activeChannel = Sample.Play();
activeChannel.Looping = Looping;
}
/// <summary> /// <summary>
/// Stops the sample. /// Stops the sample.
/// </summary> /// </summary>
public void Stop() => Sample?.Stop(); public void Stop() => activeChannel?.Stop();
/// <summary> /// <summary>
/// Whether the sample is currently playing. /// Whether the sample is currently playing.
/// </summary> /// </summary>
public bool Playing => Sample?.Playing ?? false; public bool Playing => activeChannel?.Playing ?? false;
public bool Played => activeChannel?.Played ?? false;
private bool looping; private bool looping;
@ -134,8 +143,8 @@ namespace osu.Game.Skinning
{ {
looping = value; looping = value;
if (Sample != null) if (activeChannel != null)
Sample.Looping = value; activeChannel.Looping = value;
} }
} }

View File

@ -19,7 +19,7 @@ namespace osu.Game.Skinning
public abstract Drawable GetDrawableComponent(ISkinComponent componentName); public abstract Drawable GetDrawableComponent(ISkinComponent componentName);
public abstract SampleChannel GetSample(ISampleInfo sampleInfo); public abstract Sample GetSample(ISampleInfo sampleInfo);
public Texture GetTexture(string componentName) => GetTexture(componentName, default, default); public Texture GetTexture(string componentName) => GetTexture(componentName, default, default);

View File

@ -171,7 +171,7 @@ namespace osu.Game.Skinning
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => CurrentSkin.Value.GetTexture(componentName, wrapModeS, wrapModeT); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => CurrentSkin.Value.GetTexture(componentName, wrapModeS, wrapModeT);
public SampleChannel GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo); public Sample GetSample(ISampleInfo sampleInfo) => CurrentSkin.Value.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => CurrentSkin.Value.GetConfig<TLookup, TValue>(lookup); public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => CurrentSkin.Value.GetConfig<TLookup, TValue>(lookup);

View File

@ -59,9 +59,9 @@ namespace osu.Game.Skinning
return fallbackSource?.GetTexture(componentName, wrapModeS, wrapModeT); return fallbackSource?.GetTexture(componentName, wrapModeS, wrapModeT);
} }
public SampleChannel GetSample(ISampleInfo sampleInfo) public Sample GetSample(ISampleInfo sampleInfo)
{ {
SampleChannel sourceChannel; Sample sourceChannel;
if (AllowSampleLookup(sampleInfo) && (sourceChannel = skin?.GetSample(sampleInfo)) != null) if (AllowSampleLookup(sampleInfo) && (sourceChannel = skin?.GetSample(sampleInfo)) != null)
return sourceChannel; return sourceChannel;

View File

@ -119,13 +119,12 @@ namespace osu.Game.Skinning
/// <summary> /// <summary>
/// Plays the samples. /// Plays the samples.
/// </summary> /// </summary>
/// <param name="restart">Whether to play the sample from the beginning.</param> public virtual void Play()
public virtual void Play(bool restart = true)
{ {
samplesContainer.ForEach(c => samplesContainer.ForEach(c =>
{ {
if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0) if (PlayWhenZeroVolume || c.AggregateVolume.Value > 0)
c.Play(restart); c.Play();
}); });
} }
@ -188,6 +187,8 @@ namespace osu.Game.Skinning
/// </summary> /// </summary>
public bool IsPlaying => samplesContainer.Any(s => s.Playing); public bool IsPlaying => samplesContainer.Any(s => s.Playing);
public bool IsPlayed => samplesContainer.Any(s => s.Played);
#endregion #endregion
} }
} }