예제 #1
0
        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));
        }
예제 #2
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)));
        }
예제 #3
0
        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));
        }
예제 #4
0
        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));
        }
예제 #5
0
        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;
                    }
                }
            }
        }
예제 #6
0
        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();
            }
        }