// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; 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.Game.Audio; namespace osu.Game.Skinning { public class PoolableSkinnableSample : SkinReloadableDrawable, IAggregateAudioAdjustment, IAdjustableAudioComponent { private readonly AudioContainer sampleContainer; private ISampleInfo sampleInfo; private DrawableSample sample; [Resolved] private ISampleStore sampleStore { get; set; } public PoolableSkinnableSample() { InternalChild = sampleContainer = new AudioContainer { RelativeSizeAxes = Axes.Both }; } public PoolableSkinnableSample(ISampleInfo sampleInfo) : this() { 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; Volume.Value = sampleInfo.Volume / 100.0; if (LoadState >= LoadState.Ready) updateSample(); } protected override void SkinChanged(ISkinSource skin, bool allowFallback) { base.SkinChanged(skin, allowFallback); updateSample(); } private void updateSample() { sampleContainer.Clear(); 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; sampleContainer.Add(sample = new DrawableSample(ch) { Looping = Looping }); } 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; } } /// /// The volume of this component. /// public BindableNumber Volume => sampleContainer.Volume; /// /// The playback balance of this sample (-1 .. 1 where 0 is centered) /// public BindableNumber Balance => sampleContainer.Balance; /// /// Rate at which the component is played back (affects pitch). 1 is 100% playback speed, or default frequency. /// public BindableNumber Frequency => sampleContainer.Frequency; /// /// Rate at which the component is played back (does not affect pitch). 1 is 100% playback speed. /// public BindableNumber Tempo => sampleContainer.Tempo; public void AddAdjustment(AdjustableProperty type, BindableNumber adjustBindable) => sampleContainer.AddAdjustment(type, adjustBindable); public void RemoveAdjustment(AdjustableProperty type, BindableNumber adjustBindable) => sampleContainer.RemoveAdjustment(type, adjustBindable); public void RemoveAllAdjustments(AdjustableProperty type) => sampleContainer.RemoveAllAdjustments(type); public IBindable AggregateVolume => sampleContainer.AggregateVolume; public IBindable AggregateBalance => sampleContainer.AggregateBalance; public IBindable AggregateFrequency => sampleContainer.AggregateFrequency; public IBindable AggregateTempo => sampleContainer.AggregateTempo; } }