瀏覽代碼

Merge osmd 1.3.0: fix slurs starting on tie end note not shown, add cursor.GNotesUnderCursor(), etc.

* osmd-public/develop:
chore: bump version to 1.3.0
fix beam with empty note array throwing undefined error in specific percussion samples
fix(Slurs): Fix slur starting on tie end note not shown (#1092)
feat(Cursor): Add GNotesUnderCursor() function, returning GraphicalNotes

# Conflicts:
# package.json
# src/OpenSheetMusicDisplay/Cursor.ts
# src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts
sschmid 3 年之前
父節點
當前提交
43481c6282

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "opensheetmusicdisplay-private",
-  "version": "1.2.0",
+  "version": "1.3.0",
   "description": "Private OSMD mirror/audio player.",
   "main": "build/opensheetmusicdisplay.min.js",
   "typings": "build/dist/src/",

+ 9 - 6
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -1749,12 +1749,15 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
                     }
                     // add new VexFlowSlur to List
                     if (slur.StartNote === graphicalNote.sourceNote) {
-                      if (graphicalNote.sourceNote.NoteTie) {
-                        if (graphicalNote.parentVoiceEntry.parentStaffEntry.getAbsoluteTimestamp() !==
-                          graphicalNote.sourceNote.NoteTie.StartNote.getAbsoluteTimestamp()) {
-                          break;
-                        }
-                      }
+                      // TODO the following seems to have been intended to prevent unnecessary slurs that overlap ties,
+                      //   but it simply leads to correct slurs being left out where the tie end note is the slur start note.
+                      //   visual regression tests simply show valid slurs being left out in 4 samples.
+                      // if (graphicalNote.sourceNote.NoteTie) {
+                      //   if (graphicalNote.parentVoiceEntry.parentStaffEntry.getAbsoluteTimestamp() !==
+                      //     graphicalNote.sourceNote.NoteTie.StartNote.getAbsoluteTimestamp()) {
+                      //     break;
+                      //   }
+                      // }
 
                       // Add a Graphical Slur to the staffline, if the recent note is the Startnote of a slur
                       const gSlur: GraphicalSlur = new GraphicalSlur(slur, this.rules);

+ 5 - 0
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -671,6 +671,11 @@ export class VoiceGenerator {
    */
   private handleOpenBeam(): void {
     const openBeam: Beam = this.openBeams.last();
+    if (openBeam.Notes.length === 0) {
+      // TODO why is there such a beam? sample: test_percussion_display_step_from_xml
+      this.endBeam(); // otherwise beamLastNote.ParentStaffEntry will throw an undefined error
+      return;
+    }
     if (openBeam.Notes.length === 1) {
       const beamNote: Note = openBeam.Notes[0];
       beamNote.NoteBeam = undefined;

+ 12 - 1
src/OpenSheetMusicDisplay/Cursor.ts

@@ -14,7 +14,9 @@ import { StaffLine } from "../MusicalScore/Graphical/StaffLine";
 import { GraphicalMeasure } from "../MusicalScore/Graphical/GraphicalMeasure";
 import { VexFlowMeasure } from "../MusicalScore/Graphical/VexFlow/VexFlowMeasure";
 import { CursorOptions } from "./OSMDOptions";
-import { BoundingBox, GraphicalStaffEntry } from "../MusicalScore";
+import { BoundingBox } from "../MusicalScore/Graphical/BoundingBox";
+import { GraphicalNote } from "../MusicalScore/Graphical/GraphicalNote";
+import { GraphicalStaffEntry } from "../MusicalScore/Graphical/GraphicalStaffEntry";
 import { IPlaybackListener } from "../Common/Interfaces/IPlaybackListener";
 import { CursorPosChangedData } from "../Common/DataObjects/CursorPosChangedData";
 import { PointF2D } from "../Common/DataObjects";
@@ -382,6 +384,15 @@ export class Cursor implements IPlaybackListener {
     return notes;
   }
 
+  public GNotesUnderCursor(instrument?: Instrument): GraphicalNote[] {
+    const voiceEntries: VoiceEntry[]  = this.VoicesUnderCursor(instrument);
+    const notes: GraphicalNote[] = [];
+    voiceEntries.forEach(voiceEntry => {
+      notes.push(...voiceEntry.Notes.map(note => this.rules.GNote(note)));
+    });
+    return notes;
+  }
+
   /** Check if there was a change in current page, and attach cursor element to the corresponding HTMLElement (div).
    *  This is only necessary if using PageFormat (multiple pages).
    */

+ 1 - 1
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -35,7 +35,7 @@ import { DynamicsCalculator } from "../MusicalScore/ScoreIO/MusicSymbolModules/D
  * After the constructor, use load() and render() to load and render a MusicXML file.
  */
 export class OpenSheetMusicDisplay {
-    private version: string = "1.2.1-audio-extended"; // getter: this.Version
+    private version: string = "1.3.0-audio-extended"; // getter: this.Version
     // at release, bump version and change to -release, afterwards to -dev again
 
     /**

+ 161 - 0
test/data/test_slur_starting_on_tie_end_note.musicxml

@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="3.1">
+  <work>
+    <work-title>test_slur_starting_on_tie_end_note</work-title>
+    </work>
+  <identification>
+    <encoding>
+      <software>MuseScore 3.6.2</software>
+      <encoding-date>2021-10-21</encoding-date>
+      <supports element="accidental" type="yes"/>
+      <supports element="beam" type="yes"/>
+      <supports element="print" attribute="new-page" type="yes" value="yes"/>
+      <supports element="print" attribute="new-system" type="yes" value="yes"/>
+      <supports element="stem" type="yes"/>
+      </encoding>
+    </identification>
+  <defaults>
+    <scaling>
+      <millimeters>6.99911</millimeters>
+      <tenths>40</tenths>
+      </scaling>
+    <page-layout>
+      <page-height>1696.94</page-height>
+      <page-width>1200.48</page-width>
+      <page-margins type="even">
+        <left-margin>85.7252</left-margin>
+        <right-margin>85.7252</right-margin>
+        <top-margin>85.7252</top-margin>
+        <bottom-margin>85.7252</bottom-margin>
+        </page-margins>
+      <page-margins type="odd">
+        <left-margin>85.7252</left-margin>
+        <right-margin>85.7252</right-margin>
+        <top-margin>85.7252</top-margin>
+        <bottom-margin>85.7252</bottom-margin>
+        </page-margins>
+      </page-layout>
+    <word-font font-family="Edwin" font-size="10"/>
+    <lyric-font font-family="Edwin" font-size="10"/>
+    </defaults>
+  <credit page="1">
+    <credit-type>title</credit-type>
+    <credit-words default-x="600.242" default-y="1611.21" justify="center" valign="top" font-size="22">qwqq</credit-words>
+    </credit>
+  <part-list>
+    <score-part id="P1">
+      <part-name>Piano</part-name>
+      <part-abbreviation>Pno.</part-abbreviation>
+      <score-instrument id="P1-I1">
+        <instrument-name>Piano</instrument-name>
+        </score-instrument>
+      <midi-device id="P1-I1" port="1"></midi-device>
+      <midi-instrument id="P1-I1">
+        <midi-channel>1</midi-channel>
+        <midi-program>1</midi-program>
+        <volume>78.7402</volume>
+        <pan>0</pan>
+        </midi-instrument>
+      </score-part>
+    </part-list>
+  <part id="P1">
+    <measure number="1" width="431.51">
+      <print>
+        <system-layout>
+          <system-margins>
+            <left-margin>65.90</left-margin>
+            <right-margin>531.29</right-margin>
+            </system-margins>
+          <top-system-distance>170.00</top-system-distance>
+          </system-layout>
+        <staff-layout number="2">
+          <staff-distance>65.00</staff-distance>
+          </staff-layout>
+        </print>
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+          </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+          </time>
+        <staves>2</staves>
+        <clef number="1">
+          <sign>G</sign>
+          <line>2</line>
+          </clef>
+        <clef number="2">
+          <sign>F</sign>
+          <line>4</line>
+          </clef>
+        </attributes>
+      <note>
+        <rest/>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+        </note>
+      <note default-x="167.83" default-y="-25.00">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+          </pitch>
+        <duration>1</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="start"/>
+          </notations>
+        </note>
+      <note default-x="252.18" default-y="-25.00">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+          </pitch>
+        <duration>1</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="stop"/>
+          <slur type="start" placement="above" number="1"/>
+          </notations>
+        </note>
+      <note default-x="336.52" default-y="0.00">
+        <pitch>
+          <step>F</step>
+          <octave>5</octave>
+          </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>down</stem>
+        <staff>1</staff>
+        <notations>
+          <slur type="stop" number="1"/>
+          </notations>
+        </note>
+      <backup>
+        <duration>4</duration>
+        </backup>
+      <note>
+        <rest measure="yes"/>
+        <duration>4</duration>
+        <voice>5</voice>
+        <staff>2</staff>
+        </note>
+      <barline location="right">
+        <bar-style>light-heavy</bar-style>
+        </barline>
+      </measure>
+    </part>
+  </score-partwise>