Browse Source

feat(Playback): Able to play without rendering

Additionally, you can set PlaybackManager.StopAtUnrenderedMeasures = false,
so that playback also happens when you're outside of rendering range
(e.g. when you've set osmd.EngravingRules.MinMeasureToDrawIndex and
osmd.EngravingRules.MaxMeasureToDrawIndex,
or similar via options drawFromMeasureNumber etc)
sschmidTU 1 year ago
parent
commit
6073105395
2 changed files with 13 additions and 6 deletions
  1. 1 1
      demo/index.js
  2. 12 5
      src/Playback/PlaybackManager.ts

+ 1 - 1
demo/index.js

@@ -700,7 +700,7 @@ import { TransposeCalculator } from '../src/Plugins/Transpose/TransposeCalculato
                 window.osmd = openSheetMusicDisplay;
                 openSheetMusicDisplay.zoom = zoom;
                 //openSheetMusicDisplay.Sheet.Transpose = 3; // try transposing between load and first render if you have transpose issues with F# etc
-                return openSheetMusicDisplay.render();
+                return openSheetMusicDisplay.render(); // comment out this line to test playback without rendering
             },
             function (e) {
                 errorLoadingOrRenderingSheet(e, "rendering");

+ 12 - 5
src/Playback/PlaybackManager.ts

@@ -104,6 +104,7 @@ export class PlaybackManager implements IPlaybackParametersListener {
     private metronomeSoundPlayed: boolean = false;
     /** Whether a dummy sound was played to initialize the audio context / enable sound (on iOS). */
     public DummySoundPlayed: boolean = false;
+    public StopAtUnrenderedMeasures: boolean = true; // stop when not in rendering range. automatically set to false if playing without rendering
 
     private tempoImpactFactor: number = 1.0;
     private sheetStartBPM: number;
@@ -377,6 +378,9 @@ export class PlaybackManager implements IPlaybackParametersListener {
 
         this.isPlaying = true;
         this.RunningState = PlaybackState.Running;
+        if (this.musicPartManager.MusicSheet.Rules.RenderCount === 0) { // playback without rendering
+            this.StopAtUnrenderedMeasures = false;
+        }
         await this.timingSource.start();
         this.loop();
     }
@@ -613,7 +617,8 @@ export class PlaybackManager implements IPlaybackParametersListener {
             endHasBeenReached = this.cursorIterator.EndReached;
             // TODO cursorIterator.CurrentMeasure can be undefined (at the end of the piece?)
             const currentMeasure: SourceMeasure = this.cursorIterator.CurrentMeasure;
-            if (currentMeasure && !currentMeasure.WasRendered && !currentMeasure.isReducedToMultiRest) {
+            if (this.StopAtUnrenderedMeasures && currentMeasure &&
+                !currentMeasure.WasRendered && !currentMeasure.isReducedToMultiRest) {
                 // stop if current measure is not rendered, but not if it's part of a multi-measure rest
                 endHasBeenReached = true;
             }
@@ -708,8 +713,9 @@ export class PlaybackManager implements IPlaybackParametersListener {
                         const playbackedNotes: PlaybackNote[] = [];
 
                         for (const entry of dueEntries) {
-                            if (!entry.playbackEntry.ParentVoiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.WasRendered) {
-                                continue; // don't play back entry that isn't visible. (e.g. first note in measure after maxMeasureToDraw)
+                            if (this.StopAtUnrenderedMeasures &&
+                                !entry.playbackEntry.ParentVoiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.WasRendered) {
+                                    continue; // don't play back entry that isn't visible. (e.g. first note in measure after maxMeasureToDraw)
                             }
                             const playbackEntry: PlaybackEntry = entry.playbackEntry;
                             const voiceEntry: VoiceEntry = playbackEntry.ParentVoiceEntry;
@@ -904,8 +910,9 @@ export class PlaybackManager implements IPlaybackParametersListener {
             }
 
             // Check for "updating the display"
-            if (updateCursorPosition ||
-                endHasBeenReached && !this.loopTriggeredReset) {
+            if (currentMeasure.Rules.RenderCount > 0 && ( // only update cursor if we've rendered (can play without rendering)
+                updateCursorPosition ||
+                endHasBeenReached && !this.loopTriggeredReset)) {
                 // set the play cursor in the display
                 this.updateScoreCursorPosition(resetOccurred);
             }