mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 09:07:25 +08:00
Add initial hit sample pooling
This commit is contained in:
parent
7f3c8ad744
commit
730b14b5bb
@ -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;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Catch.Judgements;
|
||||
@ -26,11 +27,17 @@ namespace osu.Game.Rulesets.Catch.Objects
|
||||
Samples = samples;
|
||||
}
|
||||
|
||||
private class BananaHitSampleInfo : HitSampleInfo
|
||||
private class BananaHitSampleInfo : HitSampleInfo, IEquatable<BananaHitSampleInfo>
|
||||
{
|
||||
private static string[] lookupNames { get; } = { "metronomelow", "catch-banana" };
|
||||
private static readonly string[] lookup_names = { "metronomelow", "catch-banana" };
|
||||
|
||||
public override IEnumerable<string> LookupNames => lookupNames;
|
||||
public override IEnumerable<string> LookupNames => lookup_names;
|
||||
|
||||
public bool Equals(BananaHitSampleInfo other) => true;
|
||||
|
||||
public override bool Equals(object obj) => obj is BananaHitSampleInfo other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => lookup_names.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace osu.Game.Audio
|
||||
{
|
||||
@ -10,7 +11,7 @@ namespace osu.Game.Audio
|
||||
/// Describes a gameplay hit sample.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class HitSampleInfo : ISampleInfo
|
||||
public class HitSampleInfo : ISampleInfo, IEquatable<HitSampleInfo>
|
||||
{
|
||||
public const string HIT_WHISTLE = @"hitwhistle";
|
||||
public const string HIT_FINISH = @"hitfinish";
|
||||
@ -57,5 +58,17 @@ namespace osu.Game.Audio
|
||||
}
|
||||
|
||||
public HitSampleInfo Clone() => (HitSampleInfo)MemberwiseClone();
|
||||
|
||||
public bool Equals(HitSampleInfo other)
|
||||
=> other != null && Bank == other.Bank && Name == other.Name && Suffix == other.Suffix;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is HitSampleInfo other && Equals(other);
|
||||
|
||||
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] // This will have to be addressed eventually
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Bank, Name, Suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a gameplay sample.
|
||||
/// </summary>
|
||||
public class SampleInfo : ISampleInfo
|
||||
public class SampleInfo : ISampleInfo, IEquatable<SampleInfo>
|
||||
{
|
||||
private readonly string[] sampleNames;
|
||||
|
||||
@ -20,5 +22,16 @@ namespace osu.Game.Audio
|
||||
public IEnumerable<string> LookupNames => sampleNames;
|
||||
|
||||
public int Volume { get; } = 100;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(sampleNames, Volume);
|
||||
}
|
||||
|
||||
public bool Equals(SampleInfo other)
|
||||
=> other != null && sampleNames.SequenceEqual(other.sampleNames);
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is SampleInfo other && Equals(other);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
@ -139,8 +138,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPooledHitObjectProvider pooledObjectProvider { get; set; }
|
||||
|
||||
private Container<PausableSkinnableSound> samplesContainer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
@ -159,7 +156,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
config.BindWith(OsuSetting.PositionalHitSounds, userPositionalHitSounds);
|
||||
|
||||
// Explicit non-virtual function call.
|
||||
base.AddInternal(samplesContainer = new Container<PausableSkinnableSound> { RelativeSizeAxes = Axes.Both });
|
||||
base.AddInternal(Samples = new PausableSkinnableSound(Array.Empty<ISampleInfo>()));
|
||||
}
|
||||
|
||||
protected override void LoadAsyncComplete()
|
||||
@ -269,6 +266,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
// In order to stop this needless update, the event is unbound and re-bound as late as possible in Apply().
|
||||
samplesBindable.CollectionChanged -= onSamplesChanged;
|
||||
|
||||
Samples.Samples = Array.Empty<ISampleInfo>();
|
||||
|
||||
if (nestedHitObjects.IsValueCreated)
|
||||
{
|
||||
foreach (var obj in nestedHitObjects.Value)
|
||||
@ -335,8 +334,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// </summary>
|
||||
protected virtual void LoadSamples()
|
||||
{
|
||||
samplesContainer.Clear();
|
||||
Samples = null;
|
||||
Samples.Samples = Array.Empty<ISampleInfo>();
|
||||
|
||||
var samples = GetSamples().ToArray();
|
||||
|
||||
@ -349,7 +347,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
||||
}
|
||||
|
||||
samplesContainer.Add(Samples = new PausableSkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s))));
|
||||
Samples.Samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||
}
|
||||
|
||||
private void onSamplesChanged(object sender, NotifyCollectionChangedEventArgs e) => LoadSamples();
|
||||
|
@ -5,6 +5,7 @@ using osuTK;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Audio;
|
||||
@ -500,7 +501,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone();
|
||||
}
|
||||
|
||||
public class LegacyHitSampleInfo : HitSampleInfo
|
||||
public class LegacyHitSampleInfo : HitSampleInfo, IEquatable<LegacyHitSampleInfo>
|
||||
{
|
||||
private int customSampleBank;
|
||||
|
||||
@ -524,9 +525,21 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
/// using the <see cref="LegacySkinConfiguration.LegacySetting.LayeredHitSounds"/> skin config option.
|
||||
/// </remarks>
|
||||
public bool IsLayered { get; set; }
|
||||
|
||||
public bool Equals(LegacyHitSampleInfo other)
|
||||
=> other != null && base.Equals(other) && CustomSampleBank == other.CustomSampleBank;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is LegacyHitSampleInfo other && Equals(other);
|
||||
|
||||
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] // This will have to be addressed eventually
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(base.GetHashCode(), customSampleBank);
|
||||
}
|
||||
}
|
||||
|
||||
private class FileHitSampleInfo : LegacyHitSampleInfo
|
||||
private class FileHitSampleInfo : LegacyHitSampleInfo, IEquatable<FileHitSampleInfo>
|
||||
{
|
||||
public string Filename;
|
||||
|
||||
@ -542,6 +555,18 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
Filename,
|
||||
Path.ChangeExtension(Filename, null)
|
||||
};
|
||||
|
||||
public bool Equals(FileHitSampleInfo other)
|
||||
=> other != null && Filename == other.Filename;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is FileHitSampleInfo other && Equals(other);
|
||||
|
||||
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] // This will have to be addressed eventually
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,19 +8,23 @@ using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
[Cached(typeof(IPooledHitObjectProvider))]
|
||||
public abstract class Playfield : CompositeDrawable, IPooledHitObjectProvider
|
||||
[Cached(typeof(IPooledSampleProvider))]
|
||||
public abstract class Playfield : CompositeDrawable, IPooledHitObjectProvider, IPooledSampleProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when a <see cref="DrawableHitObject"/> is judged.
|
||||
@ -80,6 +84,12 @@ namespace osu.Game.Rulesets.UI
|
||||
/// </summary>
|
||||
public readonly BindableBool DisplayJudgements = new BindableBool(true);
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IReadOnlyList<Mod> mods { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
@ -96,9 +106,6 @@ namespace osu.Game.Rulesets.UI
|
||||
}));
|
||||
}
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IReadOnlyList<Mod> mods { get; set; }
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
@ -336,6 +343,29 @@ namespace osu.Game.Rulesets.UI
|
||||
});
|
||||
}
|
||||
|
||||
private readonly Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>> samplePools = new Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>>();
|
||||
|
||||
public PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo)
|
||||
{
|
||||
if (!samplePools.TryGetValue(sampleInfo, out var existingPool))
|
||||
samplePools[sampleInfo] = existingPool = new DrawableSamplePool(sampleInfo, 5);
|
||||
|
||||
return existingPool.Get();
|
||||
}
|
||||
|
||||
private class DrawableSamplePool : DrawablePool<PoolableSkinnableSample>
|
||||
{
|
||||
private readonly ISampleInfo sampleInfo;
|
||||
|
||||
public DrawableSamplePool(ISampleInfo sampleInfo, int initialSize, int? maximumSize = null)
|
||||
: base(initialSize, maximumSize)
|
||||
{
|
||||
this.sampleInfo = sampleInfo;
|
||||
}
|
||||
|
||||
protected override PoolableSkinnableSample CreateNewDrawable() => base.CreateNewDrawable().With(d => d.Apply(sampleInfo));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Editor logic
|
||||
|
@ -14,13 +14,13 @@ namespace osu.Game.Skinning
|
||||
{
|
||||
protected bool RequestedPlaying { get; private set; }
|
||||
|
||||
public PausableSkinnableSound(ISampleInfo hitSamples)
|
||||
: base(hitSamples)
|
||||
public PausableSkinnableSound(ISampleInfo sample)
|
||||
: base(sample)
|
||||
{
|
||||
}
|
||||
|
||||
public PausableSkinnableSound(IEnumerable<ISampleInfo> hitSamples)
|
||||
: base(hitSamples)
|
||||
public PausableSkinnableSound(IEnumerable<ISampleInfo> samples)
|
||||
: base(samples)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Skinning
|
||||
/// <summary>
|
||||
/// Whether fallback to default skin should be allowed if the custom skin is missing this resource.
|
||||
/// </summary>
|
||||
private bool allowDefaultFallback => allowFallback == null || allowFallback.Invoke(CurrentSkin);
|
||||
protected bool AllowDefaultFallback => allowFallback == null || allowFallback.Invoke(CurrentSkin);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="SkinReloadableDrawable"/>
|
||||
@ -58,7 +58,7 @@ namespace osu.Game.Skinning
|
||||
|
||||
private void skinChanged()
|
||||
{
|
||||
SkinChanged(CurrentSkin, allowDefaultFallback);
|
||||
SkinChanged(CurrentSkin, AllowDefaultFallback);
|
||||
OnSkinChanged?.Invoke();
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,149 @@
|
||||
// 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;
|
||||
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.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Audio;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
public class SkinnableSound : SkinReloadableDrawable, IAdjustableAudioComponent
|
||||
public interface IPooledSampleProvider
|
||||
{
|
||||
private readonly ISampleInfo[] hitSamples;
|
||||
[CanBeNull]
|
||||
PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo);
|
||||
}
|
||||
|
||||
public class PoolableSkinnableSample : SkinReloadableDrawable, IAggregateAudioAdjustment, IAdjustableAudioComponent
|
||||
{
|
||||
private ISampleInfo sampleInfo;
|
||||
private DrawableSample sample;
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore samples { get; set; }
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
[Cached]
|
||||
private readonly AudioAdjustments adjustments = new AudioAdjustments();
|
||||
|
||||
public PoolableSkinnableSample()
|
||||
{
|
||||
}
|
||||
|
||||
public PoolableSkinnableSample(ISampleInfo sampleInfo)
|
||||
{
|
||||
Apply(sampleInfo);
|
||||
}
|
||||
|
||||
public void Apply(ISampleInfo sampleInfo)
|
||||
{
|
||||
if (this.sampleInfo != null)
|
||||
throw new InvalidOperationException($"A {nameof(PoolableSkinnableSample)} cannot be applied multiple {nameof(ISampleInfo)}s.");
|
||||
|
||||
this.sampleInfo = sampleInfo;
|
||||
|
||||
if (LoadState >= LoadState.Ready)
|
||||
updateSample();
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
updateSample();
|
||||
}
|
||||
|
||||
private void updateSample()
|
||||
{
|
||||
ClearInternal();
|
||||
|
||||
var ch = CurrentSkin.GetSample(sampleInfo);
|
||||
|
||||
if (ch == null && AllowDefaultFallback)
|
||||
{
|
||||
foreach (var lookup in sampleInfo.LookupNames)
|
||||
{
|
||||
if ((ch = sampleStore.Get(lookup)) != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == null)
|
||||
return;
|
||||
|
||||
AddInternal(sample = new DrawableSample(ch)
|
||||
{
|
||||
Looping = Looping,
|
||||
Volume = { Value = sampleInfo.Volume / 100.0 }
|
||||
});
|
||||
}
|
||||
|
||||
public void Play(bool restart = true) => sample?.Play(restart);
|
||||
|
||||
public void Stop() => sample?.Stop();
|
||||
|
||||
public bool Playing => sample?.Playing ?? false;
|
||||
|
||||
private bool looping;
|
||||
|
||||
public bool Looping
|
||||
{
|
||||
get => looping;
|
||||
set
|
||||
{
|
||||
looping = value;
|
||||
|
||||
if (sample != null)
|
||||
sample.Looping = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The volume of this component.
|
||||
/// </summary>
|
||||
public BindableNumber<double> Volume => adjustments.Volume;
|
||||
|
||||
/// <summary>
|
||||
/// The playback balance of this sample (-1 .. 1 where 0 is centered)
|
||||
/// </summary>
|
||||
public BindableNumber<double> Balance => adjustments.Balance;
|
||||
|
||||
/// <summary>
|
||||
/// Rate at which the component is played back (affects pitch). 1 is 100% playback speed, or default frequency.
|
||||
/// </summary>
|
||||
public BindableNumber<double> Frequency => adjustments.Frequency;
|
||||
|
||||
/// <summary>
|
||||
/// Rate at which the component is played back (does not affect pitch). 1 is 100% playback speed.
|
||||
/// </summary>
|
||||
public BindableNumber<double> Tempo => adjustments.Tempo;
|
||||
|
||||
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
|
||||
=> adjustments.AddAdjustment(type, adjustBindable);
|
||||
|
||||
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable)
|
||||
=> adjustments.RemoveAdjustment(type, adjustBindable);
|
||||
|
||||
public void RemoveAllAdjustments(AdjustableProperty type) => adjustments.RemoveAllAdjustments(type);
|
||||
|
||||
public IBindable<double> AggregateVolume => adjustments.AggregateVolume;
|
||||
|
||||
public IBindable<double> AggregateBalance => adjustments.AggregateBalance;
|
||||
|
||||
public IBindable<double> AggregateFrequency => adjustments.AggregateFrequency;
|
||||
|
||||
public IBindable<double> AggregateTempo => adjustments.AggregateTempo;
|
||||
}
|
||||
|
||||
public class SkinnableSound : SkinReloadableDrawable, IAdjustableAudioComponent
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
@ -34,17 +157,44 @@ namespace osu.Game.Skinning
|
||||
/// </remarks>
|
||||
protected bool PlayWhenZeroVolume => Looping;
|
||||
|
||||
protected readonly AudioContainer<DrawableSample> SamplesContainer;
|
||||
protected readonly AudioContainer<PoolableSkinnableSample> SamplesContainer;
|
||||
|
||||
public SkinnableSound(ISampleInfo hitSamples)
|
||||
: this(new[] { hitSamples })
|
||||
[Resolved]
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IPooledSampleProvider pooledProvider { get; set; }
|
||||
|
||||
public SkinnableSound(ISampleInfo sample)
|
||||
: this(new[] { sample })
|
||||
{
|
||||
}
|
||||
|
||||
public SkinnableSound(IEnumerable<ISampleInfo> hitSamples)
|
||||
public SkinnableSound(IEnumerable<ISampleInfo> samples)
|
||||
{
|
||||
this.hitSamples = hitSamples.ToArray();
|
||||
InternalChild = SamplesContainer = new AudioContainer<DrawableSample>();
|
||||
this.samples = samples.ToArray();
|
||||
|
||||
InternalChild = SamplesContainer = new AudioContainer<PoolableSkinnableSample>();
|
||||
}
|
||||
|
||||
private ISampleInfo[] samples;
|
||||
|
||||
public ISampleInfo[] Samples
|
||||
{
|
||||
get => samples;
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
if (samples == value)
|
||||
return;
|
||||
|
||||
samples = value;
|
||||
|
||||
if (LoadState >= LoadState.Ready)
|
||||
updateSamples();
|
||||
}
|
||||
}
|
||||
|
||||
private bool looping;
|
||||
@ -77,34 +227,23 @@ namespace osu.Game.Skinning
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
// Start playback internally for the new samples if the previous ones were playing beforehand.
|
||||
if (IsPlaying)
|
||||
Play();
|
||||
}
|
||||
|
||||
private void updateSamples()
|
||||
{
|
||||
bool wasPlaying = IsPlaying;
|
||||
|
||||
var channels = hitSamples.Select(s =>
|
||||
{
|
||||
var ch = skin.GetSample(s);
|
||||
// Remove all pooled samples (return them to the pool), and dispose the rest.
|
||||
SamplesContainer.RemoveAll(s => s.IsInPool);
|
||||
SamplesContainer.Clear();
|
||||
|
||||
if (ch == null && allowFallback)
|
||||
{
|
||||
foreach (var lookup in s.LookupNames)
|
||||
{
|
||||
if ((ch = samples.Get(lookup)) != null)
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (var s in samples)
|
||||
SamplesContainer.Add(pooledProvider?.GetPooledSample(s) ?? new PoolableSkinnableSample(s));
|
||||
|
||||
if (ch != null)
|
||||
{
|
||||
ch.Looping = looping;
|
||||
ch.Volume.Value = s.Volume / 100.0;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}).Where(c => c != null);
|
||||
|
||||
SamplesContainer.ChildrenEnumerable = channels.Select(c => new DrawableSample(c));
|
||||
|
||||
// Start playback internally for the new samples if the previous ones were playing beforehand.
|
||||
if (wasPlaying)
|
||||
Play();
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ namespace osu.Game.Storyboards.Drawables
|
||||
|
||||
foreach (var mod in mods.Value.OfType<IApplicableToSample>())
|
||||
{
|
||||
foreach (var sample in SamplesContainer)
|
||||
mod.ApplyToSample(sample);
|
||||
// foreach (var sample in SamplesContainer)
|
||||
// mod.ApplyToSample(sample.Sample);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user