mirror of
https://github.com/ppy/osu.git
synced 2025-02-22 18:53:21 +08:00
Replace TimeSignatures
enum with struct for storage of arbitrary meter
This commit is contained in:
parent
ccac7b85be
commit
735414bc49
@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
|
|||||||
if (!effectPoint.KiaiMode)
|
if (!effectPoint.KiaiMode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (beatIndex % (int)timingPoint.TimeSignature != 0)
|
if (beatIndex % timingPoint.TimeSignature.Numerator != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double duration = timingPoint.BeatLength * 2;
|
double duration = timingPoint.BeatLength * 2;
|
||||||
|
@ -178,17 +178,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
var timingPoint = controlPoints.TimingPointAt(0);
|
var timingPoint = controlPoints.TimingPointAt(0);
|
||||||
Assert.AreEqual(956, timingPoint.Time);
|
Assert.AreEqual(956, timingPoint.Time);
|
||||||
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
|
||||||
timingPoint = controlPoints.TimingPointAt(48428);
|
timingPoint = controlPoints.TimingPointAt(48428);
|
||||||
Assert.AreEqual(956, timingPoint.Time);
|
Assert.AreEqual(956, timingPoint.Time);
|
||||||
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
|
||||||
timingPoint = controlPoints.TimingPointAt(119637);
|
timingPoint = controlPoints.TimingPointAt(119637);
|
||||||
Assert.AreEqual(119637, timingPoint.Time);
|
Assert.AreEqual(119637, timingPoint.Time);
|
||||||
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
|
||||||
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
||||||
Assert.AreEqual(0, difficultyPoint.Time);
|
Assert.AreEqual(0, difficultyPoint.Time);
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
|
|
||||||
const int beat_length_numerator = 2000;
|
const int beat_length_numerator = 2000;
|
||||||
const int beat_length_denominator = 7;
|
const int beat_length_denominator = 7;
|
||||||
const TimeSignatures signature = TimeSignatures.SimpleQuadruple;
|
TimeSignature signature = TimeSignature.SimpleQuadruple;
|
||||||
|
|
||||||
var beatmap = new Beatmap
|
var beatmap = new Beatmap
|
||||||
{
|
{
|
||||||
@ -49,7 +49,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
for (int i = 0; i * beat_length_denominator < barLines.Count; i++)
|
for (int i = 0; i * beat_length_denominator < barLines.Count; i++)
|
||||||
{
|
{
|
||||||
var barLine = barLines[i * beat_length_denominator];
|
var barLine = barLines[i * beat_length_denominator];
|
||||||
int expectedTime = beat_length_numerator * (int)signature * i;
|
int expectedTime = beat_length_numerator * signature.Numerator * i;
|
||||||
|
|
||||||
// every seventh bar's start time should be at least greater than the whole number we expect.
|
// every seventh bar's start time should be at least greater than the whole number we expect.
|
||||||
// It cannot be less, as that can affect overlapping scroll algorithms
|
// It cannot be less, as that can affect overlapping scroll algorithms
|
||||||
@ -60,7 +60,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
Assert.IsTrue(Precision.AlmostEquals(barLine.StartTime, expectedTime));
|
Assert.IsTrue(Precision.AlmostEquals(barLine.StartTime, expectedTime));
|
||||||
|
|
||||||
// check major/minor lines for good measure too
|
// check major/minor lines for good measure too
|
||||||
Assert.AreEqual(i % (int)signature == 0, barLine.Major);
|
Assert.AreEqual(i % signature.Numerator == 0, barLine.Major);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
Add(new ModNightcore<HitObject>.NightcoreBeatContainer());
|
Add(new ModNightcore<HitObject>.NightcoreBeatContainer());
|
||||||
|
|
||||||
AddStep("change signature to quadruple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignatures.SimpleQuadruple));
|
AddStep("change signature to quadruple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignature.SimpleQuadruple));
|
||||||
AddStep("change signature to triple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignatures.SimpleTriple));
|
AddStep("change signature to triple", () => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.ForEach(p => p.TimeSignature = TimeSignature.SimpleTriple));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time signature at this control point.
|
/// The time signature at this control point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<TimeSignatures> TimeSignatureBindable = new Bindable<TimeSignatures>(TimeSignatures.SimpleQuadruple) { Default = TimeSignatures.SimpleQuadruple };
|
public readonly Bindable<TimeSignature> TimeSignatureBindable = new Bindable<TimeSignature>(TimeSignature.SimpleQuadruple);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
|
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
|
||||||
@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time signature at this control point.
|
/// The time signature at this control point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSignatures TimeSignature
|
public TimeSignature TimeSignature
|
||||||
{
|
{
|
||||||
get => TimeSignatureBindable.Value;
|
get => TimeSignatureBindable.Value;
|
||||||
set => TimeSignatureBindable.Value = value;
|
set => TimeSignatureBindable.Value = value;
|
||||||
|
@ -340,9 +340,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
double beatLength = Parsing.ParseDouble(split[1].Trim());
|
double beatLength = Parsing.ParseDouble(split[1].Trim());
|
||||||
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
||||||
|
|
||||||
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
|
TimeSignature timeSignature = TimeSignature.SimpleQuadruple;
|
||||||
if (split.Length >= 3)
|
if (split.Length >= 3)
|
||||||
timeSignature = split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)Parsing.ParseInt(split[2]);
|
timeSignature = split[2][0] == '0' ? TimeSignature.SimpleQuadruple : new TimeSignature(Parsing.ParseInt(split[2]));
|
||||||
|
|
||||||
LegacySampleBank sampleSet = defaultSampleBank;
|
LegacySampleBank sampleSet = defaultSampleBank;
|
||||||
if (split.Length >= 4)
|
if (split.Length >= 4)
|
||||||
|
@ -227,7 +227,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (effectPoint.OmitFirstBarLine)
|
if (effectPoint.OmitFirstBarLine)
|
||||||
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
||||||
|
|
||||||
writer.Write(FormattableString.Invariant($"{(int)legacyControlPoints.TimingPointAt(time).TimeSignature},"));
|
writer.Write(FormattableString.Invariant($"{legacyControlPoints.TimingPointAt(time).TimeSignature.Numerator},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
|
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
||||||
|
45
osu.Game/Beatmaps/Timing/TimeSignature.cs
Normal file
45
osu.Game/Beatmaps/Timing/TimeSignature.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.Timing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the time signature of a track.
|
||||||
|
/// For now, the lower numeral can only be 4; support for other denominators can be considered at a later date.
|
||||||
|
/// </summary>
|
||||||
|
public class TimeSignature : IEquatable<TimeSignature>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The numerator of a signature.
|
||||||
|
/// </summary>
|
||||||
|
public int Numerator { get; }
|
||||||
|
|
||||||
|
// TODO: support time signatures with a denominator other than 4
|
||||||
|
// this in particular requires a new beatmap format.
|
||||||
|
|
||||||
|
public TimeSignature(int numerator)
|
||||||
|
{
|
||||||
|
if (numerator < 1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(numerator), numerator, "The numerator of a time signature must be positive.");
|
||||||
|
|
||||||
|
Numerator = numerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TimeSignature SimpleTriple => new TimeSignature(3);
|
||||||
|
public static TimeSignature SimpleQuadruple => new TimeSignature(4);
|
||||||
|
|
||||||
|
public override string ToString() => $"{Numerator}/4";
|
||||||
|
|
||||||
|
public bool Equals(TimeSignature other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return Numerator == other.Numerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() => Numerator;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,13 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Timing
|
namespace osu.Game.Beatmaps.Timing
|
||||||
{
|
{
|
||||||
public enum TimeSignatures
|
[Obsolete("Use osu.Game.Beatmaps.Timing.TimeSignature instead.")]
|
||||||
|
public enum TimeSignatures // can be removed 20220722
|
||||||
{
|
{
|
||||||
[Description("4/4")]
|
[Description("4/4")]
|
||||||
SimpleQuadruple = 4,
|
SimpleQuadruple = 4,
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
if (!IsBeatSyncedWithTrack) return;
|
if (!IsBeatSyncedWithTrack) return;
|
||||||
|
|
||||||
int timeSignature = (int)timingPoint.TimeSignature;
|
int timeSignature = timingPoint.TimeSignature.Numerator;
|
||||||
|
|
||||||
// play metronome from one measure before the first object.
|
// play metronome from one measure before the first object.
|
||||||
if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
|
||||||
|
@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||||
|
|
||||||
int beatsPerBar = (int)timingPoint.TimeSignature;
|
int beatsPerBar = timingPoint.TimeSignature.Numerator;
|
||||||
int segmentLength = beatsPerBar * Divisor * bars_per_segment;
|
int segmentLength = beatsPerBar * Divisor * bars_per_segment;
|
||||||
|
|
||||||
if (!IsBeatSyncedWithTrack)
|
if (!IsBeatSyncedWithTrack)
|
||||||
@ -102,14 +102,14 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
playBeatFor(beatIndex % segmentLength, timingPoint.TimeSignature);
|
playBeatFor(beatIndex % segmentLength, timingPoint.TimeSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playBeatFor(int beatIndex, TimeSignatures signature)
|
private void playBeatFor(int beatIndex, TimeSignature signature)
|
||||||
{
|
{
|
||||||
if (beatIndex == 0)
|
if (beatIndex == 0)
|
||||||
finishSample?.Play();
|
finishSample?.Play();
|
||||||
|
|
||||||
switch (signature)
|
switch (signature.Numerator)
|
||||||
{
|
{
|
||||||
case TimeSignatures.SimpleTriple:
|
case 3:
|
||||||
switch (beatIndex % 6)
|
switch (beatIndex % 6)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TimeSignatures.SimpleQuadruple:
|
case 4:
|
||||||
switch (beatIndex % 4)
|
switch (beatIndex % 4)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -41,9 +41,9 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
int currentBeat = 0;
|
int currentBeat = 0;
|
||||||
|
|
||||||
// Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object
|
// Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object
|
||||||
double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - currentTimingPoint.BeatLength : lastHitTime + currentTimingPoint.BeatLength * (int)currentTimingPoint.TimeSignature;
|
double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - currentTimingPoint.BeatLength : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator;
|
||||||
|
|
||||||
double barLength = currentTimingPoint.BeatLength * (int)currentTimingPoint.TimeSignature;
|
double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator;
|
||||||
|
|
||||||
for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++)
|
for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++)
|
||||||
{
|
{
|
||||||
@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
BarLines.Add(new TBarLine
|
BarLines.Add(new TBarLine
|
||||||
{
|
{
|
||||||
StartTime = t,
|
StartTime = t,
|
||||||
Major = currentBeat % (int)currentTimingPoint.TimeSignature == 0
|
Major = currentBeat % currentTimingPoint.TimeSignature.Numerator == 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
if (beat == 0 && i == 0)
|
if (beat == 0 && i == 0)
|
||||||
nextMinTick = float.MinValue;
|
nextMinTick = float.MinValue;
|
||||||
|
|
||||||
int indexInBar = beat % ((int)point.TimeSignature * beatDivisor.Value);
|
int indexInBar = beat % (point.TimeSignature.Numerator * beatDivisor.Value);
|
||||||
|
|
||||||
int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value);
|
int divisor = BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value);
|
||||||
var colour = BindableBeatDivisor.GetColourFor(divisor, colours);
|
var colour = BindableBeatDivisor.GetColourFor(divisor, colours);
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
public class TimingRowAttribute : RowAttribute
|
public class TimingRowAttribute : RowAttribute
|
||||||
{
|
{
|
||||||
private readonly BindableNumber<double> beatLength;
|
private readonly BindableNumber<double> beatLength;
|
||||||
private readonly Bindable<TimeSignatures> timeSignature;
|
private readonly Bindable<TimeSignature> timeSignature;
|
||||||
private OsuSpriteText text;
|
private OsuSpriteText text;
|
||||||
|
|
||||||
public TimingRowAttribute(TimingControlPoint timing)
|
public TimingRowAttribute(TimingControlPoint timing)
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
internal class TimingSection : Section<TimingControlPoint>
|
internal class TimingSection : Section<TimingControlPoint>
|
||||||
{
|
{
|
||||||
private SettingsSlider<double> bpmSlider;
|
private SettingsSlider<double> bpmSlider;
|
||||||
private SettingsEnumDropdown<TimeSignatures> timeSignature;
|
private SettingsDropdown<TimeSignature> timeSignature;
|
||||||
private BPMTextBox bpmTextEntry;
|
private BPMTextBox bpmTextEntry;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -25,9 +25,14 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
{
|
{
|
||||||
bpmTextEntry = new BPMTextBox(),
|
bpmTextEntry = new BPMTextBox(),
|
||||||
bpmSlider = new BPMSlider(),
|
bpmSlider = new BPMSlider(),
|
||||||
timeSignature = new SettingsEnumDropdown<TimeSignatures>
|
timeSignature = new SettingsDropdown<TimeSignature>
|
||||||
{
|
{
|
||||||
LabelText = "Time Signature"
|
LabelText = "Time Signature",
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
TimeSignature.SimpleTriple,
|
||||||
|
TimeSignature.SimpleQuadruple
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
if (beatIndex < 0)
|
if (beatIndex < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (effectPoint.KiaiMode ? beatIndex % 2 == 0 : beatIndex % (int)timingPoint.TimeSignature == 0)
|
if (effectPoint.KiaiMode ? beatIndex % 2 == 0 : beatIndex % timingPoint.TimeSignature.Numerator == 0)
|
||||||
flash(leftBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
|
flash(leftBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
|
||||||
if (effectPoint.KiaiMode ? beatIndex % 2 == 1 : beatIndex % (int)timingPoint.TimeSignature == 0)
|
if (effectPoint.KiaiMode ? beatIndex % 2 == 1 : beatIndex % timingPoint.TimeSignature.Numerator == 0)
|
||||||
flash(rightBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
|
flash(rightBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
this.Delay(early_activation).Schedule(() =>
|
this.Delay(early_activation).Schedule(() =>
|
||||||
{
|
{
|
||||||
if (beatIndex % (int)timingPoint.TimeSignature == 0)
|
if (beatIndex % timingPoint.TimeSignature.Numerator == 0)
|
||||||
sampleDownbeat.Play();
|
sampleDownbeat.Play();
|
||||||
else
|
else
|
||||||
sampleBeat.Play();
|
sampleBeat.Play();
|
||||||
|
Loading…
Reference in New Issue
Block a user