ソースを参照

feat(percussion_stafflines) Potential fix for drumlines render issues

Justin Litten 5 年 前
コミット
9464da94ce

+ 8 - 0
src/MusicalScore/Graphical/EngravingRules.ts

@@ -54,6 +54,7 @@ export class EngravingRules {
     private clefRightMargin: number;
     /** Whether to automatically convert any lines with a percussion clef to a single staff line. */
     private renderPercussionOneLine: boolean;
+    private forcePercussionVoicesOneLine: boolean;
     private betweenKeySymbolsDistance: number;
     private keyRightMargin: number;
     private rhythmRightMargin: number;
@@ -284,6 +285,7 @@ export class EngravingRules {
         this.clefLeftMargin = 0.5;
         this.clefRightMargin = 0.75;
         this.renderPercussionOneLine = false;
+        this.forcePercussionVoicesOneLine = false;
         this.betweenKeySymbolsDistance = 0.2;
         this.keyRightMargin = 0.75;
         this.rhythmRightMargin = 1.25;
@@ -711,6 +713,12 @@ export class EngravingRules {
     public set RenderPercussionOneLine(value: boolean) {
         this.renderPercussionOneLine = value;
     }
+    public get ForcePercussionVoicesOneLine(): boolean {
+        return this.forcePercussionVoicesOneLine;
+    }
+    public set ForcePercussionVoicesOneLine(value: boolean) {
+        this.forcePercussionVoicesOneLine = value;
+    }
     public get KeyRightMargin(): number {
         return this.keyRightMargin;
     }

+ 2 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -60,11 +60,12 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     this.rules = rules;
     MusicSheetCalculator.symbolFactory = new VexFlowGraphicalSymbolFactory();
     MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer(this.rules);
-    MusicSheetCalculator.stafflineNoteCalculator = new VexflowStafflineNoteCalculator();
+    MusicSheetCalculator.stafflineNoteCalculator = new VexflowStafflineNoteCalculator(this.rules);
   }
 
   protected clearRecreatedObjects(): void {
     super.clearRecreatedObjects();
+    MusicSheetCalculator.stafflineNoteCalculator = new VexflowStafflineNoteCalculator(this.rules);
     for (const graphicalMeasures of this.graphicalMusicSheet.MeasureList) {
       for (const graphicalMeasure of graphicalMeasures) {
         (<VexFlowMeasure>graphicalMeasure).clean();

+ 51 - 23
src/MusicalScore/Graphical/VexFlow/VexflowStafflineNoteCalculator.ts

@@ -3,9 +3,17 @@ import { GraphicalNote } from "../GraphicalNote";
 import { ClefInstruction, ClefEnum } from "../../VoiceData";
 import { Pitch, NoteEnum, AccidentalEnum } from "../../../Common";
 import { VexFlowGraphicalNote } from "./VexFlowGraphicalNote";
+import { Dictionary } from "typescript-collections";
+import { EngravingRules } from "../EngravingRules";
 
 export class VexflowStafflineNoteCalculator implements IStafflineNoteCalculator {
+    private instrumentVoiceMapping: Dictionary<string, Dictionary<number, {note: NoteEnum, octave: number}>> =
+                                                new Dictionary<string, Dictionary<number, {note: NoteEnum, octave: number}>>();
+    private rules: EngravingRules;
 
+    constructor(rules: EngravingRules) {
+        this.rules = rules;
+    }
   /**
    * This method is called for each note, and should make any necessary position changes based on the number of stafflines, clef, etc.
    * Right now this just directly maps a voice number to a position above or below a staffline
@@ -16,38 +24,58 @@ export class VexflowStafflineNoteCalculator implements IStafflineNoteCalculator
    */
     public positionNote(graphicalNote: GraphicalNote, currentClef: ClefInstruction, stafflineCount: number): GraphicalNote {
         if (!(graphicalNote instanceof VexFlowGraphicalNote) || currentClef.ClefType !== ClefEnum.percussion ||
-        graphicalNote.sourceNote.isRest()) {
+        graphicalNote.sourceNote.isRest() || stafflineCount > 1) {
             return graphicalNote;
         }
 
-        const vfGraphicalNote: VexFlowGraphicalNote = graphicalNote as VexFlowGraphicalNote;
-        const voiceCount: number = graphicalNote.parentVoiceEntry.parentStaffEntry.sourceStaffEntry.ParentStaff.Voices.length;
+        const instrumentId: string = graphicalNote.sourceNote.PlaybackInstrumentId;
+        //const instrumentId: number = graphicalNote.parentVoiceEntry.parentVoiceEntry.ParentVoice.Parent.Id;
         const voiceNumber: number = graphicalNote.parentVoiceEntry.parentVoiceEntry.ParentVoice.VoiceId;
+        //const mappingId: number = instrumentId * 10 + voiceNumber;
+        let currentInstrumentMapping: Dictionary<number, {note: NoteEnum, octave: number}> = undefined;
+
+        if (!this.instrumentVoiceMapping.containsKey(instrumentId)) {
+            currentInstrumentMapping = new Dictionary<number, {note: NoteEnum, octave: number}>();
+            this.instrumentVoiceMapping.setValue(instrumentId, currentInstrumentMapping);
+        } else {
+            currentInstrumentMapping = this.instrumentVoiceMapping.getValue(instrumentId);
+        }
+
         let fundamental: NoteEnum = NoteEnum.B;
         let octave: number = 1;
+        const vfGraphicalNote: VexFlowGraphicalNote = graphicalNote as VexFlowGraphicalNote;
 
-        //Direct mapping for more than one voice, position voices
-        if (voiceCount > 1) {
-            switch (voiceNumber) {
-                case 2:
-                    fundamental = NoteEnum.A;
-                    break;
-                case 3:
-                    fundamental = NoteEnum.F;
-                    break;
-                case 4:
-                    fundamental = NoteEnum.D;
-                    break;
-                case 5:
-                    fundamental = NoteEnum.B;
-                    octave = 0;
-                    break;
-                default:
-                    fundamental = NoteEnum.C;
-                    octave = 2;
-                    break;
+        //if we are forcing to one line, just set to B
+        if (!this.rules.ForcePercussionVoicesOneLine) {
+            if (!currentInstrumentMapping.containsKey(voiceNumber)) {
+                //Direct mapping for more than one voice, position voices
+                switch (voiceNumber) {
+                    case 2:
+                        fundamental = NoteEnum.A;
+                        break;
+                    case 3:
+                        fundamental = NoteEnum.F;
+                        break;
+                    case 4:
+                        fundamental = NoteEnum.D;
+                        break;
+                    case 5:
+                        fundamental = NoteEnum.B;
+                        octave = 0;
+                        break;
+                    default:
+                        fundamental = NoteEnum.C;
+                        octave = 2;
+                        break;
+                }
+                currentInstrumentMapping.setValue(voiceNumber, {note: fundamental, octave: octave});
+            } else {
+                const storageObj: {note: NoteEnum, octave: number} = currentInstrumentMapping.getValue(voiceNumber);
+                fundamental = storageObj.note;
+                octave = storageObj.octave;
             }
         }
+
         //TODO: Check for playback side effects
         vfGraphicalNote.setAccidental(new Pitch(fundamental, octave, AccidentalEnum.NONE));
         return graphicalNote;

+ 5 - 0
src/OpenSheetMusicDisplay/OSMDOptions.ts

@@ -147,6 +147,11 @@ export interface IOSMDOptions {
      * Default false, use staff-lines element or if not present default to 5 lines
      */
     renderPercussionOneLine?: boolean;
+    /** Dependent on renderPercussionOneLine set to true. If this is true, it forces
+     *  all percussion voices to render on the single line, instead of positioning them.
+     *  (In the case of different snare voices, side stick, etc.)
+     */
+    forcePercussionVoicesOneLine?: boolean;
 }
 
 export enum AlignRestOption {

+ 3 - 0
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -368,6 +368,9 @@ export class OpenSheetMusicDisplay {
         }
         if (options.renderPercussionOneLine !== undefined) {
             this.rules.RenderPercussionOneLine = options.renderPercussionOneLine;
+            if (options.forcePercussionVoicesOneLine !== undefined) {
+                this.rules.ForcePercussionVoicesOneLine = options.forcePercussionVoicesOneLine;
+            }
         }
         if (options.alignRests !== undefined) {
             this.rules.AlignRests = options.alignRests;