// Copyright (c) ppy Pty Ltd . 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; using osu.Framework.Bindables; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mods { public class Metronome : BeatSyncedContainer, IAdjustableAudioComponent { private readonly double firstHitTime; private readonly PausableSkinnableSound sample; /// Start time of the first hit object, used for providing a count down. public Metronome(double firstHitTime) { this.firstHitTime = firstHitTime; AllowMistimedEventFiring = false; Divisor = 1; InternalChild = sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana")); } protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); if (!IsBeatSyncedWithTrack) return; int timeSignature = timingPoint.TimeSignature.Numerator; // play metronome from one measure before the first object. if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature) return; sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f; sample.Play(); } #region IAdjustableAudioComponent public IBindable AggregateVolume => sample.AggregateVolume; public IBindable AggregateBalance => sample.AggregateBalance; public IBindable AggregateFrequency => sample.AggregateFrequency; public IBindable AggregateTempo => sample.AggregateTempo; public BindableNumber Volume => sample.Volume; public BindableNumber Balance => sample.Balance; public BindableNumber Frequency => sample.Frequency; public BindableNumber Tempo => sample.Tempo; public void BindAdjustments(IAggregateAudioAdjustment component) { sample.BindAdjustments(component); } public void UnbindAdjustments(IAggregateAudioAdjustment component) { sample.UnbindAdjustments(component); } public void AddAdjustment(AdjustableProperty type, IBindable adjustBindable) { sample.AddAdjustment(type, adjustBindable); } public void RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) { sample.RemoveAdjustment(type, adjustBindable); } public void RemoveAllAdjustments(AdjustableProperty type) { sample.RemoveAllAdjustments(type); } #endregion } }