Browse Source

fix PlaybackManager.getSheetDurationInMs() not counting repeats, add new default method that counts repeats

sschmidTU 1 year ago
parent
commit
481fffaa3e
1 changed files with 30 additions and 1 deletions
  1. 30 1
      src/Playback/PlaybackManager.ts

+ 30 - 1
src/Playback/PlaybackManager.ts

@@ -1357,7 +1357,10 @@ export class PlaybackManager implements IPlaybackParametersListener {
      *  The result may be inaccurate if you haven't set the bpm to the first measure's bpm before playback (or the other way round).
      *  In that case, getSheetDurationInMsEvenBpm() can be more accurate (previous version of this method)
      */
-    public getSheetDurationInMs(): number {
+    public getSheetDurationInMs(withRepeats: boolean = true): number {
+        if (withRepeats) {
+            return this.getSheetDurationInMsWithRepeats();
+        }
         let totalDuration: number = 0;
         // code similar to PlaybackSettings.getDurationInMilliseconds()
         const beatRealValue: number = 1.0 / 4.0;
@@ -1368,6 +1371,32 @@ export class PlaybackManager implements IPlaybackParametersListener {
         return totalDuration;
     }
 
+    public getSheetDurationInMsWithRepeats(): number {
+        // code similar to getSheetDurationInMs, but for repeats we need to use an iterator.
+        let totalDuration: number = 0;
+        const beatRealValue: number = 0.25;
+        const iterator: MusicPartManagerIterator = new MusicPartManagerIterator(this.musicPartManager.MusicSheet);
+        const maxSteps: number = 10e6; // safety maximum loop count to prevent infinite loops
+        let loopSteps: number = 0;
+        while (!iterator.EndReached) {
+            const measure: SourceMeasure = iterator.CurrentMeasure;
+            const beatLengthInMs: number = 60000.0 / measure.TempoInBPM;
+            totalDuration += measure.Duration.RealValue * beatLengthInMs / beatRealValue;
+            while (!iterator.EndReached) {
+                iterator.moveToNext();
+                if (iterator.CurrentMeasure !== measure || iterator.backJumpOccurred) {
+                    break; // hit a new measure or jump back (perhaps to same measure), add duration again
+                }
+                loopSteps++;
+                if (loopSteps >= maxSteps) {
+                    log.error("getSheetDuration: hit maximum loop limit");
+                    return totalDuration;
+                }
+            }
+        }
+        return totalDuration;
+    }
+
     /** Returns the sheet duration of the piece in ms given the tempo set via setBpm() doesn't change. */
     public getSheetDurationInMsEvenBpm(): number {
         return this.timingSource.getDurationInMs(this.musicPartManager.MusicSheet.SheetEndTimestamp);