Procházet zdrojové kódy

fix(accidentalOctaveShift): place notes with octave brackets correctly (#424)

use drawPitch in VexFlowGraphicalNote.setPitch ignoring octaves for accidentals
add sort function to GraphicalVoiceEntry (unnecessary for now)
Simon před 6 roky
rodič
revize
43f13d5d40

+ 13 - 0
src/MusicalScore/Graphical/GraphicalVoiceEntry.ts

@@ -3,6 +3,7 @@ import { VoiceEntry } from "../VoiceData/VoiceEntry";
 import { BoundingBox } from "./BoundingBox";
 import { GraphicalNote } from "./GraphicalNote";
 import { GraphicalStaffEntry } from "./GraphicalStaffEntry";
+import { OctaveEnum } from "../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
 
 /**
  * The graphical counterpart of a [[VoiceEntry]].
@@ -19,4 +20,16 @@ export class GraphicalVoiceEntry extends GraphicalObject {
     public parentVoiceEntry: VoiceEntry;
     public parentStaffEntry: GraphicalStaffEntry;
     public notes: GraphicalNote[];
+    /** Contains octave shifts affecting this voice entry, caused by octave brackets. */
+    public octaveShiftValue: OctaveEnum;
+
+    /** Sort this entry's notes by pitch.
+     * Notes need to be sorted for Vexflow StaveNote creation.
+     * Note that Vexflow needs the reverse order, see VexFlowConverter.StaveNote().
+     */
+    public sort(): void {
+        this.notes.sort((a, b) => {
+            return b.sourceNote.Pitch.getHalfTone() - a.sourceNote.Pitch.getHalfTone();
+        });
+    }
 }

+ 3 - 2
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -1205,7 +1205,7 @@ export abstract class MusicSheetCalculator {
         if (graphicalInstantaneousDynamic.Placement === PlacementEnum.Above) {
             const skyLineValue: number = skyBottomLineCalculator.getSkyLineMinInRange(left, right);
 
-            // if StaffLine part of multiStafff Instrument and not the first one, ideal yPosition middle of distance between Staves
+            // if StaffLine part of multiStaff Instrument and not the first one, ideal yPosition middle of distance between Staves
             if (staffLine.isPartOfMultiStaffInstrument() && staffLine.ParentStaff !== staffLine.ParentStaff.ParentInstrument.Staves[0]) {
                 const formerStaffLine: StaffLine = staffLine.ParentMusicSystem.StaffLines[staffLine.ParentMusicSystem.StaffLines.indexOf(staffLine) - 1];
                 const difference: number = staffLine.PositionAndShape.RelativePosition.y -
@@ -1224,7 +1224,7 @@ export abstract class MusicSheetCalculator {
             graphicalInstantaneousDynamic.PositionAndShape.RelativePosition = new PointF2D(startPosInStaffline.x, yPosition);
         } else if (graphicalInstantaneousDynamic.Placement === PlacementEnum.Below) {
             const bottomLineValue: number = skyBottomLineCalculator.getBottomLineMaxInRange(left, right);
-            // if StaffLine part of multiStafff Instrument and not the last one, ideal yPosition middle of distance between Staves
+            // if StaffLine part of multiStaff Instrument and not the last one, ideal yPosition middle of distance between Staves
             const lastStaff: Staff = staffLine.ParentStaff.ParentInstrument.Staves[staffLine.ParentStaff.ParentInstrument.Staves.length - 1];
             if (staffLine.isPartOfMultiStaffInstrument() && staffLine.ParentStaff !== lastStaff) {
                 const nextStaffLine: StaffLine = staffLine.ParentMusicSystem.StaffLines[staffLine.ParentMusicSystem.StaffLines.indexOf(staffLine) + 1];
@@ -1488,6 +1488,7 @@ export abstract class MusicSheetCalculator {
                                sourceStaffEntry: SourceStaffEntry = undefined): OctaveEnum {
         this.calculateStemDirectionFromVoices(voiceEntry);
         const gve: GraphicalVoiceEntry = graphicalStaffEntry.findOrCreateGraphicalVoiceEntry(voiceEntry);
+        gve.octaveShiftValue = octaveShiftValue;
         for (let idx: number = 0, len: number = voiceEntry.Notes.length; idx < len; ++idx) {
             const note: Note = voiceEntry.Notes[idx];
             if (note === undefined) {

+ 7 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowConverter.ts

@@ -108,9 +108,9 @@ export class VexFlowConverter {
      */
     public static pitch(note: VexFlowGraphicalNote, pitch: Pitch): [string, string, ClefInstruction] {
         const fund: string = NoteEnum[pitch.FundamentalNote].toLowerCase();
+        const acc: string = VexFlowConverter.accidental(pitch.Accidental);
         // The octave seems to need a shift of three FIXME?
         const octave: number = pitch.Octave - note.Clef().OctaveOffset + 3;
-        const acc: string = VexFlowConverter.accidental(pitch.Accidental);
         const noteHead: NoteHead = note.sourceNote.NoteHead;
         let noteHeadCode: string = "";
         if (noteHead !== undefined) {
@@ -197,8 +197,14 @@ export class VexFlowConverter {
      * @returns {Vex.Flow.StaveNote}
      */
     public static StaveNote(gve: GraphicalVoiceEntry): Vex.Flow.StaveNote {
+        // sort notes
+        /* seems unnecessary for now
+        if (gve.octaveShiftValue !== undefined && gve.octaveShiftValue !== OctaveEnum.NONE) {
+            gve.sort(); // gves with accidentals in octave shift brackets can be unsorted
+        } */
         // VexFlow needs the notes ordered vertically in the other direction:
         const notes: GraphicalNote[] = gve.notes.reverse();
+
         const baseNote: GraphicalNote = notes[0];
         let keys: string[] = [];
         const accidentals: string[] = [];

+ 5 - 3
src/MusicalScore/Graphical/VexFlow/VexFlowGraphicalNote.ts

@@ -34,8 +34,8 @@ export class VexFlowGraphicalNote extends GraphicalNote {
     private clef: ClefInstruction;
 
     /**
-     * Update the pitch of this note. Necessary in order to display correctly
-     * accidentals, this is called by VexFlowGraphicalSymbolFactory.addGraphicalAccidental.
+     * Update the pitch of this note. Necessary in order to display accidentals correctly.
+     * This is called by VexFlowGraphicalSymbolFactory.addGraphicalAccidental.
      * @param pitch
      */
     public setPitch(pitch: Pitch): void {
@@ -46,7 +46,9 @@ export class VexFlowGraphicalNote extends GraphicalNote {
                 this.vfnote[0].addAccidental(this.vfnote[1], new Vex.Flow.Accidental(acc));
             }
         } else {
-            this.vfpitch = VexFlowConverter.pitch(this, pitch);
+            // revert octave shift, as the placement of the note is independent of octave brackets
+            const drawPitch: Pitch = OctaveShift.getPitchFromOctaveShift(pitch, this.octaveShift);
+            this.vfpitch = VexFlowConverter.pitch(this, drawPitch);
         }
     }