|
@@ -4,7 +4,7 @@ import {SourceMeasure} from "../../VoiceData/SourceMeasure";
|
|
import {Staff} from "../../VoiceData/Staff";
|
|
import {Staff} from "../../VoiceData/Staff";
|
|
import {StaffLine} from "../StaffLine";
|
|
import {StaffLine} from "../StaffLine";
|
|
import {SystemLinesEnum} from "../SystemLinesEnum";
|
|
import {SystemLinesEnum} from "../SystemLinesEnum";
|
|
-import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
|
|
|
|
|
|
+import {ClefInstruction, ClefEnum} from "../../VoiceData/Instructions/ClefInstruction";
|
|
import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
|
|
import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
|
|
import {RhythmInstruction} from "../../VoiceData/Instructions/RhythmInstruction";
|
|
import {RhythmInstruction} from "../../VoiceData/Instructions/RhythmInstruction";
|
|
import {VexFlowConverter} from "./VexFlowConverter";
|
|
import {VexFlowConverter} from "./VexFlowConverter";
|
|
@@ -29,14 +29,14 @@ import {Voice} from "../../VoiceData/Voice";
|
|
import {LinkedVoice} from "../../VoiceData/LinkedVoice";
|
|
import {LinkedVoice} from "../../VoiceData/LinkedVoice";
|
|
import {EngravingRules} from "../EngravingRules";
|
|
import {EngravingRules} from "../EngravingRules";
|
|
import {OrnamentContainer} from "../../VoiceData/OrnamentContainer";
|
|
import {OrnamentContainer} from "../../VoiceData/OrnamentContainer";
|
|
-import {TechnicalInstruction} from "../../VoiceData/Instructions/TechnicalInstruction";
|
|
|
|
|
|
+import {TechnicalInstruction, TechnicalInstructionType} from "../../VoiceData/Instructions/TechnicalInstruction";
|
|
import {PlacementEnum} from "../../VoiceData/Expressions/AbstractExpression";
|
|
import {PlacementEnum} from "../../VoiceData/Expressions/AbstractExpression";
|
|
import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
|
|
import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
|
|
import {AutoBeamOptions} from "../../../OpenSheetMusicDisplay/OSMDOptions";
|
|
import {AutoBeamOptions} from "../../../OpenSheetMusicDisplay/OSMDOptions";
|
|
import {NoteType, Arpeggio} from "../../VoiceData";
|
|
import {NoteType, Arpeggio} from "../../VoiceData";
|
|
|
|
|
|
export class VexFlowMeasure extends GraphicalMeasure {
|
|
export class VexFlowMeasure extends GraphicalMeasure {
|
|
- constructor(staff: Staff, staffLine: StaffLine = undefined, sourceMeasure: SourceMeasure = undefined) {
|
|
|
|
|
|
+ constructor(staff: Staff, sourceMeasure: SourceMeasure = undefined, staffLine: StaffLine = undefined) {
|
|
super(staff, sourceMeasure, staffLine);
|
|
super(staff, sourceMeasure, staffLine);
|
|
this.minimumStaffEntriesWidth = -1;
|
|
this.minimumStaffEntriesWidth = -1;
|
|
this.resetLayout();
|
|
this.resetLayout();
|
|
@@ -53,9 +53,9 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
/** The repetition instructions given as words or symbols (coda, dal segno..) */
|
|
/** The repetition instructions given as words or symbols (coda, dal segno..) */
|
|
public vfRepetitionWords: Vex.Flow.Repetition[] = [];
|
|
public vfRepetitionWords: Vex.Flow.Repetition[] = [];
|
|
/** The VexFlow Stave (= one measure in a staffline) */
|
|
/** The VexFlow Stave (= one measure in a staffline) */
|
|
- private stave: Vex.Flow.Stave;
|
|
|
|
|
|
+ protected stave: Vex.Flow.Stave;
|
|
/** VexFlow StaveConnectors (vertical lines) */
|
|
/** VexFlow StaveConnectors (vertical lines) */
|
|
- private connectors: Vex.Flow.StaveConnector[] = [];
|
|
|
|
|
|
+ protected connectors: Vex.Flow.StaveConnector[] = [];
|
|
/** Intermediate object to construct beams */
|
|
/** Intermediate object to construct beams */
|
|
private beams: { [voiceID: number]: [Beam, VexFlowVoiceEntry[]][]; } = {};
|
|
private beams: { [voiceID: number]: [Beam, VexFlowVoiceEntry[]][]; } = {};
|
|
/** Beams created by (optional) autoBeam function. */
|
|
/** Beams created by (optional) autoBeam function. */
|
|
@@ -65,9 +65,9 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
/** VexFlow Beams */
|
|
/** VexFlow Beams */
|
|
private vfbeams: { [voiceID: number]: Vex.Flow.Beam[]; };
|
|
private vfbeams: { [voiceID: number]: Vex.Flow.Beam[]; };
|
|
/** Intermediate object to construct tuplets */
|
|
/** Intermediate object to construct tuplets */
|
|
- private tuplets: { [voiceID: number]: [Tuplet, VexFlowVoiceEntry[]][]; } = {};
|
|
|
|
|
|
+ protected tuplets: { [voiceID: number]: [Tuplet, VexFlowVoiceEntry[]][]; } = {};
|
|
/** VexFlow Tuplets */
|
|
/** VexFlow Tuplets */
|
|
- private vftuplets: { [voiceID: number]: Vex.Flow.Tuplet[]; } = {};
|
|
|
|
|
|
+ protected vftuplets: { [voiceID: number]: Vex.Flow.Tuplet[]; } = {};
|
|
|
|
|
|
// Sets the absolute coordinates of the VFStave on the canvas
|
|
// Sets the absolute coordinates of the VFStave on the canvas
|
|
public setAbsoluteCoordinates(x: number, y: number): void {
|
|
public setAbsoluteCoordinates(x: number, y: number): void {
|
|
@@ -144,8 +144,12 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
*/
|
|
*/
|
|
public addClefAtBegin(clef: ClefInstruction): void {
|
|
public addClefAtBegin(clef: ClefInstruction): void {
|
|
this.octaveOffset = clef.OctaveOffset;
|
|
this.octaveOffset = clef.OctaveOffset;
|
|
|
|
+ if (clef.ClefType === ClefEnum.TAB) {
|
|
|
|
+ this.stave.addClef("tab", undefined, undefined, undefined);
|
|
|
|
+ } else {
|
|
const vfclef: { type: string, size: string, annotation: string } = VexFlowConverter.Clef(clef, "default");
|
|
const vfclef: { type: string, size: string, annotation: string } = VexFlowConverter.Clef(clef, "default");
|
|
this.stave.addClef(vfclef.type, vfclef.size, vfclef.annotation, Vex.Flow.StaveModifier.Position.BEGIN);
|
|
this.stave.addClef(vfclef.type, vfclef.size, vfclef.annotation, Vex.Flow.StaveModifier.Position.BEGIN);
|
|
|
|
+ }
|
|
this.updateInstructionWidth();
|
|
this.updateInstructionWidth();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -451,7 +455,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
* And the graphical notes have to be analysed directly (and not the voiceEntries, as it actually should be -> needs refactoring)
|
|
* And the graphical notes have to be analysed directly (and not the voiceEntries, as it actually should be -> needs refactoring)
|
|
* @param voice the voice for which the ghost notes shall be searched.
|
|
* @param voice the voice for which the ghost notes shall be searched.
|
|
*/
|
|
*/
|
|
- private getRestFilledVexFlowStaveNotesPerVoice(voice: Voice): GraphicalVoiceEntry[] {
|
|
|
|
|
|
+ protected getRestFilledVexFlowStaveNotesPerVoice(voice: Voice): GraphicalVoiceEntry[] {
|
|
let latestVoiceTimestamp: Fraction = undefined;
|
|
let latestVoiceTimestamp: Fraction = undefined;
|
|
const gvEntries: GraphicalVoiceEntry[] = this.getGraphicalVoiceEntriesPerVoice(voice);
|
|
const gvEntries: GraphicalVoiceEntry[] = this.getGraphicalVoiceEntriesPerVoice(voice);
|
|
for (let idx: number = 0, len: number = gvEntries.length; idx < len; ++idx) {
|
|
for (let idx: number = 0, len: number = gvEntries.length; idx < len; ++idx) {
|
|
@@ -999,7 +1003,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
/**
|
|
/**
|
|
* Create the articulations for all notes of the current staff entry
|
|
* Create the articulations for all notes of the current staff entry
|
|
*/
|
|
*/
|
|
- private createArticulations(): void {
|
|
|
|
|
|
+ protected createArticulations(): void {
|
|
for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
|
|
for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
|
|
const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
|
|
const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
|
|
|
|
|
|
@@ -1015,7 +1019,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
/**
|
|
/**
|
|
* Create the ornaments for all notes of the current staff entry
|
|
* Create the ornaments for all notes of the current staff entry
|
|
*/
|
|
*/
|
|
- private createOrnaments(): void {
|
|
|
|
|
|
+ protected createOrnaments(): void {
|
|
for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
|
|
for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
|
|
const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
|
|
const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
|
|
const gvoices: { [voiceID: number]: GraphicalVoiceEntry; } = graphicalStaffEntry.graphicalVoiceEntries;
|
|
const gvoices: { [voiceID: number]: GraphicalVoiceEntry; } = graphicalStaffEntry.graphicalVoiceEntries;
|
|
@@ -1032,15 +1036,24 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private createFingerings(voiceEntry: GraphicalVoiceEntry): void {
|
|
|
|
|
|
+ protected createFingerings(voiceEntry: GraphicalVoiceEntry): void {
|
|
const vexFlowVoiceEntry: VexFlowVoiceEntry = voiceEntry as VexFlowVoiceEntry;
|
|
const vexFlowVoiceEntry: VexFlowVoiceEntry = voiceEntry as VexFlowVoiceEntry;
|
|
const technicalInstructions: TechnicalInstruction[] = voiceEntry.parentVoiceEntry.TechnicalInstructions;
|
|
const technicalInstructions: TechnicalInstruction[] = voiceEntry.parentVoiceEntry.TechnicalInstructions;
|
|
- const fingeringsCount: number = technicalInstructions.length;
|
|
|
|
- for (let i: number = 0; i < technicalInstructions.length; i++) {
|
|
|
|
- const technicalInstruction: TechnicalInstruction = technicalInstructions[i];
|
|
|
|
|
|
+ let fingeringsCount: number = 0;
|
|
|
|
+ for (const instruction of technicalInstructions) {
|
|
|
|
+ if (instruction.type === TechnicalInstructionType.Fingering) {
|
|
|
|
+ fingeringsCount++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ let fingeringIndex: number = -1;
|
|
|
|
+ for (const fingeringInstruction of technicalInstructions) {
|
|
|
|
+ if (fingeringInstruction.type !== TechnicalInstructionType.Fingering) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ fingeringIndex++; // 0 for first fingering
|
|
let fingeringPosition: PlacementEnum = EngravingRules.Rules.FingeringPosition;
|
|
let fingeringPosition: PlacementEnum = EngravingRules.Rules.FingeringPosition;
|
|
- if (technicalInstruction.placement !== PlacementEnum.NotYetDefined) {
|
|
|
|
- fingeringPosition = technicalInstruction.placement;
|
|
|
|
|
|
+ if (fingeringInstruction.placement !== PlacementEnum.NotYetDefined) {
|
|
|
|
+ fingeringPosition = fingeringInstruction.placement;
|
|
}
|
|
}
|
|
let modifierPosition: any; // Vex.Flow.Stavemodifier.Position
|
|
let modifierPosition: any; // Vex.Flow.Stavemodifier.Position
|
|
switch (fingeringPosition) {
|
|
switch (fingeringPosition) {
|
|
@@ -1070,12 +1083,12 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- const fretFinger: Vex.Flow.FretHandFinger = new Vex.Flow.FretHandFinger(technicalInstruction.value);
|
|
|
|
|
|
+ const fretFinger: Vex.Flow.FretHandFinger = new Vex.Flow.FretHandFinger(fingeringInstruction.value);
|
|
fretFinger.setPosition(modifierPosition);
|
|
fretFinger.setPosition(modifierPosition);
|
|
if (fingeringPosition === PlacementEnum.Above || fingeringPosition === PlacementEnum.Below) {
|
|
if (fingeringPosition === PlacementEnum.Above || fingeringPosition === PlacementEnum.Below) {
|
|
const offsetYSign: number = fingeringPosition === PlacementEnum.Above ? -1 : 1; // minus y is up
|
|
const offsetYSign: number = fingeringPosition === PlacementEnum.Above ? -1 : 1; // minus y is up
|
|
- const ordering: number = fingeringPosition === PlacementEnum.Above ? i :
|
|
|
|
- technicalInstructions.length - 1 - i; // reverse order for fingerings below staff
|
|
|
|
|
|
+ const ordering: number = fingeringPosition === PlacementEnum.Above ? fingeringIndex :
|
|
|
|
+ fingeringsCount - 1 - fingeringIndex; // reverse order for fingerings below staff
|
|
if (EngravingRules.Rules.FingeringInsideStafflines && fingeringsCount > 1) { // y-shift for single fingering is ok
|
|
if (EngravingRules.Rules.FingeringInsideStafflines && fingeringsCount > 1) { // y-shift for single fingering is ok
|
|
// experimental, bounding boxes wrong for fretFinger above/below, better would be creating Labels
|
|
// experimental, bounding boxes wrong for fretFinger above/below, better would be creating Labels
|
|
// set y-shift. vexflow fretfinger simply places directly above/below note
|
|
// set y-shift. vexflow fretfinger simply places directly above/below note
|
|
@@ -1083,17 +1096,22 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
const shiftCount: number = fingeringsCount * 2.5;
|
|
const shiftCount: number = fingeringsCount * 2.5;
|
|
(<any>fretFinger).setOffsetY(offsetYSign * (ordering + shiftCount) * perFingeringShift);
|
|
(<any>fretFinger).setOffsetY(offsetYSign * (ordering + shiftCount) * perFingeringShift);
|
|
} else if (!EngravingRules.Rules.FingeringInsideStafflines) { // use StringNumber for placement above/below stafflines
|
|
} else if (!EngravingRules.Rules.FingeringInsideStafflines) { // use StringNumber for placement above/below stafflines
|
|
- const stringNumber: Vex.Flow.StringNumber = new Vex.Flow.StringNumber(technicalInstruction.value);
|
|
|
|
|
|
+ const stringNumber: Vex.Flow.StringNumber = new Vex.Flow.StringNumber(fingeringInstruction.value);
|
|
(<any>stringNumber).radius = 0; // hack to remove the circle around the number
|
|
(<any>stringNumber).radius = 0; // hack to remove the circle around the number
|
|
stringNumber.setPosition(modifierPosition);
|
|
stringNumber.setPosition(modifierPosition);
|
|
stringNumber.setOffsetY(offsetYSign * ordering * stringNumber.getWidth() * 2 / 3);
|
|
stringNumber.setOffsetY(offsetYSign * ordering * stringNumber.getWidth() * 2 / 3);
|
|
// Vexflow made a mess with the addModifier signature that changes through each class so we just cast to any :(
|
|
// Vexflow made a mess with the addModifier signature that changes through each class so we just cast to any :(
|
|
- vexFlowVoiceEntry.vfStaveNote.addModifier((i as any), (stringNumber as any));
|
|
|
|
|
|
+ vexFlowVoiceEntry.vfStaveNote.addModifier((fingeringIndex as any), (stringNumber as any));
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- // Vexflow made a mess with the addModifier signature that changes through each class so we just cast to any :(
|
|
|
|
- vexFlowVoiceEntry.vfStaveNote.addModifier((i as any), (fretFinger as any));
|
|
|
|
|
|
+ if (vexFlowVoiceEntry.vfStaveNote.getCategory() === "tabnotes") {
|
|
|
|
+ // TODO this doesn't work yet. don't add fingering for tabs for now.
|
|
|
|
+ // vexFlowVoiceEntry.vfStaveNote.addModifier(fretFinger, fingeringIndex);
|
|
|
|
+ } else {
|
|
|
|
+ // Vexflow made a mess with the addModifier signature that changes through each class so we just cast to any :(
|
|
|
|
+ vexFlowVoiceEntry.vfStaveNote.addModifier((fingeringIndex as any), (fretFinger as any));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1120,7 +1138,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
|
|
* After re-running the formatting on the VexFlow Stave, update the
|
|
* After re-running the formatting on the VexFlow Stave, update the
|
|
* space needed by Instructions (in VexFlow: StaveModifiers)
|
|
* space needed by Instructions (in VexFlow: StaveModifiers)
|
|
*/
|
|
*/
|
|
- private updateInstructionWidth(): void {
|
|
|
|
|
|
+ protected updateInstructionWidth(): void {
|
|
let vfBeginInstructionsWidth: number = 0;
|
|
let vfBeginInstructionsWidth: number = 0;
|
|
let vfEndInstructionsWidth: number = 0;
|
|
let vfEndInstructionsWidth: number = 0;
|
|
const modifiers: Vex.Flow.StaveModifier[] = this.stave.getModifiers();
|
|
const modifiers: Vex.Flow.StaveModifier[] = this.stave.getModifiers();
|