// 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.Bindables; using osu.Game.Beatmaps.Timing; using osu.Game.Graphics; using osuTK.Graphics; namespace osu.Game.Beatmaps.ControlPoints { public class TimingControlPoint : ControlPoint, IEquatable { /// /// The time signature at this control point. /// public readonly Bindable TimeSignatureBindable = new Bindable(TimeSignature.SimpleQuadruple); /// /// Whether the first bar line of this control point is ignored. /// public readonly BindableBool OmitFirstBarLineBindable = new BindableBool(); /// /// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing. /// private const double default_beat_length = 60000.0 / 60.0; public override Color4 GetRepresentingColour(OsuColour colours) => colours.Red1; public static readonly TimingControlPoint DEFAULT = new TimingControlPoint { BeatLengthBindable = { Value = default_beat_length, Disabled = true }, OmitFirstBarLineBindable = { Disabled = true }, TimeSignatureBindable = { Disabled = true } }; /// /// The time signature at this control point. /// public TimeSignature TimeSignature { get => TimeSignatureBindable.Value; set => TimeSignatureBindable.Value = value; } /// /// Whether the first bar line of this control point is ignored. /// public bool OmitFirstBarLine { get => OmitFirstBarLineBindable.Value; set => OmitFirstBarLineBindable.Value = value; } public const double DEFAULT_BEAT_LENGTH = 1000; /// /// The beat length at this control point. /// public readonly BindableDouble BeatLengthBindable = new BindableDouble(DEFAULT_BEAT_LENGTH) { MinValue = 6, MaxValue = 60000 }; /// /// The beat length at this control point. /// public double BeatLength { get => BeatLengthBindable.Value; set => BeatLengthBindable.Value = value; } /// /// The BPM at this control point. /// public double BPM => 60000 / BeatLength; public TimingControlPoint() { TimeSignatureBindable.BindValueChanged(_ => RaiseChanged()); OmitFirstBarLineBindable.BindValueChanged(_ => RaiseChanged()); BeatLengthBindable.BindValueChanged(_ => RaiseChanged()); } // Timing points are never redundant as they can change the time signature. public override bool IsRedundant(ControlPoint? existing) => false; public override void CopyFrom(ControlPoint other) { TimeSignature = ((TimingControlPoint)other).TimeSignature; OmitFirstBarLine = ((TimingControlPoint)other).OmitFirstBarLine; BeatLength = ((TimingControlPoint)other).BeatLength; base.CopyFrom(other); } public override bool Equals(ControlPoint? other) => other is TimingControlPoint otherTimingControlPoint && Equals(otherTimingControlPoint); public bool Equals(TimingControlPoint? other) => base.Equals(other) && TimeSignature.Equals(other.TimeSignature) && OmitFirstBarLine == other.OmitFirstBarLine && BeatLength.Equals(other.BeatLength); public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), TimeSignature, BeatLength, OmitFirstBarLine); } }