private static SortedList <TimingPoint> ConvertToSortedList(List <TimingPoint> presetTimingPoints) { var timingPoints = new SortedList <TimingPoint>(presetTimingPoints.Count, CompareTimingPoints); var absoluteTimingPoints = Convert <TimingPoint, AbsoluteTimingPoint>(presetTimingPoints); if (absoluteTimingPoints.Count == 0) { throw new InvalidOperationException("No absolute timing points were used"); } absoluteTimingPoints[0].SetAsInitialTimingPoint(); var relativeTimingPoints = Convert <TimingPoint, RelativeTimingPoint>(presetTimingPoints); relativeTimingPoints.Sort((a, b) => MeasuredTimePosition.CompareByAbsolutePosition(a.TimePosition, b.TimePosition)); // Add absolute timing points and calculate their relative time positions AbsoluteTimingPoint previousAbsolute = null; foreach (var a in absoluteTimingPoints) { if (previousAbsolute != null) { a.CalculateRelativeTimePosition(previousAbsolute); } timingPoints.Add(previousAbsolute = a); } // Add relative timing points, calculate their absolute time positions and adjust the absolute timing points' relative time positions foreach (var r in relativeTimingPoints) { int index = timingPoints.IndexBefore(r); r.CalculateAbsoluteTimePosition(timingPoints[index]); if (index + 1 < timingPoints.Count) { // The next timing point is certainly an absolute timing point since no relative timing points have been added beyond that one yet var nextAbsolute = timingPoints[index + 1] as AbsoluteTimingPoint; // Calculate the measure adjustment for the first absolute timing point to apply it to all the rest int currentMeasure = nextAbsolute.RelativeTimePosition.Measure; nextAbsolute.CalculateRelativeTimePosition(r); int newMeasure = nextAbsolute.RelativeTimePosition.Measure; int measureAdjustment = newMeasure - currentMeasure; if (measureAdjustment != 0) { for (int i = index + 2; i < timingPoints.Count; i++) { (timingPoints[i] as AbsoluteTimingPoint).AdjustMeasure(measureAdjustment); } } } timingPoints.Add(r); } return(timingPoints); }
/// <summary>Attempts to parse a string representation of a timing point into a <seealso cref="TimingPoint"/> and returns the resulting parsed object, or <see langword="null"/>.</summary> /// <param name="s">The string representation of a timing point to parse.</param> public static TimingPoint Parse(string s) { if (AbsoluteTimingPoint.TryParse(s, out var absolute)) { return(absolute); } if (RelativeTimingPoint.TryParse(s, out var relative)) { return(relative); } return(null); }