public void TestClear() { var cpi = new LegacyControlPointInfo(); cpi.Add(0, new TimingControlPoint()); cpi.Add(1000, new TimingControlPoint { BeatLength = 500 }); cpi.Add(10000, new TimingControlPoint { BeatLength = 200 }); cpi.Add(5000, new TimingControlPoint { BeatLength = 100 }); cpi.Add(3000, new DifficultyControlPoint { SliderVelocity = 2 }); cpi.GroupAt(7000, true).Add(new DifficultyControlPoint { SliderVelocity = 4 }); cpi.GroupAt(1000).Add(new SampleControlPoint { SampleVolume = 0 }); cpi.GroupAt(8000, true).Add(new EffectControlPoint { KiaiMode = true }); cpi.Clear(); Assert.That(cpi.Groups.Count, Is.EqualTo(0)); Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0)); Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(0)); }
public void TestOrdering() { var cpi = new LegacyControlPointInfo(); cpi.Add(0, new TimingControlPoint()); cpi.Add(1000, new TimingControlPoint { BeatLength = 500 }); cpi.Add(10000, new TimingControlPoint { BeatLength = 200 }); cpi.Add(5000, new TimingControlPoint { BeatLength = 100 }); cpi.Add(3000, new DifficultyControlPoint { SliderVelocity = 2 }); cpi.GroupAt(7000, true).Add(new DifficultyControlPoint { SliderVelocity = 4 }); cpi.GroupAt(1000).Add(new SampleControlPoint { SampleVolume = 0 }); cpi.GroupAt(8000, true).Add(new EffectControlPoint { KiaiMode = true }); Assert.That(cpi.AllControlPoints.Count, Is.EqualTo(8)); Assert.That(cpi.Groups, Is.Ordered.Ascending.By(nameof(ControlPointGroup.Time))); Assert.That(cpi.AllControlPoints, Is.Ordered.Ascending.By(nameof(ControlPoint.Time))); Assert.That(cpi.TimingPoints, Is.Ordered.Ascending.By(nameof(ControlPoint.Time))); }
public void TestAddRedundantSample() { var cpi = new LegacyControlPointInfo(); cpi.Add(0, new SampleControlPoint()); // is *not* redundant, special exception for first sample point cpi.Add(1000, new SampleControlPoint()); // is redundant Assert.That(cpi.Groups.Count, Is.EqualTo(1)); Assert.That(cpi.SamplePoints.Count, Is.EqualTo(1)); Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1)); cpi.Add(1000, new SampleControlPoint { SampleVolume = 50 }); // is not redundant Assert.That(cpi.Groups.Count, Is.EqualTo(2)); Assert.That(cpi.SamplePoints.Count, Is.EqualTo(2)); Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2)); }
public void TestAddRedundantDifficulty() { var cpi = new LegacyControlPointInfo(); cpi.Add(0, new DifficultyControlPoint()); // is redundant cpi.Add(1000, new DifficultyControlPoint()); // is redundant Assert.That(cpi.Groups.Count, Is.EqualTo(0)); Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(0)); Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0)); cpi.Add(1000, new DifficultyControlPoint { SliderVelocity = 2 }); // is not redundant Assert.That(cpi.Groups.Count, Is.EqualTo(1)); Assert.That(cpi.DifficultyPoints.Count, Is.EqualTo(1)); Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1)); }
private void handleControlPoints(TextWriter writer) { if (beatmap.ControlPointInfo.Groups.Count == 0) { return; } var legacyControlPoints = new LegacyControlPointInfo(); foreach (var point in beatmap.ControlPointInfo.AllControlPoints) { legacyControlPoints.Add(point.Time, point.DeepClone()); } writer.WriteLine("[TimingPoints]"); SampleControlPoint lastRelevantSamplePoint = null; DifficultyControlPoint lastRelevantDifficultyPoint = null; bool isOsuRuleset = beatmap.BeatmapInfo.RulesetID == 0; // iterate over hitobjects and pull out all required sample and difficulty changes extractDifficultyControlPoints(beatmap.HitObjects); extractSampleControlPoints(beatmap.HitObjects); // handle scroll speed, which is stored as "slider velocity" in legacy formats. // this is relevant for scrolling ruleset beatmaps. if (!isOsuRuleset) { foreach (var point in legacyControlPoints.EffectPoints) { legacyControlPoints.Add(point.Time, new DifficultyControlPoint { SliderVelocity = point.ScrollSpeed }); } } foreach (var group in legacyControlPoints.Groups) { var groupTimingPoint = group.ControlPoints.OfType <TimingControlPoint>().FirstOrDefault(); // If the group contains a timing control point, it needs to be output separately. if (groupTimingPoint != null) { writer.Write(FormattableString.Invariant($"{groupTimingPoint.Time},")); writer.Write(FormattableString.Invariant($"{groupTimingPoint.BeatLength},")); outputControlPointAt(groupTimingPoint.Time, true); } // Output any remaining effects as secondary non-timing control point. var difficultyPoint = legacyControlPoints.DifficultyPointAt(group.Time); writer.Write(FormattableString.Invariant($"{group.Time},")); writer.Write(FormattableString.Invariant($"{-100 / difficultyPoint.SliderVelocity},")); outputControlPointAt(group.Time, false); } void outputControlPointAt(double time, bool isTimingPoint) { var samplePoint = legacyControlPoints.SamplePointAt(time); var effectPoint = legacyControlPoints.EffectPointAt(time); // Apply the control point to a hit sample to uncover legacy properties (e.g. suffix) HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo(string.Empty)); // Convert effect flags to the legacy format LegacyEffectFlags effectFlags = LegacyEffectFlags.None; if (effectPoint.KiaiMode) { effectFlags |= LegacyEffectFlags.Kiai; } if (effectPoint.OmitFirstBarLine) { effectFlags |= LegacyEffectFlags.OmitFirstBarLine; } writer.Write(FormattableString.Invariant($"{(int)legacyControlPoints.TimingPointAt(time).TimeSignature},")); writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},")); writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},")); writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},")); writer.Write(FormattableString.Invariant($"{(isTimingPoint ? '1' : '0')},")); writer.Write(FormattableString.Invariant($"{(int)effectFlags}")); writer.WriteLine(); } IEnumerable <DifficultyControlPoint> collectDifficultyControlPoints(IEnumerable <HitObject> hitObjects) { if (!isOsuRuleset) { yield break; } foreach (var hitObject in hitObjects) { yield return(hitObject.DifficultyControlPoint); foreach (var nested in collectDifficultyControlPoints(hitObject.NestedHitObjects)) { yield return(nested); } } } void extractDifficultyControlPoints(IEnumerable <HitObject> hitObjects) { foreach (var hDifficultyPoint in collectDifficultyControlPoints(hitObjects).OrderBy(dp => dp.Time)) { if (!hDifficultyPoint.IsRedundant(lastRelevantDifficultyPoint)) { legacyControlPoints.Add(hDifficultyPoint.Time, hDifficultyPoint); lastRelevantDifficultyPoint = hDifficultyPoint; } } } IEnumerable <SampleControlPoint> collectSampleControlPoints(IEnumerable <HitObject> hitObjects) { foreach (var hitObject in hitObjects) { yield return(hitObject.SampleControlPoint); foreach (var nested in collectSampleControlPoints(hitObject.NestedHitObjects)) { yield return(nested); } } } void extractSampleControlPoints(IEnumerable <HitObject> hitObject) { foreach (var hSamplePoint in collectSampleControlPoints(hitObject).OrderBy(sp => sp.Time)) { if (!hSamplePoint.IsRedundant(lastRelevantSamplePoint)) { legacyControlPoints.Add(hSamplePoint.Time, hSamplePoint); lastRelevantSamplePoint = hSamplePoint; } } } }
private void handleControlPoints(TextWriter writer) { if (beatmap.ControlPointInfo.Groups.Count == 0) { return; } writer.WriteLine("[TimingPoints]"); if (!(beatmap.ControlPointInfo is LegacyControlPointInfo)) { var legacyControlPoints = new LegacyControlPointInfo(); foreach (var point in beatmap.ControlPointInfo.AllControlPoints) { legacyControlPoints.Add(point.Time, point.DeepClone()); } beatmap.ControlPointInfo = legacyControlPoints; SampleControlPoint lastRelevantSamplePoint = null; // iterate over hitobjects and pull out all required sample changes foreach (var h in beatmap.HitObjects) { var hSamplePoint = h.SampleControlPoint; if (!hSamplePoint.IsRedundant(lastRelevantSamplePoint)) { legacyControlPoints.Add(hSamplePoint.Time, hSamplePoint); lastRelevantSamplePoint = hSamplePoint; } } } foreach (var group in beatmap.ControlPointInfo.Groups) { var groupTimingPoint = group.ControlPoints.OfType <TimingControlPoint>().FirstOrDefault(); // If the group contains a timing control point, it needs to be output separately. if (groupTimingPoint != null) { writer.Write(FormattableString.Invariant($"{groupTimingPoint.Time},")); writer.Write(FormattableString.Invariant($"{groupTimingPoint.BeatLength},")); outputControlPointAt(groupTimingPoint.Time, true); } // Output any remaining effects as secondary non-timing control point. var difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(group.Time); writer.Write(FormattableString.Invariant($"{group.Time},")); writer.Write(FormattableString.Invariant($"{-100 / difficultyPoint.SpeedMultiplier},")); outputControlPointAt(group.Time, false); } void outputControlPointAt(double time, bool isTimingPoint) { var samplePoint = ((LegacyControlPointInfo)beatmap.ControlPointInfo).SamplePointAt(time); var effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); // Apply the control point to a hit sample to uncover legacy properties (e.g. suffix) HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo(string.Empty)); // Convert effect flags to the legacy format LegacyEffectFlags effectFlags = LegacyEffectFlags.None; if (effectPoint.KiaiMode) { effectFlags |= LegacyEffectFlags.Kiai; } if (effectPoint.OmitFirstBarLine) { effectFlags |= LegacyEffectFlags.OmitFirstBarLine; } writer.Write(FormattableString.Invariant($"{(int)beatmap.ControlPointInfo.TimingPointAt(time).TimeSignature},")); writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},")); writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},")); writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},")); writer.Write(FormattableString.Invariant($"{(isTimingPoint ? '1' : '0')},")); writer.Write(FormattableString.Invariant($"{(int)effectFlags}")); writer.WriteLine(); } }