public static BpmGraph ParseBars(List <BarSection> barSections) { //In this context, 'time' = bar (beat is still beat) barSections.Sort((a, b) => a.StartBar.CompareTo(b.StartBar)); var barToBeatSections = new List <BpmSection>(); double maxBar = 100_000; var lastBarSection = new BpmSection(0, maxBar, 0, maxBar * 4);//default bar section for default Beats Per Bar of 4 barToBeatSections.Add(lastBarSection); foreach (var bar in barSections) { double startBeat = lastBarSection.BeatAt(bar.StartBar); double endBeat = (maxBar - bar.StartBar) * bar.NewBeatsPerBar + startBeat; var section = new BpmSection(bar.StartBar, maxBar, startBeat, endBeat); //modify the last section to end here lastBarSection.EndBeat = startBeat; lastBarSection.EndTime = bar.StartBar; Assert.AreApproximatelyEqual(bar.NewBeatsPerBar, (float)section.Slope()); barToBeatSections.Add(section); lastBarSection = section; } return(new BpmGraph(barToBeatSections)); }
public double BeatAt(double time) { //check if last entry is valid for efficiency if (_beatCache != null && _beatCache.EndTime >= time && _beatCache.StartTime <= time) { return(_beatCache.BeatAt(time));//reuse cache } //(trivial) edge case if (BpmSections.Count == 1) { return(BpmSections[0].BeatAt(time)); } //binary search int min = 0; int max = BpmSections.Count - 1; while (true)//will break when found { int midpt = (min + max) / 2; if (max - min == 1)//right next to each other { if (BpmSections[min].TimeInBounds(time)) { _beatCache = BpmSections[min]; return(BpmSections[min].BeatAt(time)); } else { _beatCache = BpmSections[max]; return(BpmSections[max].BeatAt(time)); } } BpmSection mid = BpmSections[midpt]; if (mid.EndTime > time) { max = midpt; } else if (mid.StartTime < time) { min = midpt; } else { _beatCache = mid; return(mid.BeatAt(time)); } } }